Suppose I have a class like this:
class Hola(object):
NOMBRE = 'hola'
def muestro_cosas(self):
print('Mi nombre es {}'.format(Hola.NOMBRE))
class HolaPequenito(Hola):
NOMBRE = 'hola_pequenito'
...
As you can see, it HolaPequenito
is a subclass of Hola
.
Now, I do an implementation of things where I need to use the class variable NOMBRE
.
- If I have an instance of
Hola
, I will doprint (Hola.NOMBRE)
. - If I have an instance of
HolaPequenito
, I will doprint (HolaPequenito.NOMBRE)
.
However, there are times when I don't know if I will be instantiating Hola
or HolaPequenito
, because I instantiate them dynamically within a large process, in which I need to know the value of NOMBRE
the class that has been instantiated and do something like:
class Hola(object):
NOMBRE = 'hola'
def comprueba_cosas(self):
if NOMBRE == 'hola': # aquí debo usar la variable de clase
...
elif NOMBRE == 'hola_pequenito':
...
That is to say: if I instantiate Hola
or HolaPequenito
without knowing which of the two I am instantiating, how can I access the NOMBRE
respective class variable to do some heuristics?
The best I got was to define a class method that returns it to me :
class Hola(object):
NOMBRE = 'hola'
@classmethod
def bah(cls):
return cls.NOMBRE
But I don't know how to combine it to interact with the class variable NOMBRE
inside a method.
The class attribute can be accessed from the reference to an instance (
self
in this case) in several ways:Using
type
:which allows us to get the reference to the class (
type object
) using the reference of an instance (self
).Using the descriptor
__class__
directly:Accessing using
__dict__
is generally considered "non-pythonic" , so usingtype
is considered the appropriate method. This is common to other "magic" attributes such as__len__
, which are semantically considered private and should be accessed through the means provided by the API, such as the buil-tin in these two cases.An exception is the hypothetical case of using Python 2 with old-style classes (not derived from
object
), in which casetype(self)
it doesn't work since it returnsinstance
as type, but it doesself.__dict_
. In Python 3 every class derives by default fromObject
, so this does not happen.Note that
type
it does not always return the same as__class__
, the function's own documentation suggests it:This is because it is perfectly possible to override the
__class_
_ attribute in a derived class. This typically occurs, by its very nature, with proxy objects, without going any furtherweakref.proxy
than the stdlib:So there are certain cases (besides old-style classes) where using
__class__
directly insteadtype
is either the solution or a very bad idea depending on the case.Using a class method as a "getter" or "setter" as you expose is also a possibility.
It is obviously sensitive to possible overrides or overlap with an instance method of the same name in future subclasses.
The class attribute can be accessed using simply
self.attr
. This is so, because Python first looks within the instance attributes, and if nothing is found, it looks within the class attributes.The risk is that if at some point a new instance attribute with the same name (
self.attr = algo
) is defined,self.attr
it will never refer to the class attribute again, but to the instance attribute. There are times when this behavior can be of interest, but if we don't want it, I think it's better to be explicit, as the zen of Python suggests :), and access the class attribute by a reference to the class and not by the instance.