- Заметки об объектной системе языка Python ч.1
- Объекты
- Объекты и классы
- Поиск атрибутов в обычном объекте
- Cсылки
- Примечания
- How to Get Class Name in Python?
- What is Class in Python?
- Methods to Get Class Name in Python
- 1) Using __class__.__name__
- 2) Using type() and __name__attribute
- 3) Using nested classes
- Summary
Заметки об объектной системе языка Python ч.1
Несколько заметок об объектной системе python’a. Рассчитаны на тех, кто уже умеет программировать на python. Речь идет только о новых классах (new-style classes) в python 2.3 и выше. В этой статье рассказывается, что такое объекты и как происходит поиск атрибутов.
Объекты
- __class__ — определяет класс или тип, экзмепляром которого является объект. Тип (или класс объекта) определяет его поведение; он есть у всех объектов, в том числе и встроенных. Тип и класс — это разные названия одного и того же. x.__class__ type(x).
- __dict__ словарь, дающий доступ к внутреннему пространству имен, он есть почти у всех объектов, у многих встроенных типов его нет.
>>> 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__ и __class__:
>>> a . __dict__
>>> a . __class__
>>> type (a)
>>> a . __class__ is type (a)
True
Класс и тип — это одно и то же.
>>> a . __class__ is type (a) is A
True
a.__dict__ — это словарь, в котором находятся внутренние (или специфичные для объекта) атрибуты, в данном случае ‘name’. А в a.__class__ класс (тип).
И, например, в методах класса присваивание self.foo = bar практически идентично self.__dict__[‘foo’] = bar или сводится к аналогичному вызову.
В __dict__ объекта нет методов класса, дескрипторов, классовых переменных, свойств, статических методов класса, все они определяются динамически с помощью класса из __class__ атрибута, и являются специфичными именно для класса (типа) объекта, а не для самого объекта.
Пример. Переопределим класс объекта a:
>>> class B ( object ):
. qux = ‘B’
. def __init__ ( self ):
. self . name = ‘B object’
. def bar ( self ):
. print ‘bar’
.
>>> a . __dict__
>>> a . foo()
foo
>>> a . __class__
>>> a . __class__ = B
>>> a . __class__
Значение a.name осталось прежним, т.е. __init__ не вызывался при смене класса.
>>> a . __dict__
Доступ к классовым переменным и методам «прошлого» класса A пропал:
>>> a . foo()
Traceback (most recent call last):
File «», line 1, in
AttributeError: ‘B’ object has no attribute ‘foo’
А вот классовые переменные и методы класса B доступы:
>>> a . bar()
bar
>>> a . qux
‘B’
Работа с атрибутам объекта: установка, удаление и поиск, равносильна вызову встроенных функций settattr, delattr, getattr:
a.x = 1 setattr(a, ‘x’, 1)
del a.x delattr(a, ‘x’)
a.x getattr(a, ‘x’)
При этом стоит стоит понимать, что setattr и delattr влияют и изменяют только сам объект (точнее a.__dict__), и не изменяют класс объекта.
qux — является классовой переменной, т.е. она «принадлежит» классу B, а не объекту a:
>>> a . qux
‘B’
>>> a . __dict__
Если мы попытаемся удалить этот атрибут, то получим ошибку, т.к. delattr будет пытаться удалить атрибут из a.__dict__
>>> 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’
>>>
Далее, если мы попытаемся изменить (установить) атрибут, setattr поместит его в __dict__, специфичный для данного, конкретного объекта.
>>> b = B()
>>> b . qux
‘B’
>>> a . qux = ‘myB’
>>> a . qux
‘myB’
>>> a . __dict__
>>> b . qux
‘B’
>>>
Ну и раз есть ‘qux’ в __dict__ объекта, его можно удалить с помощью delattr:
>>> del a . qux
После удаления, a.qux будет возвращать значение классовой переменной:
>>> a . qux
‘B’
>>> a . __dict__
- класс для объекта — это значение специального атрибута __class__ и его можно менять. (Хотя в официальной документации говорится, что никаких гарантий нет, но на самом деле можно)
- почти каждый объект имеет свое пространство имен (атрибутов), доступ (не всегда полный), к которому осуществляется с помощью специального атрибута __dict__
- класс фактичеки влияет только на поиск атрибутов, которых нет в __dict__, как-то: методы класса, дескрипторы, магические методы, классовые переменные и прочее.
Объекты и классы
Классы — это объекты, и у них тоже есть специальные атрибуты __class__ и __dict__.
>>> class A ( object ):
. pass
.
>>> A . __class__
Правда __dict__ у классов не совсем словарь
>>> A . __dict__
Но __dict__ ответственен за доступ к внутреннему пространству имен, в котором хранятся методы, дескрипторы, переменные, свойства и прочее:
В классах помимо __class__ и __dict__, имеется еще несколько специальных атрибутов: __bases__ — список прямых родителей, __name__ — имя класса. [1]
Классы можно считать эдакими расширениями обычных объектов, которые реализуют интерфейс типа. Множество всех классов (или типов) принадлежат множеству всех объектов, а точнее является его подмножеством. Иначе говоря, любой класс является объектом, но не всякий объект является классом. Договоримся называть обычными объектами(regular objects) те объекты, которые классами не являются.
Небольшая демонстрация, которая станет лучше понятна чуть позже.
Класс является объектом.
>>> class A ( object ):
. pass
.
>>> isinstance (A, object )
True
>>> isinstance ( 42 , object )
True
>>> isinstance (A, type )
True
А вот число классом (типом) не является. (Что такое type будет пояснено позже)
>>> isinstance ( 42 , type )
False
>>>
Ну и a — тоже обычный объект.
>>> a = A()
>>> isinstance (a, A)
True
>>> isinstance (a, object )
True
>>> isinstance (a, type )
False
И у A всего один прямой родительский класс — object.
Часть специальных параметров можно даже менять:
>>> A . __name__
‘A’
>>> A . __name__ = ‘B’
>>> A
С помощью getattr получаем доступ к атрибутам класса:
>>> A . qux
‘A’
>>> A . foo
>>>
Поиск атрибутов в обычном объекте
В первом приближении алгоритм поиска выглядит так: сначала ищется в __dict__ объекта, потом идет поиск по __dict__ словарям класса объекта (который определяется с помощью __class__) и __dict__ его базовых классов в рекурсивном порядке.
>>> class A ( object ):
. qux = ‘A’
. def __init__ ( self , name):
. self . name = name
. def foo ( self ):
. print ‘foo’
.
>>> a = A()
>>> b = A()
Т.к. в обычных объектах a и b нет в __dict__ атрибута ‘qux’, то поиск продолжается во внутреннем словаре __dict__ их типа (класса), а потом по __dict__ словарям родителей в определенном порядке:
>>> b . qux
‘A’
>>> A . qux
‘A’
Меняем атрибут qux у класса A. И соответственно должны поменяться значения, которые возвращают экземпляры класса A — a и b:
>>> 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’
Точно так же как и с любыми другими объектами, можно удалить атрибут класса, например, классовую переменную qux:
>>> del A . qux
Она удалиться из __dict__
>>> 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’
>>>
У классов почти такой же поиск атрибутов, как и у обычных объектов, но есть отличия: поиск начинается с собственного __dict__ словаря, а потом идет поиск по __dict__ словарям суперклассов (которые хранятся в __bases__) по опредленному алгоритму, а затем по классу в __class__ и его суперклассах. (Подробнее об этом позже).
Cсылки
- Unifying types and classes in Python — главный документ, объясняющий что, как и зачем в новых классах.
- Making Types Look More Like Classes — PEP 252, описывающий отличие старых классов от новых.
- Built-in functions — детальное описание работы всех встроенных функций.
- Data model — детальное описание модели данных python’а.
- Python types and objects — объяснение объектной модели python на простых примерах с картинками.
Примечания
[1] О __module__ и __doc__ для простоты изложения пока забудем. Полный список атрибутов класса можно посмотреть в документацииHow to Get Class Name in Python?
Python is well famous to support object-oriented programming including the concepts of classes and objects. It provides a clear program structure and easy modification of code. Since the class is sharable, the code can be reused and also provide different advantages of abstractions, encapsulation, and polymorphism. In this article, we will study the python class and how python get class name of an instance with examples and output. Let’s get started!
What is Class in Python?
Classes are the focal point of OOP and objects are created by Classes. The class can be defined as the description or the definition of the object. The class describes what the object will be but is totally separated from the object itself.
Also, a single class is used to describe multiple objects. For example, we create a blueprint before constructing the house. Similarly, the same blueprint can be used for different houses to be built. The programming works in the flow where first the class is defined which further describes the object. Each class has a name, and its own attribute and behavior.
The method is another term used in classes. Methods are the functions in the classes. They have a specific block of code that can be called and execute a certain task and return the values. The syntax of the class is as given by:
class ClassName: # Statement1 . . . # StatementN
For example:
class Fruit: def __init__(self, name, color): self.name = name self.color = color def func(self): print("Fruit is " + self.name) f1 = Fruit("Apple", "Red") f1.func()
Methods to Get Class Name in Python
Below are 3 methods by which you can get the class name in python:
1) Using __class__.__name__
The first and easiest method to get a class name in python is by using __class__ property which basically refers to the class of the object we wish to retrieve. Here we combine the property with __name__ property to identify the class name of the object or instance. __name__ is the special variable in python that provides the name of the current module where it is used.
Note that to display the class name you have to create the object for that lass and display its name using class.name. Check out the below example for a better understanding of these methods.
For example:
class fruit: def __init__(self, fruit): self.fruit = fruit a = fruit("orange") print (a.__class__) print (a.__class__.__name__)
2) Using type() and __name__attribute
Another method is to use the type() method which is the in-built python method to find the type or the class name of the object. You have to merge the type() function with the __name__ variable and get the name of the class as shown in the below example:
For example:
class fruit: def __init__(self, fruit): self.fruit = fruit a = fruit("orange") print (type(a).__name__)
3) Using nested classes
There are scenarios where you have nested classes in the program and wish to get a class name. In this situation, you can make use of __qualname__ attribute instead of __name__ attribute to get the name of the qualified object.
For example:
class Fruit: def __init__(self, name, b): self.name = name self.vegetable = self.Vegetables(b) class Vegetables: def __init__(self, vegetable): self.vegetable = vegetable fruit = Fruit("orange", ['potatoes']) print(fruit.vegetable.__class__.__name__) print(fruit.vegetable.__class__.__qualname__)
Vegetables Fruit.Vegetables
Summary
Object-oriented programming in python provides multiple advantages such as abstraction, polymorphism, etc. It helps to maintain your code easily and error-free providing the better structure and ability to reuse it. This article represents the various methods by which python get class name easily using __class__, type() and __qualname__ methods. It is recommended to learn and understand this method thoroughly and make your programming easy and efficient.