I know that we can access class attributes with self
or the class
name.
But I am bit confused why the following also works
class Crazy(object):
VERSION = 1
def __init__(self, version=VERSION):
print version
But this doesn't
class Crazy(object):
VERSION = 1
def __init__(self):
print VERSION
while you can access class attributes using an instance it's not safe to do so. In python, the instance of a class is referred to by the keyword self. Using this keyword you can access not only all instance attributes but also the class attributes.
Attributes of a class can also be accessed using the following built-in methods and functions : getattr() – This function is used to access the attribute of object. hasattr() – This function is used to check if an attribute exist or not. setattr() – This function is used to set an attribute.
self represents the instance of the class. By using the “self” we can access the attributes and methods of the class in python. It binds the attributes with the given arguments. The reason you need to use self. is because Python does not use the @ syntax to refer to instance attributes.
Class methods don't need a class instance. They can't access the instance ( self ) but they have access to the class itself via cls . Static methods don't have access to cls or self .
A class definition, i.e. the block inside class ...:
, is evaluated like any regular Python code block. Just at the end of the class
block, every local name which was defined inside that block becomes part of the class' __dict__
. The class
syntax is more or less just syntactic sugar over:
Crazy = type('Crazy', (object,), {'VERSION': 1, ...})
See https://docs.python.org/3/library/functions.html#type.
Given this, you'd expect this to work, right?
VERSION = 1
def foo(bar=VERSION):
print(bar)
(Also see this for more explanation on its behaviour.)
Inside a class
block this works exactly the same way, with the only special behaviour that you're not creating global names, but names which will become the class' __dict__
.
The relevant paragraph in the documentation is here:
The class’s suite is then executed in a new execution frame (see Naming and binding), using a newly created local namespace and the original global namespace. (Usually, the suite contains mostly function definitions.) When the class’s suite finishes execution, its execution frame is discarded but its local namespace is saved. A class object is then created using the inheritance list for the base classes and the saved local namespace for the attribute dictionary. The class name is bound to this class object in the original local namespace.
https://docs.python.org/3/reference/compound_stmts.html#class-definitions
After the class is defined though, that implicit namespace doesn't exist anymore, so this doesn't work:
def __init__(self):
print(VERSION)
The scoping rules follow the regular lookup chain:
None of these are true, since VERSION
is just an attribute of Crazy
at this point, so is only accessible as Crazy.VERSION
or self.VERSION
, the latter of which actually also doesn't exist and falls back onto its own lookup chain and traverses up to Crazy.VERSION
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With