it-swarm.it

Le variabili di classe statiche sono possibili su Python?

È possibile avere variabili o metodi di classe statici in python? Quale sintassi è richiesta per fare questo?

1710
Andrew Walker

Le variabili dichiarate all'interno della definizione della classe, ma non all'interno di un metodo sono variabili di classe o statiche:

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

Come @ millerdev sottolinea, questo crea una variabile i di livello di classe, ma questa è distinta da qualsiasi variabile i a livello di istanza, quindi potresti avere

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

Questo è diverso da C++ e Java, ma non così diverso da C #, dove non è possibile accedere a un membro statico usando un riferimento a un'istanza.

Vedi che cosa il tutorial Python ha da dire sull'argomento delle classi e degli oggetti di classe .

@Steve Johnson ha già risposto riguardo ai metodi statici , documentati anche in "Funzioni built-in" nella libreria Python Riferimento .

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

@beidy raccomanda classmethod s su staticmethod, in quanto il metodo riceve il tipo di classe come primo argomento, ma sono ancora un po 'sfocato sui vantaggi di questo approccio su staticmethod. Se lo sei anche tu, probabilmente non importa.

1688
Blair Conrad

@Blair Conrad ha dichiarato che le variabili statiche dichiarate all'interno della definizione della classe, ma non all'interno di un metodo sono variabili di classe o "statiche":

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

Ci sono alcuni segreti qui. Proseguendo nell'esempio sopra:

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

Si noti come la variabile di istanza t.i non sia sincronizzata con la variabile di classe "statica" quando l'attributo i è stato impostato direttamente su t. Questo perché i è stato reimpostato nello spazio dei nomi t, che è distinto dallo spazio dei nomi Test. Se si desidera modificare il valore di una variabile "statica", è necessario modificarlo all'interno dell'ambito (o dell'oggetto) in cui era stato originariamente definito. Inserisco "statico" tra virgolette perché Python in realtà non ha variabili statiche nel senso che C++ e Java fanno.

Anche se non dice nulla di specifico su variabili o metodi statici, il tutorial Python ha alcune informazioni rilevanti sulle classi e oggetti di classe .

@Steve Johnson ha anche risposto ai metodi statici, documentati anche in "Funzioni built-in" nella libreria Python Reference.

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

@beid ha anche menzionato classmethod, che è simile a staticmethod. Il primo argomento di classmethod è l'oggetto di classe. Esempio:

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

Metodi statici e di classe

Come hanno notato le altre risposte, i metodi statici e di classe sono facilmente realizzabili utilizzando i decoratori incorporati:

class Test(object):

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

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

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

Come al solito, il primo argomento di MyMethod() è associato all'oggetto istanza di classe. Al contrario, il primo argomento di MyClassMethod() è associato all'oggetto della classe stesso (ad es., In questo caso, Test). Per MyStaticMethod(), nessuno degli argomenti è associato, e avere argomenti è facoltativo.

"Variabili statiche"

Tuttavia, l'implementazione di "variabili statiche" (beh, variabili statiche mutabili , comunque, se questa non è una contraddizione in termini ...) non è così semplice. Come millerdev ha sottolineato nella sua risposta , il problema è che gli attributi di classe di Python non sono veramente "variabili statiche". Tenere conto:

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

Questo perché la riga x.i = 12 ha aggiunto un nuovo attributo di istanza i a x invece di modificare il valore dell'attributo Test class i.

Comportamento variabile statico parziale previsto, cioè sincronizzazione dell'attributo tra più istanze (ma non con la classe stessa; vedere "gotcha" sotto ), può essere ottenuto trasformando l'attributo di classe in una proprietà:

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)

Ora puoi fare:

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

La variabile statica rimarrà sincronizzata tra tutte le istanze di classe .

(NOTA: Cioè, a meno che un'istanza di classe decida di definire la propria versione di _i! Ma se qualcuno decide di farlo, si merita quello che ottiene, vero ???)

Nota che tecnicamente, i non è ancora una 'variabile statica'; è un property, che è un tipo speciale di descrittore. Tuttavia, il comportamento property ora equivale a una variabile statica (mutabile) sincronizzata su tutte le istanze di classe.

"Variabili statiche" immutabili

Per comportamento delle variabili statiche immutabili, è sufficiente omettere il 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)

Ora il tentativo di impostare l'attributo i restituirà un AttributeError:

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

Un Gotcha di cui essere consapevole

Nota che i metodi sopra funzionano solo con istanze della tua classe - essi non funzionano quando usano la classe stessa . Quindi per esempio:

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'

