Are static class variables possible in Python?

1,459,299

Solution 1

Variables declared inside the class definition, but not inside a method are class or static variables:

>>> class MyClass:
...     i = 3
...
>>> MyClass.i
3 

As @millerdev points out, this creates a class-level i variable, but this is distinct from any instance-level i variable, so you could have

>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)

This is different from C++ and Java, but not so different from C#, where a static member can't be accessed using a reference to an instance.

See what the Python tutorial has to say on the subject of classes and class objects.

@Steve Johnson has already answered regarding static methods, also documented under "Built-in Functions" in the Python Library Reference.

class C:
    @staticmethod
    def f(arg1, arg2, ...): ...

@beidy recommends classmethods over staticmethod, as the method then receives the class type as the first argument.

Solution 2

@Blair Conrad said static variables declared inside the class definition, but not inside a method are class or "static" variables:

>>> class Test(object):
...     i = 3
...
>>> Test.i
3

There are a few gotcha's here. Carrying on from the example above:

>>> t = Test()
>>> t.i     # "static" variable accessed via instance
3
>>> t.i = 5 # but if we assign to the instance ...
>>> Test.i  # we have not changed the "static" variable
3
>>> t.i     # we have overwritten Test.i on t by creating a new attribute t.i
5
>>> Test.i = 6 # to change the "static" variable we do it by assigning to the class
>>> t.i
5
>>> Test.i
6
>>> u = Test()
>>> u.i
6           # changes to t do not affect new instances of Test

# Namespaces are one honking great idea -- let's do more of those!
>>> Test.__dict__
{'i': 6, ...}
>>> t.__dict__
{'i': 5}
>>> u.__dict__
{}

Notice how the instance variable t.i got out of sync with the "static" class variable when the attribute i was set directly on t. This is because i was re-bound within the t namespace, which is distinct from the Test namespace. If you want to change the value of a "static" variable, you must change it within the scope (or object) where it was originally defined. I put "static" in quotes because Python does not really have static variables in the sense that C++ and Java do.

Although it doesn't say anything specific about static variables or methods, the Python tutorial has some relevant information on classes and class objects.

@Steve Johnson also answered regarding static methods, also documented under "Built-in Functions" in the Python Library Reference.

class Test(object):
    @staticmethod
    def f(arg1, arg2, ...):
        ...

@beid also mentioned classmethod, which is similar to staticmethod. A classmethod's first argument is the class object. Example:

class Test(object):
    i = 3 # class (or static) variable
    @classmethod
    def g(cls, arg):
        # here we can use 'cls' instead of the class name (Test)
        if arg > cls.i:
            cls.i = arg # would be the same as Test.i = arg1

Pictorial Representation Of Above Example

Solution 3

Static and Class Methods

As the other answers have noted, static and class methods are easily accomplished using the built-in decorators:

class Test(object):

    # regular instance method:
    def MyMethod(self):
        pass

    # class method:
    @classmethod
    def MyClassMethod(cls):
        pass

    # static method:
    @staticmethod
    def MyStaticMethod():
        pass

As usual, the first argument to MyMethod() is bound to the class instance object. In contrast, the first argument to MyClassMethod() is bound to the class object itself (e.g., in this case, Test). For MyStaticMethod(), none of the arguments are bound, and having arguments at all is optional.

"Static Variables"

