возможны ли переменные статического класса на python?

<p>возможно ли иметь статические переменные класса или методы в python? какой синтаксис необходим для этого?</p>

<p>переменные, объявленные внутри определения класса, но не внутри метода, являются классом или статическими переменными:</p><pre><code>>>> class myclass: ... i = 3 ... >>> myclass.i 3 </code></pre><p>как указывает @ <a href="https://stackoverflow.com/questions/68645/static-class-variables-in-python#answer-69067">millerdev</a> , это создает переменную <code>i</code> уровня класса, но она отличается от любой переменной <code>i</code> уровня экземпляра, поэтому вы можете иметь</p><pre><code>>>> m = myclass() >>> m.i = 4 >>> myclass.i, m.i >>> (3, 4) </code></pre><p>это отличается от c++ и java, но не так сильно отличается от c #, где к статическому члену нельзя получить доступ, используя ссылку на экземпляр.</p><p>смотрите <a href="https://docs.python.org/2/tutorial/classes.html#class-objects">что учебник python должен сказать о предметах классов и объектов классов</a> .</p><p>@ стив джонсон уже ответил относительно <a href="http://web.archive.org/web/20090214211613/http://pyref.infogami.com/staticmethod">статические методы</a> , также задокументировано в <a href="https://docs.python.org/2/library/functions.html#staticmethod">"встроенные функции" в python справочник по библиотеке</a> .</p><pre><code>class c: @staticmethod def f(arg1, arg2, ...): ... </code></pre><p>@beidy рекомендует <a href="https://docs.python.org/2/library/functions.html#classmethod">classmethod</a> s вместо staticmethod, так как метод затем получает тип класса в качестве первого аргумента, но я все еще немного не уверен в преимуществах этого подхода по сравнению со staticmethod. если вы тоже, то это, вероятно, не имеет значения.</p>

<p>@blair conrad сказал, что статические переменные, объявленные внутри определения класса, но не внутри метода, являются классом или "статическими" переменными:</p><pre><code>>>> class test(object): ... i = 3 ... >>> test.i 3 </code></pre><p>здесь есть несколько ошибок. продолжая из приведенного выше примера:</p><pre><code>>>> t = test() >>> t.i # "static" variable accessed via instance 3 >>> t.i = 5 # but if we assign to the instance ... >>> test.i # we have not changed the "static" variable 3 >>> t.i # we have overwritten test.i on t by creating a new attribute t.i 5 >>> test.i = 6 # to change the "static" variable we do it by assigning to the class >>> t.i 5 >>> test.i 6 >>> u = test() >>> u.i 6 # changes to t do not affect new instances of test # namespaces are one honking great idea -- let's do more of those! >>> test.\_\_dict\_\_ {'i': 6, ...} >>> t.\_\_dict\_\_ {'i': 5} >>> u.\_\_dict\_\_ {} </code></pre><p>обратите внимание, как переменная экземпляра <code>t.i</code> вышла из синхронизации со "статической" переменной класса, когда атрибут <code>i</code> был установлен непосредственно для <code>t</code>. это связано с тем, что <code>i</code> был повторно связан с пространством имен <code>t</code>, которое отличается от пространства имен <code>test</code>. если вы хотите изменить значение "статической" переменной, вы должны изменить его в пределах области (или объекта), где оно было первоначально определено. я поместил "статический" в кавычки, потому что python на самом деле не имеет статических переменных в том смысле, как это делают c++ и java.</p><p>хотя он не говорит ничего конкретного о статических переменных или методах, <a href="http://docs.python.org/tut/">учебник по python</a> содержит некоторую соответствующую информацию о <a href="https://docs.python.org/2/tutorial/classes.html">классы и объекты классов</a> .</p><p>@ стив джонсон также ответил о статических методах, которые также описаны в разделе "встроенные функции" в python справочнике по библиотеке.</p><pre><code>class test(object): @staticmethod def f(arg1, arg2, ...): ... </code></pre><p>@beid также упомянул classmethod, который похож на staticmethod. первым аргументом метода класса является объект класса. пример:</p><pre><code>class test(object): i = 3 # class (or static) variable @classmethod def g(cls, arg): # here we can use 'cls' instead of the class name (test) if arg > cls.i: cls.i = arg # would the the same as test.i = arg1 </code></pre><p> <a href="https://i.stack.imgur.com/xqnxe.jpg"><img src="https://i.stack.imgur.com/xqnxe.jpg" alt="pictorial representation of above example"></a> </p>

