È possibile avere variabili o metodi di classe statici in python? Quale sintassi è richiesta per fare questo?
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.
@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
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.
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.
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
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.
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
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]
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.
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
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 .
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.
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
È 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
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.
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).
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"
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.
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
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).
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!!
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