it-swarm-pt.tech

As variáveis ​​de classe estática não existem no Python?

É possível ter variáveis ​​de classe estáticas ou métodos em python? Qual é a sintaxe necessária para fazer isso?

1710
Andrew Walker

Variáveis ​​declaradas dentro da definição de classe, mas não dentro de um método, são variáveis ​​de classe ou estáticas:

>>> class MyClass:
...     i = 3
...
>>> MyClass.i
3 

Como @ millerdev aponta, isso cria uma variável i em nível de classe, mas isso é diferente de qualquer variável i em nível de instância, então você poderia ter

>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)

Isso é diferente de C++ e Java, mas não tão diferente de C #, em que um membro estático não pode ser acessado usando uma referência a uma instância.

Veja o que o tutorial do Python tem a dizer sobre o assunto de classes e objetos de classe .

@Steve Johnson já respondeu sobre métodos estáticos , também documentado em "Funções internas" na Referência da Biblioteca Python .

class C:
    @staticmethod
    def f(arg1, arg2, ...): ...

@beidy recomenda classmethod s over staticmethod, pois o método então recebe o tipo de classe como o primeiro argumento, mas eu ainda estou um pouco confuso sobre as vantagens dessa abordagem sobre o staticmethod. Se você também é, provavelmente não importa.

1688
Blair Conrad

@Blair Conrad disse que as variáveis ​​estáticas declaradas dentro da definição de classe, mas não dentro de um método, são variáveis ​​de classe ou "estáticas":

>>> class Test(object):
...     i = 3
...
>>> Test.i
3

Há algumas pegadinhas aqui. Continuando a partir do exemplo acima:

>>> 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__
{}

Observe como a variável de instância t.i saiu de sincronia com a variável de classe "static" quando o atributo i foi definido diretamente em t. Isso ocorre porque o i foi recolocado dentro do namespace t, que é diferente do namespace Test. Se você quiser alterar o valor de uma variável "estática", você deve alterá-la dentro do escopo (ou objeto) onde foi originalmente definida. Eu coloquei "static" entre aspas porque o Python realmente não tem variáveis ​​estáticas no sentido que C++ e Java fazem.

Embora não diga nada específico sobre variáveis ​​ou métodos estáticos, o tutorial em Python tem alguma informação relevante em classes e objetos de classe .

@Steve Johnson também respondeu sobre métodos estáticos, também documentados em "Funções internas" na Referência da Biblioteca Python.

class Test(object):
    @staticmethod
    def f(arg1, arg2, ...):
        ...

@beid também mencionou o classmethod, que é semelhante ao staticmethod. O primeiro argumento de um classmethod é o objeto de classe. Exemplo:

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

Pictorial Representation Of Above Example

562
millerdev

Métodos estáticos e de classe

Como as outras respostas observaram, os métodos estáticos e de classe são facilmente executados usando os decoradores internos:

class Test(object):

    # regular instance method:
    def MyMethod(self):
        pass

    # class method:
    @classmethod
    def MyClassMethod(klass):
        pass

    # static method:
    @staticmethod
    def MyStaticMethod():
        pass

Como de costume, o primeiro argumento para MyMethod() está vinculado ao objeto de instância da classe. Em contraste, o primeiro argumento para MyClassMethod() é ligado ao próprio objeto de classe (por exemplo, neste caso, Test). Para MyStaticMethod(), nenhum dos argumentos está vinculado e ter argumentos é opcional.

"Variáveis ​​estáticas"

No entanto, implementar "variáveis ​​estáticas" (bem, mutável variáveis ​​estáticas, de qualquer maneira, se isso não é uma contradição em termos ...) não é tão simples. Como millerdev apontado em sua resposta , o problema é que os atributos de classe do Python não são verdadeiramente "variáveis ​​estáticas". Considerar:

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

Isso ocorre porque a linha x.i = 12 adicionou um novo atributo de instância i a x em vez de alterar o valor do atributo Test class i.

Comportamento de variável estática parcial esperado, isto é, sincronização do atributo entre múltiplas instâncias (mas não com o própria classe, veja "gotcha" abaixo), pode ser conseguido, transformando o atributo de classe em uma propriedade:

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)

Agora você pode fazer:

x1 = Test()
x2 = Test()
x1.i = 50
assert x2.i == x1.i  # no error
assert x2.i == 50    # the property is synced

A variável estática agora permanecerá em sincronia entre todas as instâncias de classe .

(NOTA: Isto é, a menos que uma instância de classe decida definir sua própria versão de _i! Mas se alguém decidir fazer isso, eles merecem o que recebem, não é ???)

Note que, tecnicamente falando, i ainda não é uma 'variável estática'; é um property, que é um tipo especial de descritor. No entanto, o comportamento property agora é equivalente a uma variável estática (mutável) sincronizada em todas as instâncias de classe.

"Variáveis ​​estáticas" imutáveis

Para o comportamento de variáveis ​​estáticas imutáveis, simplesmente omita o setter property:

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)

Agora, tentar definir o atributo i da instância retornará um AttributeError:

x = Test()
assert x.i == 3  # success
x.i = 12         # ERROR

