api/class question

I recently learned how to work with classes. I then realized that much of what I was doing in my games python scripts was using built in classes. one thing I don’t fully understand is when, I use something like print(dir(own)), there are things that have two underscore’s in front and behind, e.g., add, contains_, delattr. I know what “init” does, but everything else, I have no idea. are these all methods? how do I make use of them?

A good thread on stackoverflow on the subject.

This snippet here is where it clicked and makes sense to me:

“The other respondents are correct in describing the double leading and trailing underscores as a naming convention for “special” or “magic” methods.

While you can call these methods directly ([10, 20].len() for example), the presence of the underscores is a hint that these methods are intended to be invoked indirectly (len([10, 20]) for example). Most python operators have an associated “magic” method (for example, a[x] is the usual way of invoking a.getitem(x)).”

Also some good knowledge regarding other underscore-related naming. I always figured those other ones like this or this or this were merely for purposes of naming convention. Turns out they have actual function. Cool!

Thanks, that’s a big help. you are always so helpful Nines!

Building on Nines reply,

Any attribute (name of a variable belonging to an object) which starts with an underscore is a “private” member, meaning it’s not supposed to be accessed “outside of that class”. In other words, the only time you should access that member, is when it’s following “self”. It’s just a convention, because Python allows you to introspect objects without privacy enforcement, but it should be observed wherever possible.

Any attribute named with a leading double underscore will be renamed by Python to _X__y, where X is the class name and __y is the variable name that you wrote in the class definition.


class Foo:
    __bar = 1

    def print_bar(self):
        print(self.__bar)

foo = Foo()
foo.print_bar() # Will print 1

print(foo._Foo__bar) # Won't fail
print(foo.__bar) # Will fail

This renaming may catch you out if you dynamically assign functions to the class later on.

This double underscore convention is usually designed for attributes which may need to be declared again in a subclass of a class, but make sense to have the same name.


class Foo:
    __name = "Foo Class"

    def print_name(self):
        print(self.__name)


class Bar(Foo):
    __name = "Bar Class"

    def print_name(self):
        print(self.__name)

    def print_superclass_name(self):
        super().print_name()

foo = Foo()
foo.print_name() # Foo Class

bar = Bar()
bar.print_name() # Bar Class
bar.print_superclass_name() # Foo Class

If you’ve never seen super before…
Super is a magic object which allows you to get the methods (and data) of the superclass (the class that the current class inherits from). If you inherit from multiple classes, then just calling super() will not always be clear for who it refers to (it depends upon the mro (method resolution order) which is how Python sorts out (resolves) multiple inheritance). So, many people will be clear and explicit and use super like so: super(ParentCls, self).

A little bit of detailed information on classes in general. This only applies to Python 3, as many changes to the class system occurred after py2k.

  • In Python all* “things” are python objects, including functions, data types even modules. A Python object is simply a “thing” which has attributes (Foo.__name, Foo.print_name, …, X.Y). An attribute can be anything, it can be any Python object (we’re already getting into a cycle here!).
  • All Python objects have a “type”, which is the class which they are an instance of. Functions are an instance of function types, lists of a list type, modules of a module type, and so on. Most interestingly, classes themselves (not class instances) are an instance of “type”, which is the type of all base types (list, function, int, bool, str). The reason for this type of type of type of type … nonsense is because Python allows you to modify how things are created at every level. Though, this quickly gets confusing to think about.
  • All types can inherit from other types, if it wasn’t obvious. You can create your own version of dict, or list, which inherits from those types. Without any further code, they will behave as their parent classes did.
  • Functions for class instances are produced from their classes using the descriptor protocol. The descriptor protocol is used to allow developers to modify things like attribute lookups and setting. When you look up an attribute:

class Foo:
    def print_bar(self):
        print("bar")

foo = Foo()
foo.print_bar() # This involves a lookup to get print_bar from foo

The process is as follows:


def foo.__getattribute__(name):
    if name in foo.__dict__:
        return foo.__dict[name]

    elif name in type(foo).__dict__: 
        attribute = type(foo).__dict__[name]
        return attribute.__get__(foo, type(foo)) # We called the descriptor protocol here!

You’ll notice that it first tries to find the attribute on “foo” by calling foo.getattribute (which it gets by the same process, but let’s ignore that for now). If it fails (and, for our example, it does because methods are not stored on the instance, but on the class) it then tries to find the attribute on the parent class. For our example, this succeeds. But wait, isnt’ this a class-attribute, and we want a self argument for our instance? Yes, so we must invoke the descriptor protocol to ask for an attribute that is bound to our class instance (“foo”). That’s what get (for functions, as an example) does. But it’s designed to be flexible, so you could return anything. An example of something else using the descriptor protocol is properties


class Foo:
    @property
    def bar(self):
        return "FOO BAR!"

foo = Foo()
print(foo.bar) # This involves a lookup to get bar from foo

Here, property is a decorator, which is similar python syntax to:


class Foo:

    def bar(self):
        return "FOO BAR! " + str(self)

    bar = property(bar)

foo = Foo()
print(foo.bar) # This involves a lookup to get bar from foo