<h2>статические и классовые методы</h2><p>как отмечалось в других ответах, статические методы и методы класса легко реализуются с помощью встроенных декораторов:</p><pre><code>class test(object): # regular instance method: def mymethod(self): pass # class method: @classmethod def myclassmethod(klass): pass # static method: @staticmethod def mystaticmethod(): pass </code></pre><p>как обычно, первый аргумент <code>mymethod()</code> связан с объектом экземпляра класса. напротив, первый аргумент функции <code>myclassmethod()</code> <em> связан с самим объектом класса </em> (например, в данном случае <code>test</code>). для <code>mystaticmethod()</code> ни один из аргументов не связан, и наличие аргументов вообще необязательно.</p><h2>"статические переменные"</h2><p>однако реализация "статических переменных" (ну, <em> изменяемых </em> статических переменных, в любом случае, если это не противоречие в терминах ...) не так проста. как сказал millerdev <a href="https://stackoverflow.com/a/69067/2437514">указал в своем ответе</a> , проблема в том, что атрибуты класса python не являются действительно "статическими переменными". рассматривать:</p><pre><code>class test(object): i = 3 # this is a class attribute x = test() x.i = 12 # attempt to change the value of the class attribute using x instance assert x.i == test.i # error assert test.i == 3 # test.i was not affected assert x.i == 12 # x.i is a different object than test.i </code></pre><p>это связано с тем, что строка <code>x.i = 12</code> добавила новый атрибут экземпляра <code>i</code> в <code>x</code> вместо изменения значения атрибута <code>test</code> class <code>i</code>.</p><p><em> частичное </em> ожидаемое поведение статической переменной, т. е. синхронизация атрибута между несколькими экземплярами (но <strong> нет </strong> с сам класс, см. "получил" ниже), может быть достигнуто путем превращения атрибута класса в свойство:</p><pre><code>class test(object): \_i = 3 @property def i(self): return type(self).\_i @i.setter def i(self,val): type(self).\_i = val ## alternative implementation - functionally equivalent to above ## ## (except with separate methods for getting and setting i) ## class test(object): \_i = 3 def get\_i(self): return type(self).\_i def set\_i(self,val): type(self).\_i = val i = property(get\_i, set\_i) </code></pre><p>теперь вы можете сделать:</p><pre><code>x1 = test() x2 = test() x1.i = 50 assert x2.i == x1.i # no error assert x2.i == 50 # the property is synced </code></pre><p>статическая переменная теперь будет оставаться синхронизированной <em> между всеми экземплярами класса </em>.</p><p>(примечание. то есть, если экземпляр класса не решит определить свою собственную версию <code>\_i</code>! но если кто-то решит сделать это, он заслуживает того, что получает, не так ли?)</p><p>обратите внимание, что с технической точки зрения <code>i</code> по-прежнему не является "статической переменной" вообще; это <code>property</code>, который является специальным типом дескриптора. однако поведение <code>property</code> теперь эквивалентно (изменяемой) статической переменной, синхронизированной во всех экземплярах класса.</p><h2>неизменные "статические переменные"</h2><p>для поведения неизменяемой статической переменной просто опустите установщик <code>property</code>:</p><pre><code>class test(object): \_i = 3 @property def i(self): return type(self).\_i ## alternative implementation - functionally equivalent to above ## ## (except with separate methods for getting i) ## class test(object): \_i = 3 def get\_i(self): return type(self).\_i i = property(get\_i) </code></pre><p>теперь попытка установить атрибут <code>i</code> экземпляра вернет <code>attributeerror</code>:</p><pre><code>x = test() assert x.i == 3 # success x.i = 12 # error </code></pre><h2>один gotcha, чтобы быть в курсе</h2><p>обратите внимание, что описанные выше методы работают только с <em> экземплярами </em> вашего класса - они не будут <strong> </strong> работать <em> при использовании самого класса </em>. так, например:</p><pre><code>x = test() assert x.i == test.i # error # x.i and test.i are two different objects: type(test.i) # class 'property' type(x.i) # class 'int' </code></pre><p>строка <code>assert test.i == x.i</code> выдает ошибку, поскольку атрибут <code>i</code> для <code>test</code> и <code>x</code> - это два разных объекта.</p><p>многие найдут это удивительным. однако так не должно быть. если мы вернемся и проверим определение класса <code>test</code> (вторая версия), мы примем к сведению эту строку:</p><pre><code> i = property(get\_i) </code></pre><p>очевидно, что член <code>i</code> из <code>test</code> должен быть объектом <code>property</code>, который является типом объекта, возвращаемого функцией <code>property</code>.</p><p>если вы находите вышеупомянутое в замешательстве, скорее всего, вы все еще думаете об этом с точки зрения других языков (например, java или c ++). вам следует изучить объект <code>property</code>, порядок, в котором возвращаются атрибуты python, протокол дескриптора и порядок разрешения методов (mro).</p><p>я представляю решение вышеупомянутой "ошибки" ниже; тем не менее, я бы настоятельно рекомендовал - неукоснительно - не пытаться делать что-то вроде следующего, пока - как минимум - вы полностью не поймете, почему <code>assert test.i = x.i</code> вызывает ошибку.</p><h2><em> real, actual </em> статические переменные - <code>test.i == x.i</code></h2><p>я представляю решение (python 3) ниже только в ознакомительных целях. я не одобряю это как "хорошее решение". у меня есть сомнения относительно того, нужна ли когда-либо эмуляция поведения статических переменных в других языках в python. тем не менее, независимо от того, действительно ли это полезно, нижеприведенное должно помочь понять, как работает python.</p><p>обновление: эта попытка <strong> действительно ужасна </strong>; если вы настаиваете на том, чтобы сделать что-то подобное (подсказка: пожалуйста, не делайте; python - очень элегантный язык, и вы можете заставить его вести себя как другой язык просто не обязательно), используйте код в <a href="https://stackoverflow.com/a/36216964/2437514">ответ итана фурмана</a> вместо.</p><p><strong> эмуляция поведения статических переменных других языков с использованием метакласса </strong></p><p>метакласс - это класс класса. метакласс по умолчанию для всех классов в python (т. е. публикация классов "new style" python 2.3, я считаю) - <code>type</code>. например:</p><pre><code>type(int) # class 'type' type(str) # class 'type' class test(): pass type(test) # class 'type' </code></pre><p>однако вы можете определить свой собственный метакласс следующим образом:</p><pre><code>class mymeta(type): pass </code></pre><p>и примените его к своему собственному классу вот так (только python 3):</p><pre><code>class myclass(metaclass = mymeta): pass type(myclass) # class mymeta </code></pre><p>ниже я создал метакласс, который пытается эмулировать поведение "статических переменных" других языков. он в основном работает, заменяя стандартные методы получения, установки и удаления версиями, которые проверяют, является ли запрашиваемый атрибут "статической переменной".</p><p>каталог "статических переменных" хранится в атрибуте <code>staticvarmeta.statics</code>. все запросы к атрибутам первоначально пытаются разрешить с использованием порядка разрешения замены. я назвал это "статическим разрешением", или "sro". это делается путем поиска запрошенного атрибута в наборе "статических переменных" для данного класса (или его родительских классов). если атрибут не отображается в "sro", класс будет использовать поведение по умолчанию для получения/установки/удаления атрибута (т. е. "mro").</p><pre><code>from functools import wraps class staticvarsmeta(type): '''a metaclass for creating classes that emulate the "static variable" behavior of other languages. i do not advise actually using this for anything!!! behavior is intended to be similar to classes that use \_\_slots\_\_. however, "normal" attributes and \_\_statics\_\_\_ can coexist (unlike with \_\_slots\_\_). example usage: class mybaseclass(metaclass = staticvarsmeta): \_\_statics\_\_ = {'a','b','c'} i = 0 # regular attribute a = 1 # static var defined (optional) class myparentclass(mybaseclass): \_\_statics\_\_ = {'d','e','f'} j = 2 # regular attribute d, e, f = 3, 4, 5 # static vars a, b, c = 6, 7, 8 # static vars (inherited from mybaseclass, defined/re-defined here) class mychildclass(myparentclass): \_\_statics\_\_ = {'a','b','c'} j = 2 # regular attribute (redefines j from myparentclass) d, e, f = 9, 10, 11 # static vars (inherited from myparentclass, redefined here) a, b, c = 12, 13, 14 # static vars (overriding previous definition in myparentclass here)''' statics = {} def \_\_new\_\_(mcls, name, bases, namespace): # get the class object cls = super().\_\_new\_\_(mcls, name, bases, namespace) # establish the "statics resolution order" cls.\_\_sro\_\_ = tuple(c for c in cls.\_\_mro\_\_ if isinstance(c,mcls)) # replace class getter, setter, and deleter for instance attributes cls.\_\_getattribute\_\_ = staticvarsmeta.\_\_inst\_getattribute\_\_(cls, cls.\_\_getattribute\_\_) cls.\_\_setattr\_\_ = staticvarsmeta.\_\_inst\_setattr\_\_(cls, cls.\_\_setattr\_\_) cls.\_\_delattr\_\_ = staticvarsmeta.\_\_inst\_delattr\_\_(cls, cls.\_\_delattr\_\_) # store the list of static variables for the class object # this list is permanent and cannot be changed, similar to \_\_slots\_\_ try: mcls.statics[cls] = getattr(cls,'\_\_statics\_\_') except attributeerror: mcls.statics[cls] = namespace['\_\_statics\_\_'] = set() # no static vars provided # check and make sure the statics var names are strings if any(not isinstance(static,str) for static in mcls.statics[cls]): typ = dict(zip((not isinstance(static,str) for static in mcls.statics[cls]), map(type,mcls.statics[cls])))[true].\_\_name\_\_ raise typeerror('\_\_statics\_\_ items must be strings, not {0}'.format(typ)) # move any previously existing, not overridden statics to the static var parent class(es) if len(cls.\_\_sro\_\_) > 1: for attr,value in namespace.items(): if attr not in staticvarsmeta.statics[cls] and attr != ['\_\_statics\_\_']: for c in cls.\_\_sro\_\_[1:]: if attr in staticvarsmeta.statics[c]: setattr(c,attr,value) delattr(cls,attr) return cls def \_\_inst\_getattribute\_\_(self, orig\_getattribute): '''replaces the class \_\_getattribute\_\_''' @wraps(orig\_getattribute) def wrapper(self, attr): if staticvarsmeta.is\_static(type(self),attr): return staticvarsmeta.\_\_getstatic\_\_(type(self),attr) else: return orig\_getattribute(self, attr) return wrapper def \_\_inst\_setattr\_\_(self, orig\_setattribute): '''replaces the class \_\_setattr\_\_''' @wraps(orig\_setattribute) def wrapper(self, attr, value): if staticvarsmeta.is\_static(type(self),attr): staticvarsmeta.\_\_setstatic\_\_(type(self),attr, value) else: orig\_setattribute(self, attr, value) return wrapper def \_\_inst\_delattr\_\_(self, orig\_delattribute): '''replaces the class \_\_delattr\_\_''' @wraps(orig\_delattribute) def wrapper(self, attr): if staticvarsmeta.is\_static(type(self),attr): staticvarsmeta.\_\_delstatic\_\_(type(self),attr) else: orig\_delattribute(self, attr) return wrapper def \_\_getstatic\_\_(cls,attr): '''static variable getter''' for c in cls.\_\_sro\_\_: if attr in staticvarsmeta.statics[c]: try: return getattr(c,attr) except attributeerror: pass raise attributeerror(cls.\_\_+ " object has no attribute '{0}'".format(attr)) def \_\_setstatic\_\_(cls,attr,value): '''static variable setter''' for c in cls.\_\_sro\_\_: if attr in staticvarsmeta.statics[c]: setattr(c,attr,value) break def \_\_delstatic\_\_(cls,attr): '''static variable deleter''' for c in cls.\_\_sro\_\_: if attr in staticvarsmeta.statics[c]: try: delattr(c,attr) break except attributeerror: pass raise attributeerror(cls.\_\_+ " object has no attribute '{0}'".format(attr)) def \_\_delattr\_\_(cls,attr): '''prevent \_\_sro\_\_ attribute from deletion''' if attr == '\_\_sro\_\_': raise attributeerror('readonly attribute') super().\_\_delattr\_\_(attr) def is\_static(cls,attr): '''returns true if an attribute is a static variable of any class in the \_\_sro\_\_''' if any(attr in staticvarsmeta.statics[c] for c in cls.\_\_sro\_\_): return true return false </code></pre>