La riga assert Test.i == x.i produce un errore, perché l'attributo i di Test e x sono due oggetti diversi.

Molte persone lo troveranno sorprendente. Tuttavia, non dovrebbe essere. Se torniamo indietro e ispezioniamo la nostra definizione di classe Test (la seconda versione), prendiamo nota di questa linea:

    i = property(get_i) 

Chiaramente, il membro i di Test deve essere un oggetto property, che è il tipo di oggetto restituito dalla funzione property.

Se trovi la confusione di cui sopra, probabilmente lo stai ancora pensando dal punto di vista di altri linguaggi (ad es. Java o c ++). Dovresti studiare l'oggetto property, l'ordine in cui vengono restituiti gli attributi Python, il protocollo descrittore e l'ordine di risoluzione dei metodi (MRO).

Presento una soluzione al suddetto 'gotcha' di seguito; tuttavia vorrei suggerire - strenuamente - che tu non provi a fare qualcosa di simile al seguente finché - almeno - comprendi completamente perché assert Test.i = x.i causa un errore.

Variabili statiche REAL, ACTUAL - Test.i == x.i

Presento la soluzione (Python 3) di seguito solo a scopo informativo. Non lo approvo come una "buona soluzione". Ho i miei dubbi sul fatto che emulare il comportamento delle variabili statiche di altri linguaggi in Python sia mai realmente necessario. Tuttavia, indipendentemente dal fatto che sia effettivamente utile, il sotto dovrebbe aiutare a capire meglio come funziona Python.

AGGIORNAMENTO: questo tentativo è davvero piuttosto terribile ; se ti ostini a fare qualcosa di simile (suggerimento: per favore non farlo, Python è un linguaggio molto elegante e la scarpa - innamorarsi di comportarsi come un altro linguaggio non è semplicemente necessario), usa il codice in La risposta di Ethan Furman invece.

Emulazione del comportamento delle variabili statiche di altre lingue usando una metaclasse

Una metaclasse è la classe di una classe. Il metaclasse predefinito per tutte le classi in Python (ad esempio, le classi "new style" post Python 2.3 credo) è type. Per esempio:

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

Tuttavia, puoi definire il tuo metaclasse in questo modo:

class MyMeta(type): pass

E applicalo alla tua classe come questa (solo Python 3):

class MyClass(metaclass = MyMeta):
    pass

type(MyClass)  # class MyMeta

Di seguito è riportato un metaclass che ho creato che tenta di emulare il comportamento di "variabili statiche" di altri linguaggi. Funziona fondamentalmente sostituendo getter, setter e deleter predefiniti con le versioni che controllano se l'attributo richiesto è una "variabile statica".

Un catalogo delle "variabili statiche" è memorizzato nell'attributo StaticVarMeta.statics. Inizialmente si è tentato di risolvere tutte le richieste di attributo utilizzando un ordine di risoluzione sostitutivo. L'ho soprannominato "ordine di risoluzione statica" o "SRO". Questo viene fatto cercando l'attributo richiesto nel set di "variabili statiche" per una determinata classe (o le sue classi genitore). Se l'attributo non appare in "SRO", la classe ricadrà sull'attributo predefinito get/set/delete (ad es., "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

Puoi anche aggiungere variabili di classe alle classi al volo

>>> 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 le istanze di classe possono cambiare le variabili di 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

Personalmente avrei usato un metodo di classe ogni volta che avevo bisogno di un metodo statico. Principalmente perché ottengo la classe come argomento.

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

o usare un decoratore

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

Per le proprietà statiche .. È tempo di cercare qualche definizione python .. la variabile può sempre cambiare. Ci sono due tipi di questi mutabili e immutabili .. Inoltre, ci sono attributi di classe e attributi di istanza. Nulla di veramente come gli attributi statici nel senso di Java e c ++

Perché usare il metodo statico in senso pitone, se non ha alcuna relazione con la classe! Se fossi in te, userei classmethod o definirò il metodo indipendente dalla classe.

15
emb

I metodi statici in python sono chiamati classmethod s. Dai un'occhiata al seguente codice

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

Si noti che quando chiamiamo il metodo myInstanceMethod , si ottiene un errore. Questo perché richiede che il metodo venga chiamato su un'istanza di questa classe. Il metodo myStaticMethod è impostato come un metodo di classe utilizzando il decorator @ classmethod .

Solo per i calci e le risatine, potremmo chiamare myInstanceMethod sulla classe passando un'istanza della classe, in questo modo:

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

