Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The pythonic way to access a class attribute within the class

I was wondering how do you think is the way to access a class attribute from a function within the class. I haven't found a reference in PEP8 or a popular question about it. e.g.

class MyClass(object):
    BAR = 1
    def foo(self):
        # Way A:
        print(self.BAR)

        # Way B:
        print(MyClass.BAR)

Accessing via ´self´ seems reasonable as the attribute is owned by the same class, close reference for obvious same-class reference. On the other hand, accessing via the class name itself is clear as it is static and makes the origin of the use clear and also could be more clear as it is paired with the class' name.

like image 589
Ofek .T. Avatar asked May 28 '18 13:05

Ofek .T.


2 Answers

When explicity naming the class name, you prevent subclass from overriding your attribute.

On the other hand, using self gives you this flexability. Consider the following code:

class MyClass(object):
    BAR = 1
    def foo(self):
        # Way A:
        print(self.BAR)

        # Way B:
        print(MyClass.BAR)


class SubClass(MyClass):
    BAR = 2

class SubClass2(MyClass):
    pass

# output
>>> a = SubClass()
>>> a.foo()
2
1
>>> b = SubClass2()
>>> b.foo()
1
1
like image 118
Chen A. Avatar answered Oct 13 '22 12:10

Chen A.


For reads it doesn't really matter which you use - self.BAR and MyClass.BAR are syntactically equivalent unless you have a class hierarchy where a subclass redefines the value of BAR.

For writes they are not the same. Writing to self.BAR will effectively create a new variable which is local to the self object instance, so any reads from self.BAR from another object instance will not see the modifications. These can be pretty horrible to debug because it's not obvious from the code what should happen as it is timing sensitive.

In general for class variables you really should be using MyClass.BAR if you want a specific variable from a specific level in the class hierarchy, or type(self).BAR or self.__class__.BAR if you want something which is inheritance safe. This is specifically and obviously a class variable and avoids the problem outlined above with dynamic aliases popping into existence at runtime. Using self just bakes in some fragility which can be hard to spot in future.

like image 30
solidpixel Avatar answered Oct 13 '22 10:10

solidpixel