<p>вы также можете добавлять переменные класса к классам на лету</p><pre><code>>>> class x: ... pass ... >>> x.bar = 0 >>> x = x() >>> x.bar 0 >>> x.foo traceback (most recent call last): file "<interactive input>", line 1, in <module> attributeerror: x instance has no attribute 'foo' >>> x.foo = 1 >>> x.foo 1 </code></pre><p>и экземпляры класса могут изменять переменные класса</p><pre><code>class x: l = [] def \_\_init\_\_(self): self.l.append(1) print x().l print x().l >python test.py [1] [1, 1] </code></pre>

<p>лично я использовал бы метод класса всякий раз, когда мне нужен статический метод. главным образом потому, что я получаю класс в качестве аргумента.</p><pre><code>class myobj(object): def mymethod(cls) ... mymethod = classmethod(mymethod) </code></pre><p>или использовать декоратор</p><pre><code>class myobj(object): @classmethod def mymethod(cls) </code></pre><p>для статических свойств .. пришло время поискать некоторую переменную python definition .. всегда может быть изменена. есть два типа: изменяемые и неизменяемые. кроме того, есть атрибуты класса и атрибуты экземпляра. ничто на самом деле не похоже на статические атрибуты в смысле java & c ++</p><p>зачем использовать статический метод в смысле pythonic, если он не имеет никакого отношения к классу! если бы я был тобой, я бы либо использовал метод класса, либо определил бы метод, независимый от класса.</p>