Um Gotcha para estar ciente de

Note que os métodos acima só funcionam com instâncias da sua classe - eles irão não funcionar ao usar a própria classe . Então, por exemplo:

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'

A linha assert Test.i == x.i produz um erro, porque o atributo i de Test e x são dois objetos diferentes.

Muitas pessoas vão achar isso surpreendente. No entanto, não deveria ser. Se voltarmos e inspecionarmos nossa definição de classe Test (a segunda versão), tomamos nota desta linha:

    i = property(get_i) 

Claramente, o membro i de Test deve ser um objeto property, que é o tipo de objeto retornado da função property.

Se você achar o acima confuso, você provavelmente ainda está pensando sobre isso do ponto de vista de outras linguagens (por exemplo, Java ou c ++). Você deve estudar o objeto property, sobre a ordem em que os atributos do Python são retornados, o protocolo do descritor e a ordem de resolução do método (MRO).

Eu apresento uma solução para o 'pegadinha' acima abaixo; no entanto, eu sugiro - enfaticamente - que você não tente fazer algo como o seguinte até que - no mínimo - você entenda por que assert Test.i = x.i causa um erro.

REAL, ACTUAL Variáveis ​​estáticas - Test.i == x.i

Eu apresento a solução (Python 3) abaixo apenas para fins informativos. Eu não estou endossando isso como uma "boa solução". Eu tenho minhas dúvidas sobre se a emulação do comportamento da variável estática de outras linguagens no Python é realmente necessária. No entanto, independentemente de se é realmente útil, o abaixo deve ajudar a entender melhor como funciona o Python.

UPDATE: esta tentativa é realmente muito horrível ; Se você insistir em fazer algo assim (dica: por favor, não; o Python é uma linguagem muito elegante e se comportar como se outro idioma não fosse necessário), use o código em resposta de Ethan Furman em vez disso.

Emulando o comportamento da variável estática de outros idiomas usando uma metaclasse

Uma metaclasse é a classe de uma classe. A metaclasse padrão para todas as classes em Python (ou seja, as classes "new style" postadas no Python 2.3, eu acredito) é type. Por exemplo:

type(int)  # class 'type'
type(str)  # class 'type'
class Test(): pass
type(Test) # class 'type'

No entanto, você pode definir sua própria metaclasse assim:

class MyMeta(type): pass

E aplique-o à sua própria classe assim (somente Python 3):

class MyClass(metaclass = MyMeta):
    pass

type(MyClass)  # class MyMeta

Abaixo está uma metaclasse que criei que tenta emular o comportamento de "variável estática" de outras linguagens. Ele basicamente funciona substituindo o getter, setter e deleter padrão por versões que verificam se o atributo que está sendo solicitado é uma "variável estática".

Um catálogo das "variáveis ​​estáticas" é armazenado no atributo StaticVarMeta.statics. Todas as solicitações de atributo são inicialmente tentadas a serem resolvidas usando um pedido de resolução substituta. Eu chamei isso de "ordem de resolução estática" ou "SRO". Isso é feito procurando o atributo solicitado no conjunto de "variáveis ​​estáticas" para uma determinada classe (ou suas classes pai). Se o atributo não aparecer no "SRO", a classe retornará ao atributo padrão get/set/delete (isto é, "MRO").

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
167
Rick Teachey

Você também pode adicionar variáveis ​​de classe a classes dinamicamente

>>> 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

E as instâncias de classe podem alterar variáveis ​​de classe

class X:
  l = []
  def __init__(self):
    self.l.append(1)

print X().l
print X().l

>python test.py
[1]
[1, 1]
24
Gregory

Pessoalmente, eu usaria um método de classe sempre que precisasse de um método estático. Principalmente porque eu entendo a aula como um argumento.

class myObj(object):
   def myMethod(cls)
     ...
   myMethod = classmethod(myMethod) 

ou use um decorador

class myObj(object):
   @classmethod
   def myMethod(cls)

Para propriedades estáticas .. É hora de procurar alguma definição python .. variável sempre pode mudar. Existem dois tipos deles mutáveis ​​e imutáveis. Além disso, existem atributos de classe e atributos de instância. Nada realmente gosta de atributos estáticos no sentido de Java & c + +

Por que usar o método estático no sentido Pythonic, se ele não tiver relação alguma com a classe! Se eu fosse você, usaria o classmethod ou definiria o método independente da classe.

15
emb

Métodos estáticos em python são chamados classmethod s. Dê uma olhada no seguinte código

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

Observe que quando chamamos o método myInstanceMethod , obtemos um erro. Isso ocorre porque requer que o método seja chamado em uma instância dessa classe. O método myStaticMethod é definido como um método de classe usando o método de classificação decorator @ classmethod .

Apenas para chutes e risadas, poderíamos chamar myInstanceMethod na classe, passando em uma instância da classe, da seguinte forma:

>>> MyClass.myInstanceMethod(MyClass())
output from an instance method
13
willurd

Uma observação especial sobre propriedades estáticas e propriedades de instâncias, mostrada no exemplo abaixo:

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

