Latest posts on Еще раз о статических аттрибутах классов topichttps://python.su/forum/topic/827/2007-05-25T16:49:26+03:00Общий :: Python для экспертов :: Еще раз о статических аттрибутах классов
2007-05-25T16:49:26+03:00Андрей Светлов5501Я думаю, неотъемлемая часть парадигмы ООП - инкапсуляция. Которую статические открытые изменяемые поля отлично нарушают. В Питоне предостаточно методов для предоставления staticmethod/classmethod решений. И уж в них-то можно позаботиться о том, чтобы не порвать что-нибудь ненароком. А фасад останется простым и лаконичным. На чтение легко провесить свой дескриптор с одним только __get__, а запись осуществлять через интерфейсные методы.
Общий :: Python для экспертов :: Еще раз о статических аттрибутах классов
2007-05-25T14:28:16+03:00bialix5497<blockquote><em>Striver</em><br/>Вопрос bialix'а “как всегда вопрос: а зачем?” на самом деле актуальнее, чем казался сначала. <br/>Если нужно создать счетчик экземпляров, или подобную ему штуку, то предложенные способы вполне подходят.<br/>Если же необходимо сделать “поведение в точности как у C++”… Насколько я понимаю, создатели Питона никогда не ставили перед собой таких целей.</blockquote>+1
Общий :: Python для экспертов :: Еще раз о статических аттрибутах классов
2007-05-25T14:26:40+03:00bialix5496просто до кучи еще о разнице между Питоном и Си++<br/><a href="http://www.onembedding.com/tools/python/articles/compare2cpp/">http://www.onembedding.com/tools/python/articles/compare2cpp/</a>
Общий :: Python для экспертов :: Еще раз о статических аттрибутах классов
2007-05-25T14:25:07+03:00bialix5495<blockquote><em>Kolyan</em><br/>Из всего вышесказанного можно сделать вывод, что для полноценной поддержки статических аттрибутов (членов, полей - в терминах C++ и Java) нужна специфическая языковая семантика и синтаксис, которые сейчас, судя по ответам, в Python отсутствуют.</blockquote>Из этого следует вывод, что Питон – это не C++ и не Java.<br/>И что каждый язык имеет свои особенности, и писать на Питоне надо как на Питоне, а не как на Яве.<br/><br/><a href="http://dirtsimple.org/2004/12/python-is-not-java.html">http://dirtsimple.org/2004/12/python-is-not-java.html</a><br/><br/>А еще в Ява нету множественного наследования, насколько я помню. От этого факта его объектная модель не страдает?
Общий :: Python для экспертов :: Еще раз о статических аттрибутах классов
2007-05-25T14:22:01+03:00Striver5494Вопрос bialix'а “как всегда вопрос: а зачем?” на самом деле актуальнее, чем казался сначала. <br/>Если нужно создать счетчик экземпляров, или подобную ему штуку, то предложенные способы вполне подходят.<br/>Если же необходимо сделать “поведение в точности как у C++”… Насколько я понимаю, создатели Питона никогда не ставили перед собой таких целей.
Общий :: Python для экспертов :: Еще раз о статических аттрибутах классов
2007-05-25T14:02:14+03:00Kolyan5493<blockquote><em>Kolyan</em><br/>1. Аттрибут для “внутреннего пользования” _counter все так же будет делегироваться всем экземплярам класса С, и хотя мы его использовать не должны и не будем, на него все так же будет тратиться память, да и захламляться внутренняя область имен экземпляров.</blockquote>Прошу извинить, это я неправду сказал: эта проблема отпадает, ничего никому не делегируется, я уже разобрался. _counter будет аттрибутом объекта класса C и все обращения к x._counter, где x - некоторый экземпляр класса C, будут приводить к обращению C._counter (по правилу поиска аттрибутов), т.к. в x.__dict__ никакого ключа _counter нет и быть не может, пока мы явно не создадим его, например, так: x._counter = 5.<br/><br/>Но вторая проблема остается актуальной.
Общий :: Python для экспертов :: Еще раз о статических аттрибутах классов
2007-05-25T12:21:51+03:00Kolyan5492<blockquote><em>Андрей Светлов</em><br/>property поможет наверняка. Только в нем вместо self.attr следует использовать self.__class__.attr - и будет полная иллюзия статической переменной. Можно написать специализированный дескриптор вместо property (довольно слабо использующийся сейчас подход, но он интенсивно набирает обороты). Дел-то - переопределить __set__ и __get__. __delete__, кажется, не понадобится.</blockquote>Если я правильно понял вашу идею, вы предлагаете сделать что-то вроде этого:<br/><br/>class C(object):<br/> _counter = 0<br/> def get_counter(self): return self.__class__._counter<br/> def set_counter(self, val): self.__class__._counter = val<br/> counter = property(get_counter, set_counter)<br/> def __init__(self):<br/> self.counter += 1<br/><br/>Тогда будем иметь:<br/><br/>>>> inst1 = C()<br/>>>> inst2 = C()<br/>>>> inst1.counter<br/>2<br/>>>> inst2.counter<br/>2<br/>>>> inst1.counter = 4<br/>>>> inst2.counter<br/>4<br/><br/>То есть, мы решим проблему несвязанности аттрибутов экземпляров между собой - теперь все аттрибуты x.counter, где x - некоторый экземпляр класса C, - по крайней мере внешне выглядят как один и тот же аттрибут, единый для всех экземпляров, что хоть как-то согласуется с концепцией статических аттрибутов.<br/>Однако останутся другие проблемы, которые сводят на нет все усилия:<br/><br/>1. Аттрибут для “внутреннего пользования” _counter все так же будет делегироваться всем экземплярам класса С, и хотя мы его использовать не должны и не будем, на него все так же будет тратиться память, да и захламляться внутренняя область имен экземпляров.<br/><br/>2. Появится другая проблема. Наш “статический аттрибут” теперь будет являться таковым только, если обращаться к нему через экземпляры класса, а не через сам класс:<br/><br/>>>> inst1.counter<br/>4<br/>>>> C.counter<br/><property object at 0x0163F940><br/><br/>И это очень плохо. Потому как, что такое статический аттрибут (или член, в терминах C++)? Страуструп дает такое определение: "Переменная, которая является частью класса, но <u>не</u> является частью объекта этого класса, называется статическим членом". У нас же чисто внешне все выглядит так, будто counter - это аттрибут экземпляра, а не класса C. В C++ мы также можем обратиться к статическому члену через объект, либо через класс: inst.counter или C::counter, но при этом вторая запись всегда предпочтительнее, ибо подчеркивает саму суть (определение) статического члена. В нашем случае мы лишены возможности такой записи, и поэтому должны использовать лишь первый вариант записи, что может привести к разночтениям: попробуйте сразу разобраться, обращаетесь ли вы к обычному аттрибуту экземпляра, или к статическому - аттрибуту класса - с помощью такой записи: inst.counter. Если вы не писали этот код, вам придется лезть в описание класса.<br/><br/>Из всего вышесказанного можно сделать вывод, что для полноценной поддержки статических аттрибутов (членов, полей - в терминах C++ и Java) нужна специфическая языковая семантика и синтаксис, которые сейчас, судя по ответам, в Python отсутствуют. Это я и хотел узнать. Я думаю, что концепция статических аттрибутов (членов, полей) - это неотъемлемая часть парадигмы ООП, ибо являет собой простое средство моделирования общих (разделяемых) переменных для класса и его экземпляров. Можно попытаться смоделировать разделяемые переменные с помощью других механизмов (как в данном случае - с помощью свойств - properties), но 1. это стоит бОльших усилий и загромождает код ненужными деталями 2. обычно не вписывается полностью в концепцию общих (разделяемых) переменных, как в данном случае.
Общий :: Python для экспертов :: Еще раз о статических аттрибутах классов
2007-05-25T05:47:34+03:00Striver5490Ну если нужен атрибут класса (а не экземпляра), то и присваивать надо именно ему:<br/><br/>>>> class A(object):<br/>… counter=0 <br/>>>> a1=A()<br/>>>> a2=A()<br/>>>> a1.counter<br/>0<br/>>>> a1.__class__.counter<br/>0<br/>>>> a1.__class__.counter=3<br/>>>> a1.counter<br/>3<br/>>>> a2.counter<br/>3<br/>
Общий :: Python для экспертов :: Еще раз о статических аттрибутах классов
2007-05-25T00:25:03+03:00Андрей Светлов5489property поможет наверняка. Только в нем вместо self.attr следует использовать self.__class__.attr - и будет полная иллюзия статической переменной. Можно написать специализированный дескриптор вместо property (довольно слабо использующийся сейчас подход, но он интенсивно набирает обороты). Дел-то - переопределить __set__ и __get__. __delete__, кажется, не понадобится.<br/><br/>Теперь о главном. Я практически никогда не использую staticmethod. classmethod его отлично перекрывает и дает еще много дополнительных возможностей. staticmethod, по моему убеждению, полезен только в случае биндинга с C++ (мы используем boost.python), поскольку в С++ нет аналога аттрибута класса. А classmethod и аттрибут класса отлично вписываются в наследование (мне это кажется немаловажным).<br/><br/>Нужно четко представлять себе механизм поиска объекта по имени аттрибута. Стандартная документация (<a href="http://docs.python.org/ref/attribute-access.html%29">http://docs.python.org/ref/attribute-access.html)</a><br/>__getattribute__, __getattr__, поиск в словаре инстанции, поиск в словаре класса (с специальными случаями, когда в словаре класса находим дескриптор).<br/><br/>Это была бы хорошая тема для отдельной статьи, а подобные лекции я сотрудникам читал много раз (и каждый раз открывался еще один любопытный аспект).<br/>С удовольствием отвечу на более конкретный вопрос, а писать статью кажется, хотел бы, но, похоже, в ближайшем будущем не найду для этой работы времени.<br/><br/>PS. Возможно, я не до конца правильно понимаю функционирование интерпретатора - поправьте меня. Я же все таки не GvR :)
Общий :: Python для экспертов :: Еще раз о статических аттрибутах классов
2007-05-24T20:05:02+03:00bialix5473возможно property как-то поможет, но не уверен.<br/>в общем случае in-place changing будет работать, если изменять не сам атрибут, а косвенно элементы списка или словаря.<br/>но это на самом деле криво.<br/><br/>как всегда вопрос: а зачем?
Общий :: Python для экспертов :: Еще раз о статических аттрибутах классов
2007-05-24T19:57:31+03:00Александр Кошелев5472<blockquote><em>Kolyan</em><br/>То есть, описанный выше механизм лишь отчасти реализует концепцию статических аттрибутов в Python. Вопрос: есть ли альтернативный механизм, который в точности соответствует принятым понятиям в C++ или Java?</blockquote>Ну никто тебе и не обещал, что это будет статический атрибут. <br/>По крайней мере можно сделать статическую функцию, см. staticmethod в документации. Ещё посмотри функцию classmethod
Общий :: Python для экспертов :: Еще раз о статических аттрибутах классов
2007-05-24T19:36:21+03:00Kolyan5471Позволю поднять эту довольно избитую тему, так как несмотря на поиски и чтение соответствующей документации в Интернете, мое понимание данного вопроса до конца не оформилось.<br/><br/>Итак, вопрос в следующем: есть ли в Python статические аттрибуты классов в том понимании этого термина, которое выработалось в мире C++ и Java?<br/><br/>Предположим, нам необходим статический аттрибут для подсчета количества созданных экземпляров некоторого класса. Что мы делаем в Python (для чистоты буду использовать new-style ООП, хотя в случае с классическим ООП, ситуация, думаю, не изменится):<br/><br/>class C(object):<br/> counter = 0 # вот это “по идее” статический аттрибут<br/><br/> def __init__(self):<br/> C.counter += 1 # во время инициализации нового экземпляра <br/> # увеличиваем общий для всех экземпляров счетчик на 1-цу<br/><br/>Смотрим что получилось:<br/><br/>>>> inst1 = C()<br/>>>> C.counter<br/>1<br/>>>> inst2 = C()<br/>>>> C.counter<br/>2<br/><br/>Все работает как надо, и, казалось бы, counter - то что нам нужно. Но тут наступает то, что не увязывается с концепцией статического аттрибута. Дело в том, что помимо аттрибута counter класса C, создаются аттрибуты counter экземпляров класса C, для каждого экземпляра в отдельности:<br/><br/>>>> inst1.counter<br/>2<br/>>>> inst2.counter<br/>2<br/><br/>которые изначально ссылаются на тот же объект int, что и аттрибут C.counter:<br/><br/>>>> inst1.counter is C.counter<br/>True<br/>>>> inst2.counter is C.counter<br/>True<br/><br/>Но стоит поработать с аттрибутом counter какого-то экземпляра в отдельности, его связь с аттрибутом counter класса C исчезает, что и понятно:<br/><br/>>>> inst1.counter = 5<br/>>>> C.counter<br/>2<br/>>>> inst1.counter is C.counter<br/>False<br/><br/>Это совсем не та семантика статических аттрибутов данных, которая принята в C++ и в Java. Мне не нужны аттрибуты экземпляра, которые создаются для каждого объявленного в теле класса “статического” аттрибута. Это лишь захламляет память (на каждый аттрибут counter экземлпяров класса C нужно выделять указатель), да и противоречит самому понятию статический аттрибут - он должен быть в единственном экземпляре.<br/><br/>То есть, описанный выше механизм лишь отчасти реализует концепцию статических аттрибутов в Python. Вопрос: есть ли альтернативный механизм, который в точности соответствует принятым понятиям в C++ или Java?<br/><br/>Буду благодарен любым ссылкам, где освещается этот вопрос.