Una cosa speciale da notare sulle proprietà statiche e sulle proprietà dell'istanza, mostrate nell'esempio seguente:

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

Questo significa che prima di assegnare il valore alla proprietà instance, se proviamo ad accedere alla proprietà thru 'instance, viene utilizzato il valore statico. Ogni proprietà dichiarata nella classe python ha sempre uno slot statico in memoria .

13
jondinham

Quando si definisce una variabile membro al di fuori di qualsiasi metodo membro, la variabile può essere statica o non statica a seconda di come viene espressa la variabile.

  • CLASSNAME.var è una variabile statica
  • INSTANCENAME.var non è una variabile statica.
  • self.var all'interno della classe non è una variabile statica.
  • var all'interno della funzione membro della classe non è definito.

Per esempio:

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

I risultati sono

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

È possibile avere variabili di classe static, ma probabilmente non ne vale la pena.

Ecco una proof-of-concept scritta in Python 3 - se uno qualsiasi dei dettagli esatti è sbagliato, il codice può essere modificato per corrispondere a qualsiasi cosa tu voglia dire con un 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 in 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 alcuni test:

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

Si potrebbe anche far rispettare una classe per essere statica usando la 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

Quindi, ogni volta che si tenta di inizializzare MyClass si ottiene un errore StaticClassError.

6

Un punto molto interessante sulla ricerca degli attributi di Python è che può essere usato per creare " virtual variabili":

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 non ci sono assegnazioni a questi dopo che sono stati creati. Si noti che la ricerca utilizza self perché, sebbene label sia statico nel senso di non essere associato a un'istanza particolare , il valore dipende ancora dall'istanza (classe dell'istanza).

5
Davis Herring

Assolutamente Sì, Python da solo non ha alcun membro di dati statici esplicitamente, ma possiamo farlo facendo così

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

produzione

0
0
1
1

spiegazione

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

Riguardo a questo answer , per una variabile statica costante , puoi usare un descrittore. Ecco un esempio:

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

con il risultato di ...

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

Puoi sempre sollevare un'eccezione se ignorando tranquillamente il valore di impostazione (pass sopra) non è il tuo genere. Se stai cercando una variabile di classe statica in stile C++, 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

Dai un'occhiata a questa risposta e i documenti ufficiali HOWTO per maggiori informazioni sui descrittori.

4
Yann

Il modo migliore che ho trovato è usare un'altra classe. È possibile creare un oggetto e quindi utilizzarlo su altri oggetti.

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

Con l'esempio sopra, ho creato una classe chiamata staticFlag.

Questa classe dovrebbe presentare la variabile statica __success (Private Static Var).

La classe tryIt ha rappresentato la classe regolare che dobbiamo usare.

Ora ho creato un oggetto per un flag (staticFlag). Questo flag verrà inviato come riferimento a tutti gli oggetti normali.

Tutti questi oggetti vengono aggiunti all'elenco tryArr.


Questo script risultati:

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

Per evitare qualsiasi potenziale confusione, vorrei confrontare le variabili statiche e gli oggetti immutabili.

Alcuni tipi di oggetti primitivi come interi, float, stringhe e touples sono immutabili in Python. Ciò significa che l'oggetto a cui viene fatto riferimento con un nome specifico non può cambiare se appartiene a uno dei tipi di oggetto sopra menzionati. Il nome può essere riassegnato a un oggetto diverso, ma l'oggetto stesso non può essere modificato.

La creazione di una variabile statica fa un ulteriore passo in avanti disabilitando il nome della variabile in modo che punti a qualsiasi oggetto, ma quello a cui punta attualmente. (Nota: questo è un concetto di software generale e non specifico per Python, per favore vedi i post di altri per informazioni sull'implementazione delle statistiche in Python).

3
Ross

Sì, sicuramente possibile scrivere variabili e metodi statici in python.

Variabili statiche: Le variabili dichiarate a livello di classe sono chiamate variabili statiche a cui è possibile accedere direttamente utilizzando il nome della classe.

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

    >>> print(A.my_var)
        shagun

Variabili di istanza: Le variabili correlate e accessibili dall'istanza di una classe sono variabili di istanza.

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

Metodi statici: Simile alle variabili, è possibile accedere ai metodi statici direttamente utilizzando il nome della classe. Non c'è bisogno di creare un'istanza.

Ma tieni presente che un metodo statico non può chiamare un metodo non statico in python.

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

Variabili statiche in classe factory python3.6

Per chiunque usi una factory di classe con python3.6 e su usa la parola chiave nonlocal per aggiungerla all'ambito/contesto della classe creata in questo modo:

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