Static Class Variables and Methods in Python

Static class variables and methods in Python

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.

How can static method access class variable in Python?

You can access it as InviteManager.INVITE_MESSAGE, but a cleaner solution is to change the static method to a class method:

@classmethod
@missing_input_not_allowed
def invite(cls, email):
return cls.INVITE_MESSAGE

(Or, if your code is really as simple as it looks, you can replace the whole class with a bunch of functions and constants in a module. Modules are namespaces.)

How do I use a static variable inside a class in Python

There are two ways to access a class attribute: you can either access it directly on a class, or you can read it through self (but not rebind it). Accessing a class attribute through self won't work if there is already a value set directly on the instance so you would normally try to use the class to access a class attribute.

class Cls:
counter = 0
def __init__(self, name):
self.name = name
Cls.counter += 1
def count(self):
return Cls.counter

When you write self.counter += 1 this is a shorthand for self.counter = self.counter + 1 and as with any other binding through self it sets an instance attribute.

This can be useful if you want a default value for instance attributes, you can set them as class attributes and then just update them in the instances which want different values, but to avoid confusion you probably want to avoid using self at all when accessing class attributes.

You can also consider making the count method into a class method and moving the increment into another method:

@classmethod
def increment(cls):
cls.counter += 1

@classmethod
def count(cls):
return cls.counter

if you do that then each subclass will have its own independent counter. That may or may not be what you want here. The cls parameter here is the class that was actually instantiated, this can be useful if you can a whole class hierarchy, or even just a base class CountsInstances where you can put this code once and reuse it with multiple independent counters.

Decorating each function with @staticmethod will give you something close to the Java code:

class Cls:
counter = 0
def __init__(self, name):
self.name = name
self.increment()

@staticmethod
def increment():
Cls.counter += 1

@staticmethod
def count():
return Cls.counter

Static variables in python classes

Assignment to an instance attribute normally sets an instance attribute. Once there is an instance attribute, it masks the class attribute.

So before you executed instance.i=13, there was no i attribute on the instance, only on the class. You then bound the name i on the instance to 13, and the next time you look up instance.i that attribute is found, and no attempt is made to find my_class.i anymore.

But manipulating a mutable object is not the same thing as assigning to a class or instance attribute. You did not assign to instance.i, you altered the list object referenced by my_class.i and visible through instance.i. instance.i still will find the my_class.i attribute, you never used = to create the instance.i attribute.

That's because you only ever read the instance.i reference to the list, in order to print it, and to find the list.append() method. At no point do you set a new value for the instance.i attribute reference.

The list object is it's own object, one that you can alter by adding or removing or replacing the values referenced by the indices of the list. It doesn't matter what names or attributes reference that list, you can have any number of such references to the same list, and altering the list won't change those references.

Try creating more references to the list, and see what happens:

>>> list_named_i = instance.i
>>> list_named_i
[13]
>>> my_class.i.append(42)
>>> list_named_i
[13, 42]
>>> list_named_i[0] = 81
>>> instance.i
[81, 42]

instance.i, my_class.i and list_named_i are all just different references to the same list object, and you can modify (mutate) that list object via any of those references.

I recommend you read up on how Python names and attributes and lists and such work; see Facts and myths about Python names and values by Ned Batchelder.

What is the Python equivalent of static variables inside a function?

A bit reversed, but this should work:

def foo():
foo.counter += 1
print "Counter is %d" % foo.counter
foo.counter = 0

If you want the counter initialization code at the top instead of the bottom, you can create a decorator:

def static_vars(**kwargs):
def decorate(func):
for k in kwargs:
setattr(func, k, kwargs[k])
return func
return decorate

Then use the code like this:

@static_vars(counter=0)
def foo():
foo.counter += 1
print "Counter is %d" % foo.counter

It'll still require you to use the foo. prefix, unfortunately.

(Credit: @ony)

python class variable in static method

If the attributes are going to be static, don't initialize them in the initializer method, declare them outside at the class level, not at method level.

But why are you initializing class attributes in the initializer? every instance that you create will overwrite their values!

I believe you're confusing what instance attributes and class attributes are used for. Why don't you try using only instance attributes? all things considered, having static data is not a good idea. For example:

class MyConnection:
def __init__(self, hostname, port, user, password):
self.myhostname = hostname
self.myport = port
self.myuser = user
self.mypassword = password
@staticmethod
def connect():
my_session = MyConnection()
print my_session.myuser # just an example

How to initialize a class variable with a static method?

Your question is very similar to one I once asked titled Calling class staticmethod within the class body?. @DeepSpace's comment about how a class not existing during class definition time is the reason why.

Here's how to adapt the accepted answer to my question to your own situation (to define the class attribute within the class definition itself):

class A:
def __init__(self):
self.y = A.initY()

@staticmethod
def initX():
return 'X'

@staticmethod
def initY():
return 'Y'

x = initX.__func__() # Define class attribute.


print(A.x) # -> X

As @Klaus D. commented, another way to do it is after the class is defined (outside the class body).

You don't encounter the problem initializing the instance attribute of Y because it occurs within a method of an instance of the class (so the class is fully defined at that point).

How to declare a static attribute in Python?

All variables defined on the class level in Python are considered static

class Example:
Variable = 2 # static variable

print Example.Variable # prints 2 (static variable)

# Access through an instance
instance = Example()
print instance.Variable # still 2 (ordinary variable)


# Change within an instance
instance.Variable = 3 #(ordinary variable)
print instance.Variable # 3 (ordinary variable)
print Example.Variable # 2 (static variable)


# Change through Class
Example.Variable = 5 #(static variable)
print instance.Variable # 3 (ordinary variable)
print Example.Variable # 5 (static variable)

You can have two different variables in your class under the same name (one static and one ordinary).
Don't be confused.



Related Topics



Leave a reply



Submit