Can I override a class function without creating a new class in Python?

前端 未结 3 1427
我寻月下人不归
我寻月下人不归 2021-02-08 13:10

I\'m making a game in pygame and I have made an \'abstract\' class that\'s sole job is to store the sprites for a given level (with the intent of having these level objects in a

相关标签:
3条回答
  • 2021-02-08 13:29

    I'd suggest using a different class, via inheritance, for each level.

    But you might get some mileage out of copy.deepcopy() and monkey patching, if you're really married to treating Python like Java.

    0 讨论(0)
  • 2021-02-08 13:41

    Yes, it's doable. Here, I use functools.partial to get the implied self argument into a regular (non-class-method) function:

    import functools
    
    class WackyCount(object):
        "it's a counter, but it has one wacky method"
        def __init__(self, name, value):
            self.name = name
            self.value = value
        def __str__(self):
            return '%s = %d' % (self.name, self.value)
        def incr(self):
            self.value += 1
        def decr(self):
            self.value -= 1
        def wacky_incr(self):
            self.value += random.randint(5, 9)
    
    # although x is a regular wacky counter...
    x = WackyCount('spam', 1)
    # it increments like crazy:
    def spam_incr(self):
        self.value *= 2
    x.incr = functools.partial(spam_incr, x)
    
    print (x)
    x.incr()
    print (x)
    x.incr()
    print (x)
    x.incr()
    print (x)
    

    and:

    $ python2.7 wacky.py
    spam = 1
    spam = 2
    spam = 4
    spam = 8
    $ python3.2 wacky.py    
    spam = 1
    spam = 2
    spam = 4
    spam = 8
    

    Edit to add note: this is a per-instance override. It takes advantage of Python's attribute look-up sequence: if x is an instance of class K, then x.attrname starts by looking at x's dictionary to find the attribute. If not found, the next lookup is in K. All the normal class functions are actually K.func. So if you want to replace the class function dynamically, use @Brian Cane's answer instead.

    0 讨论(0)
  • 2021-02-08 13:47

    Yes, you can!

    class Foo:
        def do_other(self):
            print('other!')
        def do_foo(self):
            print('foo!')
    
    
    def do_baz():
        print('baz!')
    
    def do_bar(self):
        print('bar!')
    
    # Class-wide impact
    Foo.do_foo = do_bar
    f = Foo()
    g = Foo()
    # Instance-wide impact
    g.do_other = do_baz
    
    f.do_foo()  # prints "bar!"
    f.do_other()  # prints "other!"
    
    g.do_foo()  # prints "bar!"
    g.do_other()  # prints "baz!"
    

    So, before one of the more stanch developers goes on about how anti-python this might be

    Overwriting functions in this fashion (if you have a good reason to do so) seems reasonably pythonic to me. An example of one reason/way for which you might have to do this would be if you had a dynamic feature for which static inheritance didn't or couldn't apply.

    The case against might be found in the Zen of Python:

    • Beautiful is better than ugly.
    • Readability counts.
    • If the implementation is hard to explain, it's a bad idea.
    0 讨论(0)
提交回复
热议问题