However, implementing "static variables" (well, mutable static variables, anyway, if that's not a contradiction in terms...) is not as straight forward. As millerdev pointed out in his answer, the problem is that Python's class attributes are not truly "static variables". Consider:

class Test(object):
    i = 3  # This is a class attribute

x = Test()
x.i = 12   # Attempt to change the value of the class attribute using x instance
assert x.i == Test.i  # ERROR
assert Test.i == 3    # Test.i was not affected
assert x.i == 12      # x.i is a different object than Test.i

This is because the line x.i = 12 has added a new instance attribute i to x instead of changing the value of the Test class i attribute.

Partial expected static variable behavior, i.e., syncing of the attribute between multiple instances (but not with the class itself; see "gotcha" below), can be achieved by turning the class attribute into a property:

class Test(object):

    _i = 3

    @property
    def i(self):
        return type(self)._i

    @i.setter
    def i(self,val):
        type(self)._i = val

## ALTERNATIVE IMPLEMENTATION - FUNCTIONALLY EQUIVALENT TO ABOVE ##
## (except with separate methods for getting and setting i) ##

class Test(object):

    _i = 3

    def get_i(self):
        return type(self)._i

    def set_i(self,val):
        type(self)._i = val

    i = property(get_i, set_i)

Now you can do:

x1 = Test()
x2 = Test()
x1.i = 50
assert x2.i == x1.i  # no error
assert x2.i == 50    # the property is synced

The static variable will now remain in sync between all class instances.

(NOTE: That is, unless a class instance decides to define its own version of _i! But if someone decides to do THAT, they deserve what they get, don't they???)

Note that technically speaking, i is still not a 'static variable' at all; it is a property, which is a special type of descriptor. However, the property behavior is now equivalent to a (mutable) static variable synced across all class instances.

Immutable "Static Variables"

For immutable static variable behavior, simply omit the property setter:

class Test(object):

    _i = 3

    @property
    def i(self):
        return type(self)._i

## ALTERNATIVE IMPLEMENTATION - FUNCTIONALLY EQUIVALENT TO ABOVE ##
## (except with separate methods for getting i) ##

class Test(object):

    _i = 3

    def get_i(self):
        return type(self)._i

    i = property(get_i)

Now attempting to set the instance i attribute will return an AttributeError:

x = Test()
assert x.i == 3  # success
x.i = 12         # ERROR

One Gotcha to be Aware of

Note that the above methods only work with instances of your class - they will not work when using the class itself. So for example:

x = Test()
assert x.i == Test.i  # ERROR

# x.i and Test.i are two different objects:
type(Test.i)  # class 'property'
type(x.i)     # class 'int'

The line assert Test.i == x.i produces an error, because the i attribute of Test and x are two different objects.

Many people will find this surprising. However, it should not be. If we go back and inspect our Test class definition (the second version), we take note of this line:

    i = property(get_i) 

Clearly, the member i of Test must be a property object, which is the type of object returned from the property function.

If you find the above confusing, you are most likely still thinking about it from the perspective of other languages (e.g. Java or c++). You should go study the property object, about the order in which Python attributes are returned, the descriptor protocol, and the method resolution order (MRO).

I present a solution to the above 'gotcha' below; however I would suggest - strenuously - that you do not try to do something like the following until - at minimum - you thoroughly understand why assert Test.i = x.i causes an error.

REAL, ACTUAL Static Variables - Test.i == x.i

I present the (Python 3) solution below for informational purposes only. I am not endorsing it as a "good solution". I have my doubts as to whether emulating the static variable behavior of other languages in Python is ever actually necessary. However, regardless as to whether it is actually useful, the below should help further understanding of how Python works.

UPDATE: this attempt is really pretty awful; if you insist on doing something like this (hint: please don't; Python is a very elegant language and shoe-horning it into behaving like another language is just not necessary), use the code in Ethan Furman's answer instead.

Emulating static variable behavior of other languages using a metaclass

A metaclass is the class of a class. The default metaclass for all classes in Python (i.e., the "new style" classes post Python 2.3 I believe) is type. For example:

type(int)  # class 'type'
type(str)  # class 'type'
class Test(): pass
type(Test) # class 'type'

However, you can define your own metaclass like this:

class MyMeta(type): pass

And apply it to your own class like this (Python 3 only):

class MyClass(metaclass = MyMeta):
    pass

type(MyClass)  # class MyMeta

Below is a metaclass I have created which attempts to emulate "static variable" behavior of other languages. It basically works by replacing the default getter, setter, and deleter with versions which check to see if the attribute being requested is a "static variable".

A catalog of the "static variables" is stored in the StaticVarMeta.statics attribute. All attribute requests are initially attempted to be resolved using a substitute resolution order. I have dubbed this the "static resolution order", or "SRO". This is done by looking for the requested attribute in the set of "static variables" for a given class (or its parent classes). If the attribute does not appear in the "SRO", the class will fall back on the default attribute get/set/delete behavior (i.e., "MRO").

from functools import wraps

class StaticVarsMeta(type):
    '''A metaclass for creating classes that emulate the "static variable" behavior
    of other languages. I do not advise actually using this for anything!!!
    
    Behavior is intended to be similar to classes that use __slots__. However, "normal"
    attributes and __statics___ can coexist (unlike with __slots__). 
    
    Example usage: 
        
        class MyBaseClass(metaclass = StaticVarsMeta):
            __statics__ = {'a','b','c'}
            i = 0  # regular attribute
            a = 1  # static var defined (optional)
            
        class MyParentClass(MyBaseClass):
            __statics__ = {'d','e','f'}
            j = 2              # regular attribute
            d, e, f = 3, 4, 5  # Static vars
            a, b, c = 6, 7, 8  # Static vars (inherited from MyBaseClass, defined/re-defined here)
            
        class MyChildClass(MyParentClass):
            __statics__ = {'a','b','c'}
            j = 2  # regular attribute (redefines j from MyParentClass)
            d, e, f = 9, 10, 11   # Static vars (inherited from MyParentClass, redefined here)
            a, b, c = 12, 13, 14  # Static vars (overriding previous definition in MyParentClass here)'''
    statics = {}
    def __new__(mcls, name, bases, namespace):
        # Get the class object
        cls = super().__new__(mcls, name, bases, namespace)
        # Establish the "statics resolution order"
        cls.__sro__ = tuple(c for c in cls.__mro__ if isinstance(c,mcls))
                        
        # Replace class getter, setter, and deleter for instance attributes
        cls.__getattribute__ = StaticVarsMeta.__inst_getattribute__(cls, cls.__getattribute__)
        cls.__setattr__ = StaticVarsMeta.__inst_setattr__(cls, cls.__setattr__)
        cls.__delattr__ = StaticVarsMeta.__inst_delattr__(cls, cls.__delattr__)
        # Store the list of static variables for the class object
        # This list is permanent and cannot be changed, similar to __slots__
        try:
            mcls.statics[cls] = getattr(cls,'__statics__')
        except AttributeError:
            mcls.statics[cls] = namespace['__statics__'] = set() # No static vars provided
        # Check and make sure the statics var names are strings
        if any(not isinstance(static,str) for static in mcls.statics[cls]):
            typ = dict(zip((not isinstance(static,str) for static in mcls.statics[cls]), map(type,mcls.statics[cls])))[True].__name__
            raise TypeError('__statics__ items must be strings, not {0}'.format(typ))
        # Move any previously existing, not overridden statics to the static var parent class(es)
        if len(cls.__sro__) > 1:
            for attr,value in namespace.items():
                if attr not in StaticVarsMeta.statics[cls] and attr != ['__statics__']:
                    for c in cls.__sro__[1:]:
                        if attr in StaticVarsMeta.statics[c]:
                            setattr(c,attr,value)
                            delattr(cls,attr)
        return cls
    def __inst_getattribute__(self, orig_getattribute):
        '''Replaces the class __getattribute__'''
        @wraps(orig_getattribute)
        def wrapper(self, attr):
            if StaticVarsMeta.is_static(type(self),attr):
                return StaticVarsMeta.__getstatic__(type(self),attr)
            else:
                return orig_getattribute(self, attr)
        return wrapper
    def __inst_setattr__(self, orig_setattribute):
        '''Replaces the class __setattr__'''
        @wraps(orig_setattribute)
        def wrapper(self, attr, value):
            if StaticVarsMeta.is_static(type(self),attr):
                StaticVarsMeta.__setstatic__(type(self),attr, value)
            else:
                orig_setattribute(self, attr, value)
        return wrapper
    def __inst_delattr__(self, orig_delattribute):
        '''Replaces the class __delattr__'''
        @wraps(orig_delattribute)
        def wrapper(self, attr):
            if StaticVarsMeta.is_static(type(self),attr):
                StaticVarsMeta.__delstatic__(type(self),attr)
            else:
                orig_delattribute(self, attr)
        return wrapper
    def __getstatic__(cls,attr):
        '''Static variable getter'''
        for c in cls.__sro__:
            if attr in StaticVarsMeta.statics[c]:
                try:
                    return getattr(c,attr)
                except AttributeError:
                    pass
        raise AttributeError(cls.__name__ + " object has no attribute '{0}'".format(attr))
    def __setstatic__(cls,attr,value):
        '''Static variable setter'''
        for c in cls.__sro__:
            if attr in StaticVarsMeta.statics[c]:
                setattr(c,attr,value)
                break
    def __delstatic__(cls,attr):
        '''Static variable deleter'''
        for c in cls.__sro__:
            if attr in StaticVarsMeta.statics[c]:
                try:
                    delattr(c,attr)
                    break
                except AttributeError:
                    pass
        raise AttributeError(cls.__name__ + " object has no attribute '{0}'".format(attr))
    def __delattr__(cls,attr):
        '''Prevent __sro__ attribute from deletion'''
        if attr == '__sro__':
            raise AttributeError('readonly attribute')
        super().__delattr__(attr)
    def is_static(cls,attr):
        '''Returns True if an attribute is a static variable of any class in the __sro__'''
        if any(attr in StaticVarsMeta.statics[c] for c in cls.__sro__):
            return True
        return False

Solution 4

You can also add class variables to classes on the fly

>>> class X:
...     pass
... 
>>> X.bar = 0
>>> x = X()
>>> x.bar
0
>>> x.foo
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
AttributeError: X instance has no attribute 'foo'
>>> X.foo = 1
>>> x.foo
1

And class instances can change class variables

class X:
  l = []
  def __init__(self):
    self.l.append(1)

print X().l
print X().l

>python test.py
[1]
[1, 1]

Solution 5

Personally I would use a classmethod whenever I needed a static method. Mainly because I get the class as an argument.

class myObj(object):
   def myMethod(cls)
     ...
   myMethod = classmethod(myMethod) 

or use a decorator

class myObj(object):
   @classmethod
   def myMethod(cls)

For static properties.. Its time you look up some python definition.. variable can always change. There are two types of them mutable and immutable.. Also, there are class attributes and instance attributes.. Nothing really like static attributes in the sense of java & c++

Why use static method in pythonic sense, if it has no relation whatever to the class! If I were you, I'd either use classmethod or define the method independent from the class.

Share:
1,459,299
Andrew Walker
Author by

Andrew Walker

Engineer specialising in software engineering for robotics and mechatronics Engineer. Completed a PhD in 2011 on "Hard Real-Time Motion Planning for Autonomous Vehicles". Currently employed in the Defence &amp; Aerospace industry. I enjoy working in Python, Mathematica and C/C++, and I'm passionate about developing and verifying high integrity software.

Updated on July 10, 2022

Comments

  • Andrew Walker
    Andrew Walker almost 2 years

    Is it possible to have static class variables or methods in Python? What syntax is required to do this?

  • tmsppc
    tmsppc over 11 years
    I'm just learning Python, but the advantages of @classmethod over @staticmethod AFAIK is that you always get the name of the class the method was invoked on, even if it's a subclass. A static method lacks this information, so it cannot call an overridden method, for example.
  • zakdances
    zakdances about 11 years
    Will the new class variables stick even if the class is imported into another module?
  • john_science
    john_science about 11 years
    @Blair Is this something I want to do. As an example, if you wanted to be able to access PI = 3.14 lots of times in a class (ignoring math libraries for argument sake), would your really do MyClass.PI in all those places? What is the Pythonic approach? Doesn't this look kind of cluttered and ugly? Or am I wrong?
  • Giszmo
    Giszmo almost 11 years
    @theJollySin the pythonic way for constants is to not grow a class for constants. Just have some const.py with PI = 3.14 and you can import it everywhere. from const import PI
  • Mark
    Mark over 9 years
    I suggest you extend the example just a little: if, after setting Test.i=6, you then instantiate a new object (e.g., u=Test()), the new object will "inherit" the new class value (e.g., u.i==6)
  • yantrab
    yantrab over 9 years
    Why is it even a class if you aren't going to instantiate it? This feels like twisting Python to turn it into Java....
  • Rick
    Rick over 9 years
    A way to keep the static variables in sync is to make them properties: class Test(object):, _i = 3, @property, def i(self),return type(self)._i, @i.setter, def i(self,val):, type(self)._i = val. Now you can do x = Test(), x.i = 12, assert x.i == Test.i.
  • Rick
    Rick over 9 years
    You could also just use @property, which is the same as using a descriptor, but it's a lot less code.
  • Rick
    Rick over 9 years
    This answer is likely to confuse the static variable issue. To begin with, i = 3 is not a static variable, it is a class attribute, and since it is distinct from an instance-level attribute i it does not behave like a static variable in other languages. See millerdev's answer, Yann's answer, and my answer below.
  • Rick
    Rick over 9 years
    The Borg idiom is a better way to handle this.
  • Muhammed Refaat
    Muhammed Refaat about 9 years
    I tried to use your way but I faced a problem, kindly have a look at my question here stackoverflow.com/questions/29329850/get-static-variable-val‌​ue
  • Ole Thomsen Buus
    Ole Thomsen Buus about 9 years
    @RickTeachey: I guess you should generally view anything you do on the class Instance Test (before using it for instantiating instances) as being in the domain of meta-programming? For instance, you alter the class-behavior by doing Test.i = 0 (here you simply destroy the property object entirely). I guess the "property-mechanism" kicks in only on property-access on instances of a class (unless you change underlying behavior using a meta-class as an intermediate, perhaps). Btw, please finish this answer :-)
  • Rick
    Rick about 9 years
    @OleThomsenBuus Um, I wouldn't quite put it that way. It would be more correct to call it "class object programming" and "instance object programming" - because classes ARE objects. The meta programming is only necessary (in this particular case) if you wish to erase the line between instance and class, which is where a "static variable" lives. The property behavior works because instance objects delegate attribute access to their class in certain cases (eg when the attribute doesn't exist). Also: I promise I will get around to finishing up what I had in mind for this answer. Just been busy.
  • Ole Thomsen Buus
    Ole Thomsen Buus about 9 years
    @RickTeachey Thanks :-) Your metaclass in the end is interesting but is actually a bit too complex for my liking. It might be useful in a large framework/application where this mechanism is absolutely required. Anyway, this exemplifies that if new (complex) non-default meta-behavior is really needed, Python makes it possible :)
  • yoyo
    yoyo almost 9 years
    Seems this sort of class variable cannot be accessed during __del__? In my limited experience the class variables are going away before __del__ runs. Is this expected?
  • Ali
    Ali over 8 years
    So I could say all variables are static initially and then accessing instances makes instance variables at runtime?
  • Błażej Michalik
    Błażej Michalik over 7 years
    @classmethod superiority over @staticmethod is IMO the fact, that you can easily refactorize class methods and break them up into smaller ones, while with @staticmethod you are basically stuck with what you've got. Refactorizing static method C.m() would require adding class reference C to each call, not to mention fetching class fields. This probably has negative side effects on polymorphism in some cases.
  • gauteh
    gauteh over 7 years
    This would give a quite different behavior if you were using a mutable variable like a list: i = [], then m.i.append (1) would change the contents of the variable in the class as well.
  • Ethan Furman
    Ethan Furman about 7 years
    @OleThomsenBuus: Check my answer for a simpler metaclass that does the job.
  • Saurabh Jain
    Saurabh Jain almost 7 years
    so only one copy of i(static variable) will be in memory even if I create hundreds of instance of this class ?
  • Rick
    Rick almost 7 years
    yes, but in this case hasattr(SomeClass, 'x') is False. i doubt this is what anyone means by a static variable at all.
  • jmunsch
    jmunsch almost 7 years
    @RickTeachey lol, saw your static variable code, stackoverflow.com/a/27568860/2026508 +1 internet sir, and i thought hasattr didn't work like that? so is some_var immutable, and statically defined, or is it not? What does outside getter access have to do with a variable being static or not? i have so many questions now. would love to hear some answers when you get the time.
  • Rick
    Rick almost 7 years
    Yeah that metaclass is pretty ridiculous. I'm not certain I understand the questions but to my mind, some_var above isn't a class member at all. In Python all class members can be accessed from outside the class.
  • Rick
    Rick almost 7 years
    The nonlocal keywoard "bumps" the scope of the variable. The scope of a class body definition is independent of the scope it finds itself in- when you say nonlocal some_var, that is just creating a non-local (read: NOT in the class definition scope) name reference to another named object. Therefore it doesn't get attached to the class definition because it is not in the class body scope.
  • Davis Herring
    Davis Herring over 6 years
    Variables are not mutable or immutable; objects are. (However, an object can, with varying degrees of success, try to prevent assignment to certain of its attributes.)
  • taper
    taper over 6 years
    I tried and found that @property is not synced between class instances in python 3. Is that a feature of old python language?
  • Rick
    Rick over 6 years
    @taper as explained in the answer above, @property is in sync between class instances (for all versions of python going back a long time). the class member of the same name as the property attached to the class object itself is not in sync with the instances.
  • taper
    taper over 6 years
    Dear @RickTeachey , I cannot understand your point because of some terminologies I am not familiar with. But what I mean could be demonstrated by this gist. If you run it in python 3.6.3 (which I did), it gives different result as claimed by this answer.
  • Rick
    Rick over 6 years
    @taper You are correct; I have edited the answer to fix the problem (can't believe it's been sitting there wrong for so long!). Sorry for the confusion.
  • OfirD
    OfirD about 6 years
    For anyone's interested who's Daniel mentioned in @Dubslow comment, it is millerdev (wayback machine)
  • Pablo
    Pablo about 6 years
    Perhaps this is interesting: if you define a method in Test that changes Test.i, that will affect BOTH Test.i and t.i values.
  • cowbert
    cowbert about 6 years
    @sdream yes, since the only reference to i is its assignment on the class. In order to access this from an instance is via instance.__class__.i
  • Pedro
    Pedro almost 6 years
    Yes. Classes are effectively singletons, regardless of the namespace you call them from.
  • NightOwl19
    NightOwl19 over 5 years
    @millerdev, like u mentioned Python doesn't have static variables as C++ or JAVA have..So will it be okay to say, Test.i is more of a class variable rather than a static variable?
  • stevepastelan
    stevepastelan over 5 years
    @NedBatchelder It's an abstract class, intended only for subclassing (and instantiating the subclasses)
  • yantrab
    yantrab over 5 years
    I hope the subclasses don't use super() to invoke the __new__ of its parents...
  • Howard Lovatt
    Howard Lovatt about 5 years
    Really like the write up. One nit pick the immutable version isn't really immutable because you can assign a lambda to get_i that returns a different value.
  • Rick
    Rick about 5 years
    @HowardLovatt it doesn't actually work that way. if you try to monkeypatch get_i after the property has been created, it will not overwrite the property. try it.
  • Howard Lovatt
    Howard Lovatt about 5 years
    The following changes t.i for me: t.get_i = lambda s: 7 ; assert t.i == 7 # ERROR i changed.
  • Rick
    Rick about 5 years
    @HowardLovatt your assert statement should be assert t.i == 3 and there is no error.
  • Howard Lovatt
    Howard Lovatt about 5 years
    @RickTeachey No it passes the assert for me, i.e. t.i is 7 - it has changed. This is true on Pythonista which uses 3.6 (I think) and on 3.7 (via PyCharm).
  • Rick
    Rick about 5 years
    @HowardLovatt that's odd. It will definitely will not change the value on any version of python I've ever used if you set the property first and then swap out the getter (or setter) without overwriting the property. That's just not how it works.
  • ShadowRanger
    ShadowRanger almost 5 years
    Umm... static methods are made with @staticmethod; @classmethod is (obviously) for class methods (which are primarily intended for use as alternate constructors, but can serve in a pinch as static methods which happen to receive a reference to the class that they were called through).
  • Thomas Weller
    Thomas Weller almost 5 years
    The indentation is broken. This won't execute
  • Angel O'Sphere
    Angel O'Sphere over 4 years
    Java and C++ use static (ill use of the word, imho) exactly as you use instance versus class attribute. A class attribute/method is static in Java and C++, no difference, except that in Python the first parameter to a class method call is the class.
  • Amr ALHOSSARY
    Amr ALHOSSARY over 4 years
    @Gregory you said "And class instances can change class variables" Actually this example is called access not modification. The modification was done by the object itself through its own append() function.
  • chepner
    chepner over 3 years
    I vaguely remember reading some comments from Guido van Rossum regarding the introduction of class and static methods. IIRC, static methods are what correspond more closely to class methods in other languages. The Python classmethod was more or less a "mistake", though it became the natural way to define an alternate class constructor to use in place of __new__.
  • Andrew
    Andrew over 3 years
    What you call 'static' variables are, I think, class variables. Viz: class A(): inner_var = 0 class B(A): pass A.inner_var = 15 B.inner_var = 30 print ("A:static=" + str(A.inner_var)) print ("B:static=" + str(B.inner_var)) # Output: # A:static=15 # B:static=30
  • Alex
    Alex over 3 years
    This is a little bit scary when coming from other programming languages and expect it to be just a private/protected field.
  • Sunil Garg
    Sunil Garg almost 3 years
    hey hi can you please help me on this stackoverflow.com/questions/68301705/…
  • joseville
    joseville over 2 years
    For completion, it should be noted that "static" variables that are modified in-place will stay in sync. E.g. if i had been a list instead of an int, then whether you do t.i[0] = 5 or Test.i[0] = 5, every Test instance and the Test class itself will see the change: @millerdev's example with i as a list instead of an int. I think this is because you're not overwriting the value of i, a reference, but you're following the reference and modifying the underlying data structure in-place.
  • ingyhere
    ingyhere over 2 years
    @RicksupportsMonica Using type(self) doesn't work as provided, at least in Python 3.9. I read your full answer, but my tests don't bear it out. Incidentally, I am declaring a number of staticmethod functions in the class.