<p>статические методы в python называются <a href="http://pyref.infogami.com/classmethod">classmethod</a> s. посмотрите на следующий код</p><pre><code>class myclass: def myinstancemethod(self): print 'output from an instance method' @classmethod def mystaticmethod(cls): print 'output from a static method' >>> myclass.myinstancemethod() traceback (most recent call last): file "<stdin>", line 1, in <module> typeerror: unbound method myinstancemethod() must be called [...] >>> myclass.mystaticmethod() output from a static method </code></pre><p>обратите внимание, что когда мы вызываем метод <em> myinstancemethod </em>, мы получаем ошибку. это потому, что он требует, чтобы метод вызывался для экземпляра этого класса. метод <em> mystaticmethod </em> устанавливается как метод класса с использованием <a href="http://www.python.org/dev/peps/pep-0318/">декоратор</a> <em> @ classmethod </em>.</p><p>просто для того, чтобы пнуть и посмеяться, мы могли бы вызвать <em> myinstancemethod </em> для класса, передав экземпляр класса, например, так:</p><pre><code>>>> myclass.myinstancemethod(myclass()) output from an instance method </code></pre>

<p>особое внимание следует обратить на статические свойства и свойства экземпляра, показанные в следующем примере:</p><pre><code>class my\_cls: my\_prop = 0 #static property print my\_cls.my\_prop #--> 0 #assign value to static property my\_cls.my\_prop = 1 print my\_cls.my\_prop #--> 1 #access static property thru' instance my\_inst = my\_cls() print my\_inst.my\_prop #--> 1 #instance property is different from static property #after being assigned a value my\_inst.my\_prop = 2 print my\_cls.my\_prop #--> 1 print my\_inst.my\_prop #--> 2 </code></pre><p>это означает, что перед присвоением значения свойству экземпляра, если мы пытаемся получить доступ к свойству через экземпляр, используется статическое значение. <strong>каждое свойство, объявленное в классе python, всегда имеет статический слот в памяти</strong>.</p>

