Метаморфозы атрибутов класса

Короткая заметка из серии «Вас предупреждали»
Переход с классических языков программирования на Питон доставляет немало сюрпризов.
Читаем документацию:

Generally speaking, instance variables are for data unique to each instance and class variables are for attributes and methods shared by all instances of the class

Попробуем поиграться

class Vessel:     #class attribute     vtype = "boat"      #instance attribute     def __init__(self, name):         self.name = name 


Создаем два объекта проверим значения всех атрибутов:

Iowa = Vessel("Iowa") Drum=Vessel("Drum") printAttr(Iowa, Drum)  >>name=Iowa          	vtype=boat          	__class__.vtype=boat          	 >>name=Drum          	vtype=boat          	__class__.vtype=boat  

Пока все как и ожидалось.
Попытаемся изменить vtype: это можно сделать двумя способами, которые по сути просто разный синтаксис одного и того же

Vessel.vtype = "USS boat" printAttr(Iowa, Drum) >>name=Iowa          	vtype=USS boat      	__class__.vtype=USS boat      	 >>name=Drum          	vtype=USS boat      	__class__.vtype=USS boat      	  Iowa.__class__.vtype = 'USS WW2 Boat' printAttr(Iowa, Drum) >>name=Iowa          	vtype=USS WW2 Boat  	__class__.vtype=USS WW2 Boat  	 >>name=Drum          	vtype=USS WW2 Boat  	__class__.vtype=USS WW2 Boat  	 

И снова все в порядке.
Теперь попытаемся сделать тоже самое через атрибут объекта.

Drum.vtype = 'submarine' printAttr(Iowa, Drum) >>name=Iowa          	vtype=USS WW2 Boat  	__class__.vtype=USS WW2 Boat  	 >>name=Drum          	vtype=submarine     	__class__.vtype=USS WW2 Boat  	 

И вот первая неожиданность: несмотря на то, что vtype это атрибут класса, неожиданно он становится атрибутом объекта.
Проверим:

Vessel.vtype = "NAVY Museum" >>name=Iowa          	vtype=NAVY Museum   	__class__.vtype=NAVY Museum   	 >>name=Drum          	vtype=submarine     	__class__.vtype=NAVY Museum   	 

а что если…

 del Drum.vtype >>name=Iowa          	vtype=NAVY Museum   	__class__.vtype=NAVY Museum   	 >>name=Drum          	vtype=NAVY Museum   	__class__.vtype=NAVY Museum    

И снова атрибут класса.
Следующее выражение уже не проходит

del Drum.vtype printAttr(Iowa, Drum) 	del Drum.vtype 	AttributeError: vtype 

И последний пример, эмулирующий переопределения класса и удаление атрибута vtype.

Drum.vtype = 'submarine' del Vessel.vtype printAttr(Iowa, Drum)  >>name=Iowa          	 >>name=Drum          	vtype=submarine     	 

Если начать разбираться с namespace-ами, то подобное поведение становится понятным.
Однако для программистов, кто раньше работал с нормальными языками, это по меньшей мере кажется странным. А если говорить о больших проектах, которые поддерживаются несколькими поколениями разработчиков, это может оказаться провалом сроков и пр.
Принимая во внимание концепцию Питона, что все открыто для всех, почему бы не сделать доступ к «классным» атрибутам только через __class__ или его аналог. На мой взгляд, это бы хоть как-то оградило от сюрпризов и заставило 10 раз подумать прежде чем присваивать что-то классным атрибутам на уровне объектов.


ссылка на оригинал статьи https://habr.com/post/427065/

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *