59

I have this class:

class ReallyLongClassName:
    
    static_var = 5

    def instance_method(self):
        ReallyLongClassName.static_var += 1

Is there some way to access the static variable using the self variable?

I'd rather do something like class(self).static_var += 1, because long names are unreadable.

2 Answers 2

81

The answer is "yes, but…"

The best way to understand is to actually try it:

>>> class RLCN:
...     static_var = 5
...     def method1(self):
...         RLCN.static_var += 1
...     def method2(self):
...         self.static_var += 1
>>> rlcn = RLCN()
>>> RLCN.static_var, rlcn.static_var
(5, 5)
>>> rlcn.static_var
5
>>> rlcn.method1()
>>> RLCN.static_var, rlcn.static_var
(6, 6)
>>> rlcn.method2()
>>> RLCN.static_var, rlcn.static_var
(6, 7)

What happened?

Well, accessing a class attribute through self works just fine. If there is no instance attribute of the same name, you get the class attribute.

But assigning to it will hide the class attribute with a new instance attribute of the same name. Which is probably not what you wanted.

Note that this means you can use class attributes as "default values" or "initial values" for instance attributes. But I'm not sure it's very Pythonic to do so; what's actually happening, and what a novice (especially someone coming from, e.g., C++11 or Java) thinks is happening, are very different.

(Things get slightly more complicated when you deal with descriptors, like methods or @propertys, but let's ignore that; in the simple case that you're discussing, it's not relevant.)


I'd rather do something like class(self).static_var += 1, because long names are unreadable.

You can, you just need to spell it right: type is the function that returns the type of any object. So:

type(self).static_var += 1

This has the added advantage of being dynamic (e.g., when you have multiple inheritance and don't know which side a @property comes from, you probably don't want to explicitly list a class name, for basically the same reason you want to use super() instead of explicitly calling a base class method).

This has the disadvantage of not working on old-style classes in Python 2.x, but then you shouldn't be using those anyway. Especially in classes that have a need for class attributes, because those are exactly the types you're often going to later want to add @classmethods, @propertys, etc. to, and none of that works with old-style classes (along with many other things). If you really need to handle old-style and new-style classes transparently for some reason, self.__class__ is works with old-style classes. I'm not sure it's guaranteed to work with new-style classes; the docs say that the return value of type(object) is "generally the same object as returned by object.__class__", but doesn't say under what conditions that "generally" is untrue. It's also documented as a special attribute "added by the implementation" for "several object types" in 3.x. In practice, I don't know of any cases where they're different in 3.x, and in 2.x, the most prominent case where they're different is old-style classes.

Sign up to request clarification or add additional context in comments.

7 Comments

It seems that type(self).static_var += 1 works only in Python3.
@AntonSavin: No, it works in Python 2 just fine. See it here in Python 2.7.2.
@AntonSavin: If you're using old-style classes, sure, type doesn't work, and all of the relevant benefits become irrelevant anyway, since super, @property, multiple inheritance, etc. don't work on old-style classes anyway. But the answer to that is simple: don't use old-style classes. But I'll add a comment to that effect.
Good explanation..the only drawback is see is if one changes the class name after creating the class, then all reference to the old class name in the class itself will need to be changed....
Is there an accepted name for the promotion of class variables to instance variables on assignment? Googling for an explanation of what is happening in method2 is tough.
|
78

Use self.__class__.classAttr. This should work for both old & new style classes.

3 Comments

Is this somehow better than type(self)?
@Alexey see the comments on stackoverflow.com/a/25577642/5241481
Please don't get convinced by upvotes, self.__class__ is very un-pythonic, and using type(self) should be the way to do it (if you don't want the classname hardcoded) as illustrated by stackoverflow.com/a/25577642/860421. The only case to be cautious in is when you're accessing superclass's attribute in an inherited class & the attribute name starts (but not ends) with __, as name mangling will haunt you. In any case, using hardcoded classname is the safest approach.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.