<p>при определении некоторой переменной-члена вне какого-либо метода-члена переменная может быть статической или нестатической в зависимости от того, как она выражена.</p><ul> <li>classname.var является статической переменной</li> <li>instancename.var не является статической переменной.</li> <li>self.var внутри класса не является статической переменной.</li> <li>var внутри функции-члена класса не определен.</li> </ul><p>например:</p><pre><code>#!/usr/bin/python class a: var=1 def printvar(self): print "self.var is %d" % self.var print "a.var is %d" % a.var a = a() a.var = 2 a.printvar() a.var = 3 a.printvar() </code></pre><p>результаты</p><pre><code>self.var is 2 a.var is 1 self.var is 2 a.var is 3 </code></pre>

<p>возможно иметь переменные класса <code>static</code>, но, вероятно, не стоит усилий.</p><p>вот подтверждение концепции, написанное в python 3 - если какая-то из точных деталей неверна, код можно настроить так, чтобы он соответствовал практически любому значению <code>static variable</code>:</p><hr><pre><code>class static: def \_\_init\_\_(self, value, doc=none): self.deleted = false self.value = value self.\_\_doc\_\_ = doc def \_\_get\_\_(self, inst, cls=none): if self.deleted: raise attributeerror('attribute not set') return self.value def \_\_set\_\_(self, inst, value): self.deleted = false self.value = value def \_\_delete\_\_(self, inst): self.deleted = true class statictype(type): def \_\_delattr\_\_(cls, name): obj = cls.\_\_dict\_\_.get(name) if isinstance(obj, static): obj.\_\_delete\_\_(name) else: super(statictype, cls).\_\_delattr\_\_(name) def \_\_getattribute\_\_(cls, *args): obj = super(statictype, cls).\_\_getattribute\_\_(*args) if isinstance(obj, static): obj = obj.\_\_get\_\_(cls, cls.\_\_class\_\_) return obj def \_\_setattr\_\_(cls, name, val): # check if object already exists obj = cls.\_\_dict\_\_.get(name) if isinstance(obj, static): obj.\_\_set\_\_(name, val) else: super(statictype, cls).\_\_setattr\_\_(name, val) </code></pre><p>и в использовании:</p><pre><code>class mystatic(metaclass=statictype): """ testing static vars """ a = static(9) b = static(12) c = 3 class yourstatic(mystatic): d = static('woo hoo') e = static('doo wop') </code></pre><p>и некоторые тесты:</p><pre><code>ms1 = mystatic() ms2 = mystatic() ms3 = mystatic() assert ms1.a == ms2.a == ms3.a == mystatic.a assert ms1.b == ms2.b == ms3.b == mystatic.b assert ms1.c == ms2.c == ms3.c == mystatic.c ms1.a = 77 assert ms1.a == ms2.a == ms3.a == mystatic.a ms2.b = 99 assert ms1.b == ms2.b == ms3.b == mystatic.b mystatic.a = 101 assert ms1.a == ms2.a == ms3.a == mystatic.a mystatic.b = 139 assert ms1.b == ms2.b == ms3.b == mystatic.b del mystatic.b for inst in (ms1, ms2, ms3): try: getattr(inst, 'b') except attributeerror: pass else: print('attributeerror not raised on %r' % attr) ms1.c = 13 ms2.c = 17 ms3.c = 19 assert ms1.c == 13 assert ms2.c == 17 assert ms3.c == 19 mystatic.c = 43 assert ms1.c == 13 assert ms2.c == 17 assert ms3.c == 19 ys1 = yourstatic() ys2 = yourstatic() ys3 = yourstatic() mystatic.b = 'burgler' assert ys1.a == ys2.a == ys3.a == yourstatic.a == mystatic.a assert ys1.b == ys2.b == ys3.b == yourstatic.b == mystatic.b assert ys1.d == ys2.d == ys3.d == yourstatic.d assert ys1.e == ys2.e == ys3.e == yourstatic.e ys1.a = 'blah' assert ys1.a == ys2.a == ys3.a == yourstatic.a == mystatic.a ys2.b = 'kelp' assert ys1.b == ys2.b == ys3.b == yourstatic.b == mystatic.b ys1.d = 'fee' assert ys1.d == ys2.d == ys3.d == yourstatic.d ys2.e = 'fie' assert ys1.e == ys2.e == ys3.e == yourstatic.e mystatic.a = 'aargh' assert ys1.a == ys2.a == ys3.a == yourstatic.a == mystatic.a </code></pre>