If you print Foo.bar, you’ll see “<property object…>”, but if you print foo.bar, you’ll see “FOO BAR! <main.Foo…>”. Why did this work? Well, the property object returns the result of the function it wraps, when its get method is called! Why did we print the value of self within bar? Because, to prove this magic, let’s manually invoke the descriptor protocol:

class Foo:

    def print_bar(self):
        print("FOO BAR! " + str(self))

foo = Foo()
print_bar = Foo.print_bar.__get__("Hello") # We manually do the lookup!
print_bar() # "FOO BAR! Hello"

And you’ll see that the value of self inside the function call was replaced with “Hello”. Why? Because that’s how self is normally provided, we just overrode it.

Tying this in with super, in our earlier example:


class Foo:
    __name = "Foo Class"

    def print_name(self):
        print(self.__name)


class Bar(Foo):
    __name = "Bar Class"

    def print_name(self):
        print(self.__name)

    def print_superclass_name(self):
        super().print_name()

foo = Foo()
foo.print_name() # Foo Class

bar = Bar()
bar.print_name() # Bar Class
bar.print_superclass_name() # Foo Class

in print_superclass_name, super().print_name() does something similar to:
Foo.print_name.get(foo)()
in otherwords, get my parent class’s print_name function, but pretend it’s mine. Super is just nice and rewires everything behind a pretty name. Woo!

  • The Python type of type of type of type notion can get confusing, quickly. To get an instance of a type (foo = Foo(), bar = Bar(), …) a method on the class is called (Foo.new, Bar.new). and that returns a class instance. The same happens when you define a class, and so on (confusing!)

Anyway, I recognise that a lot of this stuff is obscure, but it may be useful for others, so I’ll leave it in. In short, all these names of variables and other things are being used by some part of the Python interpreter that you had probably not noticed doing anything!

As a note of interest, @property is a handy trick that has a lot of uses in a video game sort of environment.

As another example on top of goose’s, let’s say we have an RPG, where the player’s Attack is Strength + Weapon Power. Since this is an RPG and a big part of an RPG is making Numbers Go Up, there’s always a decent chance that Strength and/or Weapon Power may change values between calls to the Attack method. Normally, you would want to do the addition within the Attack method to make sure you’re getting up-to-date data:


def Attack(self,target):
attackPower = self.Strength + self.weapon.Power
target.takeDamage(attackPower)

Which isn’t bad when it’s simple like this, but if you want to get attack power (and various other values that behave the same way) from outside the Attack() call itself (say, for a Stats menu display), you have to make sure you’re doing that same math every time, for every Stat, or using helper method or a method within Player. ( attackPower = self.getAttackPower() or something )

Instead, you could create an attribute of the Player class:


class Player:
def __init__(self,Strength,weapon):
self.Strength = Strength
self.weapon = weapon

self.attackPower = self.Strength + self.weapon.Power

def Attack(self,target):
target.takeDamage(self.attackPower)

But, of course, it will only do this math once (on initialization). If Strength increases after that, attackPower is not going to care, and won’t update itself to reflect that.

So in comes @property. Define a method after this decorator, and it will look and act like a method, but can be referenced to like a self.property:


class Player:
def __init__(self,Strength,weapon):
self.Strength = Strength
self.weapon = weapon

@property
def attackPower(self):
    return self.Strength + self.weapon.Power

def Attack(self,target):
    target.takeDamage(self.attackPower)

There are a lot of other decorator types, but this is the only one I know how to use so far.

for that are called “magic method” (i guess)

potentially you can do anything .

is a shame that there almost not example of game/tutorial with classes at the same time +working and +readable :frowning:

ie -> from print “hello world” to -> 58.974.000 modules

no examples :frowning:

To add on to Nines’ recommendation of subclassing, one should be aware that the process destroys the old reference to the object. This means that, for example, if you make a reference to the Player object, then set it up to subclass a custom Python class, that reference is invalid, which can cause the game to crash if you use it later. So, you have to be sure that references are valid before using them.

This is all very helpful. I haven’t read everything yet, but I wanted to say “thank you”.

@Nines: thanks for recommending my article! Glad to hear it was useful.

I love python classes. Its a bit more to wrap your head around and means you’ve got to think a bit more about your code design, but once you’ve got that down the development time is quicker and if your class design is good then extending the functionality becomes easy.

On Planet Smasher i used the factory pattern to create the player subclass on the fly. This meant i could dynamically inject new functions into the player class without breaking any old code. To make life easy with classes i’d recommend keeping a linear inheritance tree and only a few levels, otherwise things get confusing pretty quickly.

Thanks to everyone for the great info. It’s nice to see it all in one place.
I really need to learn more about decorators, I’m sure there’s some useful possibilities there but I haven’t really looked in to it before now.

There was a thread a few years back about why to use classes, and it seems difficult to understand until you actually know how and why to use them.

One place that classes work really well when using States in a Finite State Machine. Most states contain info which is not used in the other states, or which should be reset once the state changes. If you don’t use classes then you have to define all properties of all states when the game starts, and then update them every time a state changes. It can get really messy. Other states share a lot of properties and functions, so subclassing them saves a lot of duplicated code.