Isso significa antes de atribuir o valor à propriedade da instância, se tentarmos acessar a propriedade através da instância, o valor estático será usado. Cada propriedade declarada na classe python sempre tem um slot estático na memória.

13
jondinham

Quando define alguma variável de membro fora de qualquer método de membro, a variável pode ser estática ou não-estática dependendo de como a variável é expressa.

  • CLASSNAME.var é variável estática
  • INSTANCENAME.var não é variável estática.
  • self.var dentro da classe não é variável estática.
  • var dentro da função de membro de classe não está definida.

Por exemplo:

#!/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()

Os resultados são

self.var is 2
A.var is 1
self.var is 2
A.var is 3
8
user2209576

É possível ter variáveis ​​de classe static, mas provavelmente não vale o esforço.

Aqui está uma prova de conceito escrita em Python 3 - se algum dos detalhes exatos estiver errado, o código pode ser ajustado para corresponder ao que quer que você queira dizer com um static variable:


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)

e em uso:

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')

e alguns testes:

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
6
Ethan Furman

Você também pode impor que uma classe seja estática usando metaclasse.

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

Então sempre que acidentalmente você tentar inicializar MyClass você obterá um StaticClassError.

6
Bartosz Ptaszynski

Um ponto muito interessante sobre a pesquisa de atributos do Python é que ela pode ser usada para criar " virtual variables":

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!

Normalmente, não há atribuições para estes depois que eles são criados. Observe que a pesquisa usa self porque, embora label seja estático no sentido de não estar associado a uma instância específica , o valor ainda depende da (classe da) instância.

5
Davis Herring

Absolutamente Sim, o Python por si só não tem nenhum membro de dados estático explicitamente, mas podemos fazer isso

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())

saída

0
0
1
1

explicação

here object (x) alone increment the counter variable
from 0 to 1 by not object y. But result it as "static counter"
4
Mari Selvan

Em relação a isto resposta , para uma constante estática , você pode usar um descritor. Aqui está um exemplo:

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

resultando em ...

small demo 10
small subdemo 100
big demo 10
big subdemo 10

Você sempre pode levantar uma exceção se silenciosamente ignorar o valor de configuração (pass acima) não é sua coisa. Se você estiver procurando por uma variável de classe estática C++, estilo Java:

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

Dê uma olhada em esta resposta e os documentos oficiais HOWTO para mais informações sobre os descritores.

4
Yann

A melhor maneira que encontrei é usar outra classe. Você pode criar um objeto e usá-lo em outros objetos.

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()

Com o exemplo acima, criei uma classe chamada staticFlag.

Esta classe deve apresentar o static var __success (Private Static Var).

tryIt class representou a classe regular que precisamos usar.

Agora eu fiz um objeto para um sinalizador (staticFlag). Este sinalizador será enviado como referência para todos os objetos regulares.

Todos esses objetos estão sendo adicionados à lista tryArr.


Resultados deste script:

False
False
False
False
False
True
True
True
True
True
3
Tomer Zait

Para evitar qualquer confusão potencial, gostaria de contrastar variáveis ​​estáticas e objetos imutáveis.

Alguns tipos de objetos primitivos, como inteiros, flutuantes, sequências de caracteres e toques, são imutáveis ​​no Python. Isso significa que o objeto que é referido por um determinado nome não pode ser alterado se for de um dos tipos de objetos mencionados anteriormente. O nome pode ser reatribuído para um objeto diferente, mas o objeto em si não pode ser alterado.

Tornar uma variável estática leva isso um pouco além, impedindo que o nome da variável aponte para qualquer objeto, mas aquele para o qual ele aponta atualmente. (Nota: este é um conceito geral de software e não é específico do Python; por favor, veja os posts dos outros para obter informações sobre como implementar estática no Python).

3
Ross

Sim, definitivamente possível escrever variáveis ​​estáticas e métodos em python.

Variáveis ​​estáticas: Variáveis ​​declaradas no nível da classe são chamadas de variáveis ​​estáticas que podem ser acessadas diretamente usando o nome da classe.

    >>> class A:
        ...my_var = "shagun"

    >>> print(A.my_var)
        shagun

Variáveis ​​de instância: Variáveis ​​relacionadas e acessadas por instância de uma classe são variáveis ​​de instância.

   >>> a = A()
   >>> a.my_var = "pruthi"
   >>> print(A.my_var,a.my_var)
       shagun pruthi

Métodos estáticos: Similar às variáveis, os métodos estáticos podem ser acessados ​​diretamente usando o nome da classe. Não há necessidade de criar uma instância.

Mas lembre-se, um método estático não pode chamar um método não estático em python.

    >>> class A:
   ...     @staticmethod
   ...     def my_static_method():
   ...             print("Yippey!!")
   ... 
   >>> A.my_static_method()
   Yippey!!
2
Shagun Pruthi

Variáveis ​​Estáticas em Classe factory python3.6

Para qualquer pessoa que use uma factory de classe com python3.6 e use a palavra-chave nonlocal para adicioná-la ao escopo/contexto da classe que está sendo criada da seguinte forma:

>>> 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
1
jmunsch