<p>вы также можете заставить класс быть статичным, используя метакласс.</p><pre><code>class staticclasserror(exception): pass class staticclass: \_\_metaclass\_\_ = abc.abcmeta def \_\_new\_\_(cls, *args, **kw): raise staticclasserror("%s is a static class and cannot be initiated." % cls) class myclass(staticclass): a = 1 b = 3 @staticmethod def add(x, y): return x+y </code></pre><p>тогда всякий раз, когда вы случайно попытаетесь инициализировать <strong>myclass</strong>, вы получите staticclasserror.</p>

<p>один очень интересный момент в поиске атрибутов python заключается в том, что его можно использовать для создания " <a href="https://en.wikipedia.org/wiki/virtual\_function">virtual</a> variable":</p><pre><code>class a(object): label="amazing" def \_\_init\_\_(self,d): self.data=d def say(self): print("%s %s!"%(self.label,self.data)) class b(a): label="bold" # overrides a.label a(5).say() # amazing 5! b(3).say() # bold 3! </code></pre><p>обычно нет никаких назначений этим после того, как они созданы. обратите внимание, что поиск использует <code>self</code>, потому что, хотя <code>label</code> является статическим в том смысле, что он не связан с <em> конкретным </em> экземпляром, значение по-прежнему зависит от (класса ) экземпляра.</p>

