Форум сайта python.su
Позволю поднять эту довольно избитую тему, так как несмотря на поиски и чтение соответствующей документации в Интернете, мое понимание данного вопроса до конца не оформилось.
Итак, вопрос в следующем: есть ли в Python статические аттрибуты классов в том понимании этого термина, которое выработалось в мире C++ и Java?
Предположим, нам необходим статический аттрибут для подсчета количества созданных экземпляров некоторого класса. Что мы делаем в Python (для чистоты буду использовать new-style ООП, хотя в случае с классическим ООП, ситуация, думаю, не изменится):
class C(object):
counter = 0 # вот это “по идее” статический аттрибут
def __init__(self):
C.counter += 1 # во время инициализации нового экземпляра
# увеличиваем общий для всех экземпляров счетчик на 1-цу
Смотрим что получилось:
>>> inst1 = C()
>>> C.counter
1
>>> inst2 = C()
>>> C.counter
2
Все работает как надо, и, казалось бы, counter - то что нам нужно. Но тут наступает то, что не увязывается с концепцией статического аттрибута. Дело в том, что помимо аттрибута counter класса C, создаются аттрибуты counter экземпляров класса C, для каждого экземпляра в отдельности:
>>> inst1.counter
2
>>> inst2.counter
2
которые изначально ссылаются на тот же объект int, что и аттрибут C.counter:
>>> inst1.counter is C.counter
True
>>> inst2.counter is C.counter
True
Но стоит поработать с аттрибутом counter какого-то экземпляра в отдельности, его связь с аттрибутом counter класса C исчезает, что и понятно:
>>> inst1.counter = 5
>>> C.counter
2
>>> inst1.counter is C.counter
False
Это совсем не та семантика статических аттрибутов данных, которая принята в C++ и в Java. Мне не нужны аттрибуты экземпляра, которые создаются для каждого объявленного в теле класса “статического” аттрибута. Это лишь захламляет память (на каждый аттрибут counter экземлпяров класса C нужно выделять указатель), да и противоречит самому понятию статический аттрибут - он должен быть в единственном экземпляре.
То есть, описанный выше механизм лишь отчасти реализует концепцию статических аттрибутов в Python. Вопрос: есть ли альтернативный механизм, который в точности соответствует принятым понятиям в C++ или Java?
Буду благодарен любым ссылкам, где освещается этот вопрос.
Офлайн
KolyanНу никто тебе и не обещал, что это будет статический атрибут.
То есть, описанный выше механизм лишь отчасти реализует концепцию статических аттрибутов в Python. Вопрос: есть ли альтернативный механизм, который в точности соответствует принятым понятиям в C++ или Java?
Офлайн
возможно property как-то поможет, но не уверен.
в общем случае in-place changing будет работать, если изменять не сам атрибут, а косвенно элементы списка или словаря.
но это на самом деле криво.
как всегда вопрос: а зачем?
Офлайн
property поможет наверняка. Только в нем вместо self.attr следует использовать self.__class__.attr - и будет полная иллюзия статической переменной. Можно написать специализированный дескриптор вместо property (довольно слабо использующийся сейчас подход, но он интенсивно набирает обороты). Дел-то - переопределить __set__ и __get__. __delete__, кажется, не понадобится.
Теперь о главном. Я практически никогда не использую staticmethod. classmethod его отлично перекрывает и дает еще много дополнительных возможностей. staticmethod, по моему убеждению, полезен только в случае биндинга с C++ (мы используем boost.python), поскольку в С++ нет аналога аттрибута класса. А classmethod и аттрибут класса отлично вписываются в наследование (мне это кажется немаловажным).
Нужно четко представлять себе механизм поиска объекта по имени аттрибута. Стандартная документация (http://docs.python.org/ref/attribute-access.html)
__getattribute__, __getattr__, поиск в словаре инстанции, поиск в словаре класса (с специальными случаями, когда в словаре класса находим дескриптор).
Это была бы хорошая тема для отдельной статьи, а подобные лекции я сотрудникам читал много раз (и каждый раз открывался еще один любопытный аспект).
С удовольствием отвечу на более конкретный вопрос, а писать статью кажется, хотел бы, но, похоже, в ближайшем будущем не найду для этой работы времени.
PS. Возможно, я не до конца правильно понимаю функционирование интерпретатора - поправьте меня. Я же все таки не GvR :)
Офлайн
Ну если нужен атрибут класса (а не экземпляра), то и присваивать надо именно ему:
>>> class A(object):
… counter=0
>>> a1=A()
>>> a2=A()
>>> a1.counter
0
>>> a1.__class__.counter
0
>>> a1.__class__.counter=3
>>> a1.counter
3
>>> a2.counter
3
Офлайн
Андрей СветловЕсли я правильно понял вашу идею, вы предлагаете сделать что-то вроде этого:
property поможет наверняка. Только в нем вместо self.attr следует использовать self.__class__.attr - и будет полная иллюзия статической переменной. Можно написать специализированный дескриптор вместо property (довольно слабо использующийся сейчас подход, но он интенсивно набирает обороты). Дел-то - переопределить __set__ и __get__. __delete__, кажется, не понадобится.
Офлайн
KolyanПрошу извинить, это я неправду сказал: эта проблема отпадает, ничего никому не делегируется, я уже разобрался. _counter будет аттрибутом объекта класса C и все обращения к x._counter, где x - некоторый экземпляр класса C, будут приводить к обращению C._counter (по правилу поиска аттрибутов), т.к. в x.__dict__ никакого ключа _counter нет и быть не может, пока мы явно не создадим его, например, так: x._counter = 5.
1. Аттрибут для “внутреннего пользования” _counter все так же будет делегироваться всем экземплярам класса С, и хотя мы его использовать не должны и не будем, на него все так же будет тратиться память, да и захламляться внутренняя область имен экземпляров.
Офлайн
Вопрос bialix'а “как всегда вопрос: а зачем?” на самом деле актуальнее, чем казался сначала.
Если нужно создать счетчик экземпляров, или подобную ему штуку, то предложенные способы вполне подходят.
Если же необходимо сделать “поведение в точности как у C++”… Насколько я понимаю, создатели Питона никогда не ставили перед собой таких целей.
Офлайн
KolyanИз этого следует вывод, что Питон – это не C++ и не Java.
Из всего вышесказанного можно сделать вывод, что для полноценной поддержки статических аттрибутов (членов, полей - в терминах C++ и Java) нужна специфическая языковая семантика и синтаксис, которые сейчас, судя по ответам, в Python отсутствуют.
Офлайн
просто до кучи еще о разнице между Питоном и Си++
http://www.onembedding.com/tools/python/articles/compare2cpp/
Офлайн