How do I create static class variables or methods in Python?
static
actually means several things in C++ (abbreviated definitions due to very strict comment length). There's file scoped static
inherited from C which means "this variable/function is usable in this file only", there's class scoped static
which means "this method or field is associated with the type and not any instance of the type" (rarely used in C++ but common in C#/Java/ObjC, for example, I think this is what the OP is asking about), there's local variable static
in functions which means "this variable's value is retained between function calls".
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.
@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
https://i.stack.imgur.com/xqnxe.jpg
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
.
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 my_method(self):
pass
# class method:
@classmethod
def my_class_method(cls):
pass
# static method:
@staticmethod
def my_static_method():
pass
As usual, the first argument to my_method()
is bound to the class instance object. In contrast, the first argument to my_class_method()
is bound to the class object itself (e.g., in this case, Test
). For my_static_method()
, 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
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 :-)
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]
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.
One special thing to note about static properties & instance properties, shown in the example below:
class my_cls:
my_prop = 0
#static property
print my_cls.my_prop #--> 0
#assign value to static property
my_cls.my_prop = 1
print my_cls.my_prop #--> 1
#access static property thru' instance
my_inst = my_cls()
print my_inst.my_prop #--> 1
#instance property is different from static property
#after being assigned a value
my_inst.my_prop = 2
print my_cls.my_prop #--> 1
print my_inst.my_prop #--> 2
This means before assigning the value to instance property, if we try to access the property thru' instance, the static value is used. Each property declared in python class always has a static slot in memory.
Static methods in python are called classmethods. Take a look at the following code
class MyClass:
def myInstanceMethod(self):
print 'output from an instance method'
@classmethod
def myStaticMethod(cls):
print 'output from a static method'
>>> MyClass.myInstanceMethod()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method myInstanceMethod() must be called [...]
>>> MyClass.myStaticMethod()
output from a static method
Notice that when we call the method myInstanceMethod, we get an error. This is because it requires that method be called on an instance of this class. The method myStaticMethod is set as a classmethod using the decorator @classmethod.
Just for kicks and giggles, we could call myInstanceMethod on the class by passing in an instance of the class, like so:
>>> MyClass.myInstanceMethod(MyClass())
output from an instance method
@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).
It is possible to have static
class variables, but probably not worth the effort.
Here's a proof-of-concept written in Python 3 -- if any of the exact details are wrong the code can be tweaked to match just about whatever you mean by a static variable
:
class Static:
def __init__(self, value, doc=None):
self.deleted = False
self.value = value
self.__doc__ = doc
def __get__(self, inst, cls=None):
if self.deleted:
raise AttributeError('Attribute not set')
return self.value
def __set__(self, inst, value):
self.deleted = False
self.value = value
def __delete__(self, inst):
self.deleted = True
class StaticType(type):
def __delattr__(cls, name):
obj = cls.__dict__.get(name)
if isinstance(obj, Static):
obj.__delete__(name)
else:
super(StaticType, cls).__delattr__(name)
def __getattribute__(cls, *args):
obj = super(StaticType, cls).__getattribute__(*args)
if isinstance(obj, Static):
obj = obj.__get__(cls, cls.__class__)
return obj
def __setattr__(cls, name, val):
# check if object already exists
obj = cls.__dict__.get(name)
if isinstance(obj, Static):
obj.__set__(name, val)
else:
super(StaticType, cls).__setattr__(name, val)
and in use:
class MyStatic(metaclass=StaticType):
"""
Testing static vars
"""
a = Static(9)
b = Static(12)
c = 3
class YourStatic(MyStatic):
d = Static('woo hoo')
e = Static('doo wop')
and some tests:
ms1 = MyStatic()
ms2 = MyStatic()
ms3 = MyStatic()
assert ms1.a == ms2.a == ms3.a == MyStatic.a
assert ms1.b == ms2.b == ms3.b == MyStatic.b
assert ms1.c == ms2.c == ms3.c == MyStatic.c
ms1.a = 77
assert ms1.a == ms2.a == ms3.a == MyStatic.a
ms2.b = 99
assert ms1.b == ms2.b == ms3.b == MyStatic.b
MyStatic.a = 101
assert ms1.a == ms2.a == ms3.a == MyStatic.a
MyStatic.b = 139
assert ms1.b == ms2.b == ms3.b == MyStatic.b
del MyStatic.b
for inst in (ms1, ms2, ms3):
try:
getattr(inst, 'b')
except AttributeError:
pass
else:
print('AttributeError not raised on %r' % attr)
ms1.c = 13
ms2.c = 17
ms3.c = 19
assert ms1.c == 13
assert ms2.c == 17
assert ms3.c == 19
MyStatic.c = 43
assert ms1.c == 13
assert ms2.c == 17
assert ms3.c == 19
ys1 = YourStatic()
ys2 = YourStatic()
ys3 = YourStatic()
MyStatic.b = 'burgler'
assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a
assert ys1.b == ys2.b == ys3.b == YourStatic.b == MyStatic.b
assert ys1.d == ys2.d == ys3.d == YourStatic.d
assert ys1.e == ys2.e == ys3.e == YourStatic.e
ys1.a = 'blah'
assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a
ys2.b = 'kelp'
assert ys1.b == ys2.b == ys3.b == YourStatic.b == MyStatic.b
ys1.d = 'fee'
assert ys1.d == ys2.d == ys3.d == YourStatic.d
ys2.e = 'fie'
assert ys1.e == ys2.e == ys3.e == YourStatic.e
MyStatic.a = 'aargh'
assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a
When define some member variable outside any member method, the variable can be either static or non-static depending on how the variable is expressed.
CLASSNAME.var is static variable
INSTANCENAME.var is not static variable.
self.var inside class is not static variable.
var inside the class member function is not defined.
For example:
#!/usr/bin/python
class A:
var=1
def printvar(self):
print "self.var is %d" % self.var
print "A.var is %d" % A.var
a = A()
a.var = 2
a.printvar()
A.var = 3
a.printvar()
The results are
self.var is 2
A.var is 1
self.var is 2
A.var is 3
@dataclass definitions provide class-level names that are used to define the instance variables and the initialization method, __init__()
. If you want class-level variable in @dataclass
you should use typing.ClassVar
type hint. The ClassVar
type's parameters define the class-level variable's type.
from typing import ClassVar
from dataclasses import dataclass
@dataclass
class Test:
i: ClassVar[int] = 10
x: int
y: int
def __repr__(self):
return f"Test({self.x=}, {self.y=}, {Test.i=})"
Usage examples:
> test1 = Test(5, 6)
> test2 = Test(10, 11)
> test1
Test(self.x=5, self.y=6, Test.i=10)
> test2
Test(self.x=10, self.y=11, Test.i=10)
You could also enforce a class to be static using metaclass.
class StaticClassError(Exception):
pass
class StaticClass:
__metaclass__ = abc.ABCMeta
def __new__(cls, *args, **kw):
raise StaticClassError("%s is a static class and cannot be initiated."
% cls)
class MyClass(StaticClass):
a = 1
b = 3
@staticmethod
def add(x, y):
return x+y
Then whenever by accident you try to initialize MyClass you'll get an StaticClassError.
__new__
of its parents...
One very interesting point about Python's attribute lookup is that it can be used to create "virtual variables":
class A(object):
label="Amazing"
def __init__(self,d):
self.data=d
def say(self):
print("%s %s!"%(self.label,self.data))
class B(A):
label="Bold" # overrides A.label
A(5).say() # Amazing 5!
B(3).say() # Bold 3!
Normally there aren't any assignments to these after they are created. Note that the lookup uses self
because, although label
is static in the sense of not being associated with a particular instance, the value still depends on the (class of the) instance.
Yes, definitely possible to write static variables and methods in python.
Static Variables : Variable declared at class level are called static variable which can be accessed directly using class name.
>>> class A:
...my_var = "shagun"
>>> print(A.my_var)
shagun
Instance variables: Variables that are related and accessed by instance of a class are instance variables.
>>> a = A()
>>> a.my_var = "pruthi"
>>> print(A.my_var,a.my_var)
shagun pruthi
Static Methods: Similar to variables, static methods can be accessed directly using class Name. No need to create an instance.
But keep in mind, a static method cannot call a non-static method in python.
>>> class A:
... @staticmethod
... def my_static_method():
... print("Yippey!!")
...
>>> A.my_static_method()
Yippey!!
In regards to this answer, for a constant static variable, you can use a descriptor. Here's an example:
class ConstantAttribute(object):
'''You can initialize my value but not change it.'''
def __init__(self, value):
self.value = value
def __get__(self, obj, type=None):
return self.value
def __set__(self, obj, val):
pass
class Demo(object):
x = ConstantAttribute(10)
class SubDemo(Demo):
x = 10
demo = Demo()
subdemo = SubDemo()
# should not change
demo.x = 100
# should change
subdemo.x = 100
print "small demo", demo.x
print "small subdemo", subdemo.x
print "big demo", Demo.x
print "big subdemo", SubDemo.x
resulting in ...
small demo 10
small subdemo 100
big demo 10
big subdemo 10
You can always raise an exception if quietly ignoring setting value (pass
above) is not your thing. If you're looking for a C++, Java style static class variable:
class StaticAttribute(object):
def __init__(self, value):
self.value = value
def __get__(self, obj, type=None):
return self.value
def __set__(self, obj, val):
self.value = val
Have a look at this answer and the official docs HOWTO for more information about descriptors.
@property
, which is the same as using a descriptor, but it's a lot less code.
With Object datatypes it is possible. But with primitive types like bool
, int
, float
or str
bahaviour is different from other OOP languages. Because in inherited class static attribute does not exist. If attribute does not exists in inherited class, Python start to look for it in parent class. If found in parent class, its value will be returned. When you decide to change value in inherited class, static attribute will be created in runtime. In next time of reading inherited static attribute its value will be returned, bacause it is already defined. Objects (lists, dicts) works as a references so it is safe to use them as static attributes and inherit them. Object address is not changed when you change its attribute values.
Example with integer data type:
class A:
static = 1
class B(A):
pass
print(f"int {A.static}") # get 1 correctly
print(f"int {B.static}") # get 1 correctly
A.static = 5
print(f"int {A.static}") # get 5 correctly
print(f"int {B.static}") # get 5 correctly
B.static = 6
print(f"int {A.static}") # expected 6, but get 5 incorrectly
print(f"int {B.static}") # get 6 correctly
A.static = 7
print(f"int {A.static}") # get 7 correctly
print(f"int {B.static}") # get unchanged 6
Solution based on refdatatypes library:
from refdatatypes.refint import RefInt
class AAA:
static = RefInt(1)
class BBB(AAA):
pass
print(f"refint {AAA.static.value}") # get 1 correctly
print(f"refint {BBB.static.value}") # get 1 correctly
AAA.static.value = 5
print(f"refint {AAA.static.value}") # get 5 correctly
print(f"refint {BBB.static.value}") # get 5 correctly
BBB.static.value = 6
print(f"refint {AAA.static.value}") # get 6 correctly
print(f"refint {BBB.static.value}") # get 6 correctly
AAA.static.value = 7
print(f"refint {AAA.static.value}") # get 7 correctly
print(f"refint {BBB.static.value}") # get 7 correctly
Absolutely Yes, Python by itself don't have any static data member explicitly, but We can have by doing so
class A:
counter =0
def callme (self):
A.counter +=1
def getcount (self):
return self.counter
>>> x=A()
>>> y=A()
>>> print(x.getcount())
>>> print(y.getcount())
>>> x.callme()
>>> print(x.getcount())
>>> print(y.getcount())
output
0
0
1
1
explanation
here object (x) alone increment the counter variable
from 0 to 1 by not object y. But result it as "static counter"
The best way I found is to use another class. You can create an object and then use it on other objects.
class staticFlag:
def __init__(self):
self.__success = False
def isSuccess(self):
return self.__success
def succeed(self):
self.__success = True
class tryIt:
def __init__(self, staticFlag):
self.isSuccess = staticFlag.isSuccess
self.succeed = staticFlag.succeed
tryArr = []
flag = staticFlag()
for i in range(10):
tryArr.append(tryIt(flag))
if i == 5:
tryArr[i].succeed()
print tryArr[i].isSuccess()
With the example above, I made a class named staticFlag
.
This class should present the static var __success
(Private Static Var).
tryIt
class represented the regular class we need to use.
Now I made an object for one flag (staticFlag
). This flag will be sent as reference to all the regular objects.
All these objects are being added to the list tryArr
.
This Script Results:
False
False
False
False
False
True
True
True
True
True
To avoid any potential confusion, I would like to contrast static variables and immutable objects.
Some primitive object types like integers, floats, strings, and touples are immutable in Python. This means that the object that is referred to by a given name cannot change if it is of one of the aforementioned object types. The name can be reassigned to a different object, but the object itself may not be changed.
Making a variable static takes this a step further by disallowing the variable name to point to any object but that to which it currently points. (Note: this is a general software concept and not specific to Python; please see others' posts for information about implementing statics in Python).
Summarizing others' answers and adding, there are many ways to declare Static Methods or Variables in python.
1. Using staticmethod() as a decorator:
One can simply put a decorator above a method(function) declared to make it a static method. For eg.
class Calculator:
@staticmethod
def multiply(n1, n2, *args):
Res = 1
for num in args: Res *= num
return n1 * n2 * Res
print(Calculator.multiply(1, 2, 3, 4)) # 24
2. Using staticmethod() as a parameter function:
This method can receive an argument which is of function type, and it returns a static version of the function passed. For eg.
class Calculator:
def add(n1, n2, *args):
return n1 + n2 + sum(args)
Calculator.add = staticmethod(Calculator.add)
print(Calculator.add(1, 2, 3, 4)) # 10
3. Using classmethod() as a decorator:
@classmethod has similar effect on a function as @staticmethod has, but this time, an additional argument is needed to be accepted in the function (similar to self parameter for instance variables). For eg.
class Calculator:
num = 0
def __init__(self, digits) -> None:
Calculator.num = int(''.join(digits))
@classmethod
def get_digits(cls, num):
digits = list(str(num))
calc = cls(digits)
return calc.num
print(Calculator.get_digits(314159)) # 314159
4. Using classmethod() as a parameter function:
@classmethod can also be used as a parameter function, in case one doesn't want to modify class definition. For eg.
class Calculator:
def divide(cls, n1, n2, *args):
Res = 1
for num in args: Res *= num
return n1 / n2 / Res
Calculator.divide = classmethod(Calculator.divide)
print(Calculator.divide(15, 3, 5)) # 1.0
5. Direct declaration
A method/variable declared outside all other methods, but inside a class is automatically static.
class Calculator:
def subtract(n1, n2, *args):
return n1 - n2 - sum(args)
print(Calculator.subtract(10, 2, 3, 4)) # 1
The whole program
class Calculator:
num = 0
def __init__(self, digits) -> None:
Calculator.num = int(''.join(digits))
@staticmethod
def multiply(n1, n2, *args):
Res = 1
for num in args: Res *= num
return n1 * n2 * Res
def add(n1, n2, *args):
return n1 + n2 + sum(args)
@classmethod
def get_digits(cls, num):
digits = list(str(num))
calc = cls(digits)
return calc.num
def divide(cls, n1, n2, *args):
Res = 1
for num in args: Res *= num
return n1 / n2 / Res
def subtract(n1, n2, *args):
return n1 - n2 - sum(args)
Calculator.add = staticmethod(Calculator.add)
Calculator.divide = classmethod(Calculator.divide)
print(Calculator.multiply(1, 2, 3, 4)) # 24
print(Calculator.add(1, 2, 3, 4)) # 10
print(Calculator.get_digits(314159)) # 314159
print(Calculator.divide(15, 3, 5)) # 1.0
print(Calculator.subtract(10, 2, 3, 4)) # 1
Refer to Python Documentation for mastering OOP in python.
Static Variables in Class factory python3.6
For anyone using a class factory with python3.6 and up use the nonlocal
keyword to add it to the scope / context of the class being created like so:
>>> def SomeFactory(some_var=None):
... class SomeClass(object):
... nonlocal some_var
... def print():
... print(some_var)
... return SomeClass
...
>>> SomeFactory(some_var="hello world").print()
hello world
hasattr(SomeClass, 'x')
is False
. i doubt this is what anyone means by a static variable at all.
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.
some_var
above isn't a class member at all. In Python all class members can be accessed from outside the class.
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.
So this is probably a hack, but I've been using eval(str)
to obtain an static object, kind of a contradiction, in python 3.
There is an Records.py file that has nothing but class
objects defined with static methods and constructors that save some arguments. Then from another .py file I import Records
but i need to dynamically select each object and then instantiate it on demand according to the type of data being read in.
So where object_name = 'RecordOne'
or the class name, I call cur_type = eval(object_name)
and then to instantiate it you do cur_inst = cur_type(args)
However before you instantiate you can call static methods from cur_type.getName()
for example, kind of like abstract base class implementation or whatever the goal is. However in the backend, it's probably instantiated in python and is not truly static, because eval is returning an object....which must have been instantiated....that gives static like behavior.
You can use a list or a dictionary to get "static behavior" between instances.
class Fud:
class_vars = {'origin_open':False}
def __init__(self, origin = True):
self.origin = origin
self.opened = True
if origin:
self.class_vars['origin_open'] = True
def make_another_fud(self):
''' Generating another Fud() from the origin instance '''
return Fud(False)
def close(self):
self.opened = False
if self.origin:
self.class_vars['origin_open'] = False
fud1 = Fud()
fud2 = fud1.make_another_fud()
print (f"is this the original fud: {fud2.origin}")
print (f"is the original fud open: {fud2.class_vars['origin_open']}")
# is this the original fud: False
# is the original fud open: True
fud1.close()
print (f"is the original fud open: {fud2.class_vars['origin_open']}")
# is the original fud open: False
If you are attempting to share a static variable for, by example, increasing it across other instances, something like this script works fine:
# -*- coding: utf-8 -*-
class Worker:
id = 1
def __init__(self):
self.name = ''
self.document = ''
self.id = Worker.id
Worker.id += 1
def __str__(self):
return u"{}.- {} {}".format(self.id, self.name, self.document).encode('utf8')
class Workers:
def __init__(self):
self.list = []
def add(self, name, doc):
worker = Worker()
worker.name = name
worker.document = doc
self.list.append(worker)
if __name__ == "__main__":
workers = Workers()
for item in (('Fiona', '0009898'), ('Maria', '66328191'), ("Sandra", '2342184'), ('Elvira', '425872')):
workers.add(item[0], item[1])
for worker in workers.list:
print(worker)
print("next id: %i" % Worker.id)
Put it this way the static variable is created when a user-defined a class come into existence and the define a static variable it should follow the keyword self,
class Student:
the correct way of static declaration
i = 10
incorrect
self.i = 10
Not like the @staticmethod
but class variables are static method of class and are shared with all the instances.
Now you can access it like
instance = MyClass()
print(instance.i)
or
print(MyClass.i)
you have to assign the value to these variables
I was trying
class MyClass:
i: str
and assigning the value in one method call, in that case it will not work and will throw an error
i is not attribute of MyClass
Class variable and allow for subclassing
Assuming you are not looking for a truly static variable but rather something pythonic that will do the same sort of job for consenting adults, then use a class variable. This will provide you with a variable which all instances can access (and update)
Beware: Many of the other answers which use a class variable will break subclassing. You should avoid referencing the class directly by name.
from contextlib import contextmanager
class Sheldon(object):
foo = 73
def __init__(self, n):
self.n = n
def times(self):
cls = self.__class__
return cls.foo * self.n
#self.foo * self.n would give the same result here but is less readable
# it will also create a local variable which will make it easier to break your code
def updatefoo(self):
cls = self.__class__
cls.foo *= self.n
#self.foo *= self.n will not work here
# assignment will try to create a instance variable foo
@classmethod
@contextmanager
def reset_after_test(cls):
originalfoo = cls.foo
yield
cls.foo = originalfoo
#if you don't do this then running a full test suite will fail
#updates to foo in one test will be kept for later tests
will give you the same functionality as using Sheldon.foo
to address the variable and will pass tests like these:
def test_times():
with Sheldon.reset_after_test():
s = Sheldon(2)
assert s.times() == 146
def test_update():
with Sheldon.reset_after_test():
s = Sheldon(2)
s.updatefoo()
assert Sheldon.foo == 146
def test_two_instances():
with Sheldon.reset_after_test():
s = Sheldon(2)
s3 = Sheldon(3)
assert s.times() == 146
assert s3.times() == 219
s3.updatefoo()
assert s.times() == 438
It will also allow someone else to simply:
class Douglas(Sheldon):
foo = 42
which will also work:
def test_subclassing():
with Sheldon.reset_after_test(), Douglas.reset_after_test():
s = Sheldon(2)
d = Douglas(2)
assert d.times() == 84
assert s.times() == 146
d.updatefoo()
assert d.times() == 168 #Douglas.Foo was updated
assert s.times() == 146 #Seldon.Foo is still 73
def test_subclassing_reset():
with Sheldon.reset_after_test(), Douglas.reset_after_test():
s = Sheldon(2)
d = Douglas(2)
assert d.times() == 84 #Douglas.foo was reset after the last test
assert s.times() == 146 #and so was Sheldon.foo
For great advice on things to watch out for when creating classes check out Raymond Hettinger's video https://www.youtube.com/watch?v=HTLu2DFOdTg
Success story sharing
@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.const.py
withPI = 3.14
and you can import it everywhere.from const import PI
i = 3
is not a static variable, it is a class attribute, and since it is distinct from an instance-level attributei
it does not behave like a static variable in other languages. See millerdev's answer, Yann's answer, and my answer below.i
(static variable) will be in memory even if I create hundreds of instance of this class ?