<p>абсолютно да, python само по себе не имеет какого-либо статического члена данных явно, но мы можем получить таким образом</p><pre><code>class a: counter =0 def callme (self): a.counter +=1 def getcount (self): return self.counter >>> x=a() >>> y=a() >>> print(x.getcount()) >>> print(y.getcount()) >>> x.callme() >>> print(x.getcount()) >>> print(y.getcount()) </code></pre><p>результат</p><pre><code>0 0 1 1 </code></pre><p>объяснение</p><pre><code>here object (x) alone increment the counter variable from 0 to 1 by not object y. but result it as "static counter" </code></pre>

<p>что касается этой <a href="https://stackoverflow.com/a/68672/717357">answer</a> , то для <em> постоянной </em> статической переменной вы можете использовать дескриптор. вот пример:</p><pre><code>class constantattribute(object): '''you can initialize my value but not change it.''' def \_\_init\_\_(self, value): self.value = value def \_\_get\_\_(self, obj, type=none): return self.value def \_\_set\_\_(self, obj, val): pass class demo(object): x = constantattribute(10) class subdemo(demo): x = 10 demo = demo() subdemo = subdemo() # should not change demo.x = 100 # should change subdemo.x = 100 print "small demo", demo.x print "small subdemo", subdemo.x print "big demo", demo.x print "big subdemo", subdemo.x </code></pre><p>в результате чего ...</p><pre><code>small demo 10 small subdemo 100 big demo 10 big subdemo 10 </code></pre><p>вы всегда можете вызвать исключение, если тихое игнорирование значения настройки (<code>pass</code> выше) не является вашей вещью. если вы ищете переменную статического класса в стиле c++, java:</p><pre><code>class staticattribute(object): def \_\_init\_\_(self, value): self.value = value def \_\_get\_\_(self, obj, type=none): return self.value def \_\_set\_\_(self, obj, val): self.value = val </code></pre><p>посмотрите <a href="https://stackoverflow.com/a/102062/717357">этот ответ</a> и официальные документы <a href="https://docs.python.org/2/howto/descriptor.html">howto</a> для получения дополнительной информации о дескрипторах.</p>

