correct way to define class variables in Python
Neither way is necessarily correct or incorrect, they are just two different kinds of class elements:
- Elements outside the
__init__
method are static elements; they belong to the class. - Elements inside the
__init__
method are elements of the object (self
); they don't belong to the class.
You'll see it more clearly with some code:
class MyClass:
static_elem = 123
def __init__(self):
self.object_elem = 456
c1 = MyClass()
c2 = MyClass()
# Initial values of both elements
>>> print c1.static_elem, c1.object_elem
123 456
>>> print c2.static_elem, c2.object_elem
123 456
# Nothing new so far ...
# Let's try changing the static element
MyClass.static_elem = 999
>>> print c1.static_elem, c1.object_elem
999 456
>>> print c2.static_elem, c2.object_elem
999 456
# Now, let's try changing the object element
c1.object_elem = 888
>>> print c1.static_elem, c1.object_elem
999 888
>>> print c2.static_elem, c2.object_elem
999 456
As you can see, when we changed the class element, it changed for both objects. But, when we changed the object element, the other object remained unchanged.
Class (static) variables and methods
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.
Python, how come we can create class variables that were not defined in class creation?
A class
object is just an instance of yet another type, usually type
(though you can change this using the metaclass
parameter to the class
statement).
Like most other instances, you can add arbitrary instance attributes to a class
object at any time.
Class attributes and instance attributes are wholly separate; the former are stored on the class
object, the latter on instances of the class.
There's nothing particularly special about __init__
; it's just another method that, among other things, can attached new attributes to an object. What is special is that __init__
is called automatically when you create a new instance of the class by calling the class. foo = MyClass(2)
is equivalent to
foo = MyClass.__new__(MyClass, 2)
foo.__init__(2)
The class statement
class MyClass(object):
class_var = 1
def __init__(self, i_var):
self.i_var = i_var
is roughly equivalent to
def my_class_init(self, i_var):
self.i_var = i_var
MyClass = type('MyClass', (object,), {'class_var': 1, '__init__: my_class_init})
The 3-argument form of type
lets you pass a dict
that creates class attributes when you first create the class, but you can always assign attributes after the fact as well:
MyClass = type('MyClass', (object,), {})
MyClass.class_var = 1
MyClass.__init__ = my_class_init
Just to blow your mind a little bit more, the call to type
can be though of as
MyClass = type.__new__(type, 'MyClass', (object,), {...})
MyClass.__init__('MyClass', (object,), {...})
though unless you define a custom metaclass (by subclassing type
), you never have to think about type
itself having __new__
and __init__
methods.
How to properly access and set class variables in a derived class?
Is it because
c.set_formats
uses the class method withcls
being an instance?
Yes, you can check via print calls showing the ids of the involved objects.
Does Python have “private” variables in classes?
It's cultural. In Python, you don't write to other classes' instance or class variables. In Java, nothing prevents you from doing the same if you really want to - after all, you can always edit the source of the class itself to achieve the same effect. Python drops that pretence of security and encourages programmers to be responsible. In practice, this works very nicely.
If you want to emulate private variables for some reason, you can always use the __
prefix from PEP 8. Python mangles the names of variables like __foo
so that they're not easily visible to code outside the namespace that contains them (although you can get around it if you're determined enough, just like you can get around Java's protections if you work at it).
By the same convention, the _
prefix means _variable
should be used internally in the class (or module) only, even if you're not technically prevented from accessing it from somewhere else. You don't play around with another class's variables that look like __foo
or _bar
.
Different ways to declare internal class variables in Python. Which is the best one?
Your first example doesn't work. You can define a static variable like this:
class ApplePie:
type = "apple"
def __init__(self):
print(f"I'm an {ApplePie.type} pie!")
This is a class property (i.e. it's shared among all instances of this class), as opposed to an instance property, accessed through self
, like in your second example. These can differ among multiple instances of a class.
Your third example is
Useful for expensive computed properties of instances that are otherwise effectively immutable.
as described in the official documentation.
Proper way to create class variable in Data Class
To create a class variable, annotate the field as a typing.ClassVar
or not at all.
from typing import ClassVar
from dataclasses import dataclass
@dataclass
class Foo:
ivar: float = 0.5
cvar: ClassVar[float] = 0.5
nvar = 0.5
foo = Foo()
Foo.ivar, Foo.cvar, Foo.nvar = 1, 1, 1
print(Foo().ivar, Foo().cvar, Foo().nvar) # 0.5 1 1
print(foo.ivar, foo.cvar, foo.nvar) # 0.5 1 1
print(Foo(), Foo(12)) # Foo(ivar=0.5) Foo(ivar=12)
There is a subtle difference in that the unannotated field is completely ignored by @dataclass
, whereas the ClassVar
field is stored but not converted to an attribute.
dataclasses
— Data Classes
The member variables [...] are defined using PEP 526 type annotations.
Class variables
One of two places where
dataclass()
actually inspects the type of a
field is to determine if a field is a class variable as defined in PEP
526. It does this by checking if the type of the field istyping.ClassVar
. If a field is aClassVar
, it is excluded from
consideration as a field and is ignored by the dataclass mechanisms.
SuchClassVar
pseudo-fields are not returned by the module-level
fields() function.
How do I access Class member variables?
The answer, in a few words
In your example, itsProblem
is a local variable.
Your must use self
to set and get instance variables. You can set it in the __init__
method. Then your code would be:
class Example(object):
def __init__(self):
self.itsProblem = "problem"
theExample = Example()
print(theExample.itsProblem)
But if you want a true class variable, then use the class name directly:
class Example(object):
itsProblem = "problem"
theExample = Example()
print(theExample.itsProblem)
print (Example.itsProblem)
But be careful with this one, as theExample.itsProblem
is automatically set to be equal to Example.itsProblem
, but is not the same variable at all and can be changed independently.
Some explanations
In Python, variables can be created dynamically. Therefore, you can do the following:
class Example(object):
pass
Example.itsProblem = "problem"
e = Example()
e.itsSecondProblem = "problem"
print Example.itsProblem == e.itsSecondProblem
prints
True
Therefore, that's exactly what you do with the previous examples.
Indeed, in Python we use self
as this
, but it's a bit more than that. self
is the the first argument to any object method because the first argument is always the object reference. This is automatic, whether you call it self
or not.
Which means you can do:
class Example(object):
def __init__(self):
self.itsProblem = "problem"
theExample = Example()
print(theExample.itsProblem)
or:
class Example(object):
def __init__(my_super_self):
my_super_self.itsProblem = "problem"
theExample = Example()
print(theExample.itsProblem)
It's exactly the same. The first argument of ANY object method is the current object, we only call it self
as a convention. And you add just a variable to this object, the same way you would do it from outside.
Now, about the class variables.
When you do:
class Example(object):
itsProblem = "problem"
theExample = Example()
print(theExample.itsProblem)
You'll notice we first set a class variable, then we access an object (instance) variable. We never set this object variable but it works, how is that possible?
Well, Python tries to get first the object variable, but if it can't find it, will give you the class variable. Warning: the class variable is shared among instances, and the object variable is not.
As a conclusion, never use class variables to set default values to object variables. Use __init__
for that.
Eventually, you will learn that Python classes are instances and therefore objects themselves, which gives new insight to understanding the above. Come back and read this again later, once you realize that.
Related Topics
Check List of Words in Another String
Correct Way to Implement a Custom Popup Tkinter Dialog Box
Explicitly Select Items from a List or Tuple
Python - Add Pythonpath During Command Line Module Run
What Can Multiprocessing and Dill Do Together
Extract Subset of Key-Value Pairs from Dictionary
Script Using Multiprocessing Module Does Not Terminate
Getting the SQL from a Django Queryset
String to Dictionary in Python
Why Sum on Lists Is (Sometimes) Faster Than Itertools.Chain
Clicking on Svg Using Selenium Python
Get Raw Post Body in Python Flask Regardless of Content-Type Header
Count Unique Values Using Pandas Groupby
Failed to Catch Syntax Error Python