
Notes on the Python Object System Part 1
A few notes on the python object system. Designed for those who already know how to program in python. It is only about new classes (new-style classes) in python 2.3 and higher. This article describes what objects are and how attributes are searched.
All data in python are objects. Each object has 2 special attributes __class__ and __dict__.
The value of a.name remains the same, i.e. __init__ was not called when changing the class. Access to class variables and methods of the “past” class A disappeared: But class variables and methods of class B accesses: Working with object attributes: setting, deleting and searching is equivalent to calling the built-in functions settattr, delattr, getattr: ax = 1 <== > setattr (a, 'x', 1) del ax <==> delattr (a, 'x') ax <==> getattr (a, 'x') It should be understood that setattr and delattr affect they change only the object itself (more precisely, a .__ dict__), and do not change the class of the object. qux - is a class variable, i.e. it “belongs” to class B, and not to object a:
If we try to remove this attribute, we get an error, because delattr will try to remove the attribute from a .__ dict__ Next, if we try to change (set) the attribute, setattr will put it in __dict__ specific to this particular object. Well, since there is a 'qux' in an __dict__ object, it can be deleted using delattr: After deleting, a.qux will return the value of the class variable: So:
Classes are objects, and they also have special attributes __class__ and __dict__. The class has a type type. True __dict__ the classes are not quite a dictionary But __dict__ is responsible for accessing the internal namespace, which stores methods, descriptors, variables, properties and more: In the classes, in addition to __class__ and __dict__, there are several more special attributes: __bases__ - list of direct parents, __name__ Is the name of the class. [1]
Classes can be considered some kind of extensions of ordinary objects that implement a type interface. The set of all classes (or types) belong to the set of all objects, or rather, is a subset of it. In other words, any class is an object, but not every object is a class. We agree to call regular objects those objects that are not classes.
A small demonstration that will become better understood a bit later.
The class is an object. A number is also an object. A class is a class (i.e. type). But the number is not a class (type). (What type will be explained later) Well, a is also an ordinary object. And A has only one direct parent class - object. Some of the special parameters can even be changed:
Using getattr we get access to the class attributes:
In a first approximation, the search algorithm looks like this: first it is searched in the __dict__ of the object, then it searches the __dict__ dictionaries of the class of the object (which is determined using __class__) and __dict__ of its base classes in recursive order.
Example. Because in ordinary objects a and b there is no 'qux' attribute in __dict__, then the search continues in the internal dictionary __dict__ of their type (class), and then on __dict__ parent dictionaries in a certain order: Change the qux attribute of class A. And accordingly, the values should change, that return instances of class A - a and b: Similarly, in runtime, you can add a method to the class: And access to it will appear in the instances:
Just like with any other objects, you can remove the class attribute, for example, the qux class variable: It will be removed from __dict__ And access will be lost for instances. Classes have almost the same attribute search as ordinary objects, but there are differences: the search starts with our own __dict__ dictionary, and then we search the __dict__ dictionaries of superclasses (which are stored in __bases__) by a specific algorithm, and then by the class in __class__ and his superclasses. (More on this later).
[1] For the sake of simplicity, let us forget about __module__ and __doc__. The full list of class attributes can be found in the documentation.
Notes on the Python Object System Part 2
Notes on the Python Object System Part 3
The objects
All data in python are objects. Each object has 2 special attributes __class__ and __dict__.
- __class__ - defines the class or type whose instance is an object. A type (or class of an object) determines its behavior; all objects, including built-in ones, have it. Type and class are different names for the same thing. x .__ class__ <==> type (x).
- __dict__ is a dictionary that gives access to the internal namespace, almost all objects have it, many built-in types do not.
>>> def foo(): pass
...
>>> foo.__class__
>>> foo.__dict__
{}
>>> (42).__dict__
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'int' object has no attribute '__dict__'
>>> (42).__class__
>>> class A(object):
... qux = 'A'
... def __init__(self, name):
... self.name=name
... def foo(self):
... print 'foo'
...
>>> a = A('a')
>>> a.__dict__ {'name': 'a'}
>>> a.__class__
>>> type(a)
>>> a.__class__ is type(a)
True
>>> a.__class__ is type(a) is A
True
>>> class B(object):
... qux = 'B'
... def __init__(self):
... self.name = 'B object'
... def bar(self):
... print 'bar'
...
>>> a.__dict__
{'name': 'a'}
>>> a.foo()
foo
>>> a.__class__
>>> a.__class__ = B
>>> a.__class__
The value of a.name remains the same, i.e. __init__ was not called when changing the class. Access to class variables and methods of the “past” class A disappeared: But class variables and methods of class B accesses: Working with object attributes: setting, deleting and searching is equivalent to calling the built-in functions settattr, delattr, getattr: ax = 1 <== > setattr (a, 'x', 1) del ax <==> delattr (a, 'x') ax <==> getattr (a, 'x') It should be understood that setattr and delattr affect they change only the object itself (more precisely, a .__ dict__), and do not change the class of the object. qux - is a class variable, i.e. it “belongs” to class B, and not to object a:
>>> a.__dict__
{'name': 'a'}
>>> a.foo()
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'B' object has no attribute 'foo'
>>> a.bar()
bar
>>> a.qux
'B'
>>> a.qux
'B'
>>> a.__dict__
{'name': 'a'}
If we try to remove this attribute, we get an error, because delattr will try to remove the attribute from a .__ dict__ Next, if we try to change (set) the attribute, setattr will put it in __dict__ specific to this particular object. Well, since there is a 'qux' in an __dict__ object, it can be deleted using delattr: After deleting, a.qux will return the value of the class variable: So:
>>> delattr(a, 'qux')
Traceback (most recent call last):
File "", line 1, in
AttributeError: qux
>>> del a.qux
Traceback (most recent call last):
File "", line 1, in
AttributeError: qux
>>> a.qux
'B'
>>>
>>> b = B()
>>> b.qux
'B'
>>> a.qux = 'myB'
>>> a.qux
'myB'
>>> a.__dict__
{'qux': 'myB', 'name': 'a'}
>>> b.qux
'B'
>>>
>>> del a.qux
>>> a.qux
'B'
>>> a.__dict__
{'name': 'a'}
- the class for the object is the value of the special attribute __class__ and it can be changed. (Although the official documentation says that there are no guarantees, but in fact it is possible)
- almost every object has its own namespace (attributes), access (not always full), which is carried out using the special attribute __dict__
- the class actually only affects the search for attributes that are not in __dict__, such as class methods, descriptors, magic methods, class variables, and more.
Objects and Classes
Classes are objects, and they also have special attributes __class__ and __dict__. The class has a type type. True __dict__ the classes are not quite a dictionary But __dict__ is responsible for accessing the internal namespace, which stores methods, descriptors, variables, properties and more: In the classes, in addition to __class__ and __dict__, there are several more special attributes: __bases__ - list of direct parents, __name__ Is the name of the class. [1]
>>> class A(object):
... pass
...
>>> A.__class__
>>> A.__dict__
>>> dict(A.__dict__)
{'__module__': '__main__', 'qux': 'A', '__dict__': , 'foo': , '__weakref__': , '__doc__': None}
>>> A.__dict__.keys()
['__module__', 'qux', '__dict__', 'foo', '__weakref__', '__doc__']<
Classes can be considered some kind of extensions of ordinary objects that implement a type interface. The set of all classes (or types) belong to the set of all objects, or rather, is a subset of it. In other words, any class is an object, but not every object is a class. We agree to call regular objects those objects that are not classes.
A small demonstration that will become better understood a bit later.
The class is an object. A number is also an object. A class is a class (i.e. type). But the number is not a class (type). (What type will be explained later) Well, a is also an ordinary object. And A has only one direct parent class - object. Some of the special parameters can even be changed:
>>> class A(object):
... pass
...
>>> isinstance(A, object)
True
>>> isinstance(42, object)
True
>>> isinstance(A, type)
True
>>> isinstance(42, type)
False
>>>
>>> a = A()
>>> isinstance(a, A)
True
>>> isinstance(a, object)
True
>>> isinstance(a, type)
False
>>> A.__bases__
(,)
>>> A.__name__
'A'
>>> A.__name__ = 'B'
>>> A
Using getattr we get access to the class attributes:
>>> A.qux
'A'
>>> A.foo
>>>
Search for attributes in a regular object
In a first approximation, the search algorithm looks like this: first it is searched in the __dict__ of the object, then it searches the __dict__ dictionaries of the class of the object (which is determined using __class__) and __dict__ of its base classes in recursive order.
Example. Because in ordinary objects a and b there is no 'qux' attribute in __dict__, then the search continues in the internal dictionary __dict__ of their type (class), and then on __dict__ parent dictionaries in a certain order: Change the qux attribute of class A. And accordingly, the values should change, that return instances of class A - a and b: Similarly, in runtime, you can add a method to the class: And access to it will appear in the instances:
>>> class A(object):
... qux = 'A'
... def __init__(self, name):
... self.name=name
... def foo(self):
... print 'foo'
...
>>> a = A()
>>> b = A()
>>> b.qux
'A'
>>> A.qux
'A'
>>> A.qux='B'
>>> a.qux
'B'
>>> b.qux
'B'
>>>
>>> A.quux = lambda self: 'i have quux method'
>>> A.__dict__['quux']
at 0x7f7797a25b90>
>>> A.quux
>
>>> a.quux()
'i have quux method'
Just like with any other objects, you can remove the class attribute, for example, the qux class variable: It will be removed from __dict__ And access will be lost for instances. Classes have almost the same attribute search as ordinary objects, but there are differences: the search starts with our own __dict__ dictionary, and then we search the __dict__ dictionaries of superclasses (which are stored in __bases__) by a specific algorithm, and then by the class in __class__ and his superclasses. (More on this later).
>>> del A.qux
>>> A.__dict__['qux']
Traceback (most recent call last):
File "", line 1, in
KeyError: 'qux'
>>> a.qux
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'A' object has no attribute 'qux'
>>>
Links
- Unifying types and classes in Python is the main document explaining what, how, and why in new classes.
- Making Types Look More Like Classes - PEP 252, which describes the difference between old classes and new ones.
- Built-in functions - a detailed description of the operation of all built-in functions.
- Data model - a detailed description of the python data model.
- Python types and objects - an explanation of the python object model using simple examples with pictures.
Notes
[1] For the sake of simplicity, let us forget about __module__ and __doc__. The full list of class attributes can be found in the documentation.
Read more
Notes on the Python Object System Part 2
Notes on the Python Object System Part 3