<p>лучший способ, который я нашел, - это использовать другой класс. вы можете создать объект, а затем использовать его на других объектах.</p><pre><code>class staticflag: def \_\_init\_\_(self): self.\_\_success = false def issuccess(self): return self.\_\_success def succeed(self): self.\_\_success = true class tryit: def \_\_init\_\_(self, staticflag): self.issuccess = staticflag.issuccess self.succeed = staticflag.succeed tryarr = [] flag = staticflag() for i in range(10): tryarr.append(tryit(flag)) if i == 5: tryarr[i].succeed() print tryarr[i].issuccess() </code></pre><p>в приведенном выше примере я создал класс с именем <code>staticflag</code>.</p><p>этот класс должен представлять статический var <code>\_\_success</code> (private static var).</p><p>класс <code>tryit</code> представляет обычный класс, который нам нужно использовать.</p><p>теперь я сделал объект для одного флага (<code>staticflag</code>). этот флаг будет отправлен как ссылка на все обычные объекты.</p><p>все эти объекты добавляются в список <code>tryarr</code>.</p><hr><p>результаты этого скрипта:</p><pre><code>false false false false false true true true true true </code></pre>

<p>чтобы избежать возможной путаницы, я бы хотел сопоставить статические переменные и неизменяемые объекты.</p><p>некоторые примитивные типы объектов, такие как целые числа, числа с плавающей запятой, строки и части, являются неизменяемыми в python. это означает, что объект, на который ссылается данное имя, не может измениться, если он относится к одному из вышеупомянутых типов объектов. имя может быть переназначено другому объекту, но сам объект не может быть изменен.</p><p>если сделать статическую переменную еще более продвинутой, запретить имя переменной указывать на любой объект, кроме того, на который она в данный момент указывает. (примечание: это общая концепция программного обеспечения, а не специфичная для python; см. посты других пользователей для получения информации о реализации статики в python).</p>

<p>да, безусловно, можно писать статические переменные и методы в python.</p><p><strong>статические переменные:</strong> переменные, объявленные на уровне класса, называются статическими переменными, к которым можно обращаться напрямую, используя имя класса.</p><pre><code> >>> class a: ...my\_var = "shagun" >>> print(a.my\_var) shagun </code></pre><p><strong>переменные экземпляра:</strong> переменные, которые связаны и доступны экземпляру класса, являются переменными экземпляра.</p><pre><code> >>> a = a() >>> a.my\_var = "pruthi" >>> print(a.my\_var,a.my\_var) shagun pruthi </code></pre><p><strong>статические методы:</strong> подобно переменным, статические методы могут быть доступны напрямую с помощью класса name. не нужно создавать экземпляр.</p><p>но имейте в виду, что статический метод не может вызывать нестатический метод в python.</p><pre><code> >>> class a: ... @staticmethod ... def my\_static\_method(): ... print("yippey!!") ... >>> a.my\_static\_method() yippey!! </code></pre>

<h1>статические переменные в фабрике классов python3.6</h1><p>для тех, кто использует фабрику классов с <strong>python3.6</strong> и выше, используйте ключевое слово <code>nonlocal</code>, чтобы добавить его в контекст/контекст создаваемого класса следующим образом:</p><pre><code>>>> def somefactory(some\_var=none): ... class someclass(object): ... nonlocal some\_var ... def print(): ... print(some\_var) ... return someclass ... >>> somefactory(some\_var="hello world").print() hello world </code></pre>