Can I access a class variable from an instance?

Question:

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.

Asked By: Jacklynn

||

Answers:

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.

Answered By: abarnert

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

Answered By: Judah Meek
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.