15

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 list to facilitate the player being moved from one level to another)

Alright, so to the question. If I can do the equivalent of this in Python(code curtesy of Java):

Object object = new Object (){
    public void overriddenFunction(){
        //new functionality
        };
    };

Than when I build the levels in the game I would simply have to override the constructor (or a class/instance method that is responsible for building the level) with the information on where the sprites go, because making a new class for every level in the game isn't that elegant of an answer. Alternatively I would have to make methods within the level class that would then build the level once a level object is instantiated, placing the sprites as needed.

So, before one of the more stanch developers goes on about how anti-python this might be (I've read enough of this site to get that vibe from Python experts) just tell me if its doable.

2
  • when you say "'abstract' class" do you mean you actually used abc.ABCMeta and abc.abstractmethod or you did something all your own here Commented Jul 20, 2013 at 0:09
  • Somebody correct me if I'm wrong. But yeah that actually creates a class an anonymous class. Commented Jul 20, 2013 at 0:17

3 Answers 3

15

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.
Sign up to request clarification or add additional context in comments.

3 Comments

You've overridden the class method (Foo.do_foo), so if I do g = Foo() and invoke g.do_foo() that will also print bar. Might be what the OP wants, not really sure whether he wants overrides per instance or per class...
Indeed, that's the intent of my example. Title says 'class function' so that's what I went with.
It might not be pythonic (I'm mainly a Java dev) but it's really useful for creating a tree structure with an isChildGivenCriteria(criteria) function and for the root node, overriding it with an "everything is my child" return True function
11

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.

Comments

1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.