Python'da statik sınıf değişkenleri veya yöntemleri olabilir mi? Bunu yapmak için hangi sözdizimi gereklidir?
Python'da statik sınıf değişkenleri veya yöntemleri olabilir mi? Bunu yapmak için hangi sözdizimi gereklidir?
Yanıtlar:
Sınıf tanımının içinde bildirilen ancak bir yöntem içinde belirtilmeyen değişkenler sınıf veya statik değişkenlerdir:
>>> class MyClass:
... i = 3
...
>>> MyClass.i
3
@ Millerdev'in işaret ettiği gibi , bu, sınıf düzeyinde bir i
değişken oluşturur, ancak bu, herhangi bir örnek düzeyi i
değişkeninden farklıdır , bu nedenle
>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)
Bu, C ++ ve Java'dan farklıdır, ancak bir örneğe başvuru kullanılarak statik bir üyeye erişilemediği C # 'dan çok farklı değildir.
Sınıflar ve sınıf nesneleri konusunda Python öğreticisinin neler söylediğine bakın .
@Steve Johnson, Python Kütüphanesi Referansında "Yerleşik İşlevler" altında da belgelenen statik yöntemlerle ilgili olarak zaten yanıt verdi .
class C:
@staticmethod
def f(arg1, arg2, ...): ...
@beidy , yöntem daha sonra sınıf argümanını ilk argüman olarak aldığından, staticmethod üzerinden classmethod'ları önerir , ancak hala staticmethod'a göre bu yaklaşımın avantajları üzerinde biraz bulanıkım. Siz de iseniz, muhtemelen önemli değil.
const.py
var PI = 3.14
ve her yere aktarabilirsiniz. from const import PI
i = 3
bir değil bir sınıf niteliği olduğunu ve bir örnek düzeyi özniteliği ayrı olmasından dolayı, statik bir değişken i
o mu değil diğer dillerde statik değişken gibi davranır. Bkz millerdev yanıtını , Yann'ın cevabı ve benim cevap aşağıda.
i
Bu sınıfın yüzlerce örneğini oluştursam bile (statik değişken) yalnızca bir kopyası bellekte olacak?
@Blair Conrad, sınıf tanımında bildirilen ancak bir yöntem içinde belirtilmeyen statik değişkenlerin sınıf veya "statik" değişkenler olduğunu söyledi:
>>> class Test(object):
... i = 3
...
>>> Test.i
3
Burada birkaç tane yakaladım. Yukarıdaki örnekten devam etmek:
>>> 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__
{}
t.i
Öznitelik i
doğrudan ayarlandığında örnek değişkeninin "statik" sınıf değişkeni ile nasıl senkronize olmadığına dikkat edin t
. Bunun nedeni i
, t
ad alanından farklı olan ad alanı içinde yeniden bağlanmış olmasıdır Test
. "Statik" bir değişkenin değerini değiştirmek istiyorsanız, değişkeni orijinal olarak tanımlandığı kapsam (veya nesne) içinde değiştirmeniz gerekir. Ben "statik" tırnak koymak çünkü Python gerçekten C ++ ve Java yapmak anlamında statik değişkenler yok.
Statik değişkenler veya yöntemler hakkında spesifik bir şey söylemese de, Python öğreticisinde sınıflar ve sınıf nesneleri ile ilgili bazı bilgiler bulunur .
@Steve Johnson, Python Kütüphanesi Referansında "Yerleşik İşlevler" altında da belgelenen statik yöntemlerle ilgili olarak cevap verdi.
class Test(object):
@staticmethod
def f(arg1, arg2, ...):
...
@, aynı zamanda, statik metoda benzer sınıf metodundan da bahsetmiştir. Bir sınıf yönteminin ilk argümanı sınıf nesnesidir. Misal:
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 be the same as Test.i = arg1
class Test(object):
, _i = 3
, @property
, def i(self)
, return type(self)._i
, @i.setter
, def i(self,val):
, type(self)._i = val
. Şimdi yapabilirsiniz x = Test()
, x.i = 12
, assert x.i == Test.i
.
Diğer cevapların belirttiği gibi, statik ve sınıf yöntemleri yerleşik dekoratörler kullanılarak kolayca gerçekleştirilir:
class Test(object):
# regular instance method:
def MyMethod(self):
pass
# class method:
@classmethod
def MyClassMethod(klass):
pass
# static method:
@staticmethod
def MyStaticMethod():
pass
Her zamanki gibi, ilk argüman MyMethod()
sınıf örneği nesnesine bağlıdır. Bunun aksine, ilk değişken için MyClassMethod()
olan sınıf nesnesine bağlı (bu durumda, örneğin Test
). Çünkü MyStaticMethod()
, argümanların hiçbiri bağlı değildir ve hiçbir argümana sahip olmak isteğe bağlıdır.
Ancak, "statik değişkenler" (iyi, değişebilir statik değişkenler, her neyse, eğer bu bir çelişki değilse ...) uygulamak o kadar da ileri değildir. Millerdev'in cevabında belirttiği gibi , sorun Python'un sınıf özelliklerinin gerçekten "statik değişkenler" olmamasıdır. Düşünmek:
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
Çizgi Bunun nedeni, x.i = 12
yeni bir örnek özelliğini eklemiştir i
için x
yerine değerinin değiştirilmesi Test
sınıfı i
öznitelik.
Kısmi beklenen statik değişken davranışı, yani (ama birden çok örneği arasında özelliğinin senkronize olmayan sınıfın kendisi ile; "yakaladım" bkz aşağıda), bir mülkte class özelliği çevirerek elde edilebilir:
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)
Şimdi şunları yapabilirsiniz:
x1 = Test()
x2 = Test()
x1.i = 50
assert x2.i == x1.i # no error
assert x2.i == 50 # the property is synced
Statik değişken artık tüm sınıf örnekleri arasında senkronize kalacaktır .
(NOT: Yani, bir sınıf örneği kendi sürümünü tanımlamaya karar vermedikçe _i
! Ama birisi bunu yapmaya karar verirse, aldıklarını hak ederler, değil mi ???)
Teknik olarak konuşmanın i
hala bir 'statik değişken' olmadığını unutmayın ; Bir olan property
tanımlayıcısı özel bir türü olan. Ancak, property
davranış şimdi tüm sınıf örnekleri arasında eşitlenmiş (değişken) statik değişkene eşdeğerdir.
Değişmez statik değişken davranış için property
ayarlayıcıyı atlayın :
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)
Şimdi örnek i
niteliğini ayarlamaya çalışmak aşağıdakileri döndürür AttributeError
:
x = Test()
assert x.i == 3 # success
x.i = 12 # ERROR
Yukarıdaki yöntemler ile sadece iş o Not örnekleri bunlar olacak - sınıfınızın değil işin sınıfını kendisi kullanarak . Yani mesela:
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'
Çizgi assert Test.i == x.i
için, bir hata üretir i
niteliği Test
ve x
iki farklı nesneleridir.
Birçok insan bunu şaşırtıcı bulacaktır. Ancak, olmamalı. Geri dönüp Test
sınıf tanımımızı (ikinci sürüm) incelersek, bu satırı not ederiz:
i = property(get_i)
Açıktır ki, eleman i
arasında Test
mutlaka bir olmak property
dönen nesne türü bir amacı, property
fonksiyon.
Yukarıda kafa karıştırıcı bulursanız, büyük olasılıkla hala diğer diller açısından (örneğin Java veya c ++) düşünüyorsunuz. Sen incelemek gitmeli property
Python nitelikleri iade sırayla, açıklayıcısı protokolü ve yöntem çözünürlüğü sırayla (MRO) hakkında nesne.
Ben aşağıda yukarıdaki 'gotcha' için bir çözüm sunuyoruz; ancak - yorucu bir şekilde - en azından assert Test.i = x.i
neden bir hataya neden olduğunu anlayana kadar aşağıdaki gibi bir şey yapmaya çalışmamanızı öneririm .
Test.i == x.i
Aşağıdaki (Python 3) çözümünü yalnızca bilgilendirme amacıyla sunuyorum. Ben bunu "iyi bir çözüm" olarak kabul etmiyorum. Python'daki diğer dillerin statik değişken davranışlarını taklit etmenin gerçekten gerekli olup olmadığı konusunda şüphelerim var. Bununla birlikte, gerçekten yararlı olup olmadığına bakılmaksızın, aşağıdakiler Python'un nasıl çalıştığını daha iyi anlamaya yardımcı olmalıdır.
GÜNCELLEME: bu girişim gerçekten çok korkunç ; eğer böyle bir şey yapmakta ısrar ediyorsanız (ipucu: lütfen yapma; Python çok zarif bir dildir ve ayakkabı dilini başka bir dil gibi davranmak zorunda değildir), bunun yerine Ethan Furman'ın cevabındaki kodu kullanın.
Metasınıf kullanarak diğer dillerin statik değişken davranışlarını taklit etme
Metasınıf bir sınıfın sınıfıdır. Python'daki tüm sınıflar için varsayılan metasınıf (yani "yeni stil" sınıfları Python 2.3 sonrası inanıyorum) type
. Örneğin:
type(int) # class 'type'
type(str) # class 'type'
class Test(): pass
type(Test) # class 'type'
Ancak, kendi metasınıfınızı şu şekilde tanımlayabilirsiniz:
class MyMeta(type): pass
Ve bunu kendi sınıfınıza uygulayın (yalnızca Python 3):
class MyClass(metaclass = MyMeta):
pass
type(MyClass) # class MyMeta
Aşağıda, diğer dillerin "statik değişken" davranışını taklit etmeye çalışan bir metasınıf var. Temel olarak, varsayılan alıcı, ayarlayıcı ve silmeyi, istenen özniteliğin "statik değişken" olup olmadığını kontrol eden sürümlerle değiştirerek çalışır.
"Statik değişkenler" kataloğu StaticVarMeta.statics
öznitelikte saklanır . Tüm öznitelik istekleri başlangıçta yedek çözüm siparişi kullanılarak çözümlenmeye çalışılır. Bunu "statik çözünürlük sırası" veya "SRO" olarak adlandırdım. Bu, belirli bir sınıf (veya üst sınıfları) için "statik değişkenler" kümesinde istenen öznitelik aranarak yapılır. Öznitelik "SRO" da görünmezse, sınıf varsayılan öznitelik alma / ayarlama / silme davranışına (yani "MRO") geri döner.
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.__name__ + " 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.__name__ + " 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
Test
(örnekleme örnekleri için kullanmadan önce) yaptığınız her şeyi meta-programlama alanında görmelisiniz ? Örneğin, yaparak sınıf davranışını değiştirirsiniz Test.i = 0
(burada özellik nesnesini tamamen yok edersiniz). "Özellik-mekanizma" sadece bir sınıf örnekleri üzerinde özellik erişimi başladı (belki de bir meta-sınıf ara olarak kullanarak temel davranış değiştirmek sürece) sanırım. Btw, lütfen bu cevabı bitir :-)
Ayrıca sınıflara anında değişkenler ekleyebilirsiniz
>>> 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
Ve sınıf örnekleri sınıf değişkenlerini değiştirebilir
class X:
l = []
def __init__(self):
self.l.append(1)
print X().l
print X().l
>python test.py
[1]
[1, 1]
Statik bir yönteme ihtiyaç duyduğumda şahsen bir sınıf yöntemi kullanırdım. Temelde sınıfı bir argüman olarak aldığım için.
class myObj(object):
def myMethod(cls)
...
myMethod = classmethod(myMethod)
veya bir dekoratör kullanın
class myObj(object):
@classmethod
def myMethod(cls)
Statik özellikler için .. Onun zaman bazı python tanımı ararken .. değişken her zaman değişebilir. Değişken ve değişmez iki türü vardır .. Ayrıca, sınıf öznitelikleri ve örnek öznitelikleri vardır .. Hiçbir şey gerçekten java & c ++ anlamında statik öznitelikler gibi değil
Sınıfla herhangi bir ilişkisi yoksa neden statik yöntemi pythonic anlamında kullanın! Ben olsaydım ya classmethod kullanırdım ya da sınıftan bağımsız bir yöntem tanımlardım.
Aşağıdaki örnekte gösterilen statik özellikler ve örnek özellikler hakkında not edilmesi gereken özel bir şey:
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
Bu, örnek örneği özelliğine atamadan önce, örneğe özelliğe erişmeye çalışırsak statik değer kullanılır. Python sınıfında bildirilen her özelliğin her zaman bellekte statik bir yuvası vardır .
Pitondaki statik yöntemlere classmethod s denir . Aşağıdaki koda bir göz atın
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
MyInstanceMethod yöntemini çağırdığımızda bir hata aldığımızı göreceksiniz . Bunun nedeni, bu yöntemin bu sınıfın bir örneğinde çağrılmasını gerektirmesidir. MyStaticMethod yöntemi , dekoratör @classmethod kullanılarak bir sınıf yöntemi olarak ayarlanır .
Sadece tekmeler ve kıkırdamalar için, sınıfın bir örneğini ileterek sınıfa myInstanceMethod diyebiliriz :
>>> MyClass.myInstanceMethod(MyClass())
output from an instance method
@staticmethod
; @classmethod
(açıkçası) sınıf yöntemleri içindir (bunlar esas olarak alternatif kurucular olarak kullanılmak üzere tasarlanmıştır, ancak bir çimdik içinde çağrıldıkları sınıfa referans alan statik yöntemler olarak hizmet edebilir).
Herhangi bir üye yönteminin dışında bir üye değişken tanımlandığında, değişkenin nasıl ifade edildiğine bağlı olarak değişken statik veya statik olmayabilir.
Örneğin:
#!/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()
Sonuçlar
self.var is 2
A.var is 1
self.var is 2
A.var is 3
static
Sınıf değişkenlerine sahip olmak mümkündür , ama muhtemelen çabaya değmez.
İşte Python 3'te yazılmış bir kavram kanıtı - kesin detaylardan herhangi biri yanlışsa, kod, ne demek istediğinizle hemen hemen eşleşecek şekilde değiştirilebilir 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)
ve kullanımda:
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')
ve bazı testler:
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
Ayrıca, bir sınıfı metasınıf kullanarak statik olması için zorlayabilirsiniz.
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
Ne zaman yanlışlıkla MyClass başlatmaya çalıştığınızda bir StaticClassError alırsınız.
__new__
ebeveynlerini çağırmak için super () kullanmazlar ...
Python'un öznitelik aramasıyla ilgili çok ilginç bir nokta, " sanal değişkenler" oluşturmak için kullanılabilmesidir :
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!
Normalde, oluşturulduktan sonra bunlara herhangi bir atama yapılmaz. Belirli bir örnekle ilişkilendirilememesi anlamında statik self
olsa label
da , değerin yine de (sınıfının) örneğine bağlı olduğu için aramanın kullandığını unutmayın .
Bu cevapla ilgili olarak , sabit bir statik değişken için bir tanımlayıcı kullanabilirsiniz. İşte bir örnek:
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
sonuçlanan ...
small demo 10
small subdemo 100
big demo 10
big subdemo 10
Ayar değerini ( pass
yukarıda) sessizce göz ardı etmek sizin işiniz değilse her zaman bir istisna oluşturabilirsiniz . Bir C ++, Java stili statik sınıf değişkeni arıyorsanız:
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
Göz at Bu cevap ve resmi belgeler NASIL tanımlayıcıları hakkında daha fazla bilgi için.
@property
bir tanımlayıcı kullanmakla aynı olan kullanabilirsiniz , ancak çok daha az kod.
Kesinlikle Evet, Python'un kendi başına herhangi bir statik veri üyesi yoktur, ancak bunu yapabiliriz.
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())
çıktı
0
0
1
1
açıklama
here object (x) alone increment the counter variable
from 0 to 1 by not object y. But result it as "static counter"
Evet, python'a statik değişkenler ve yöntemler yazmak kesinlikle mümkündür.
Statik Değişkenler: Sınıf düzeyinde bildirilen değişkene, sınıf adı kullanılarak doğrudan erişilebilen statik değişken denir.
>>> class A:
...my_var = "shagun"
>>> print(A.my_var)
shagun
Örnek değişkenleri: Bir sınıf örneğiyle ilişkilendirilen ve erişilen değişkenler örnek değişkenleridir.
>>> a = A()
>>> a.my_var = "pruthi"
>>> print(A.my_var,a.my_var)
shagun pruthi
Statik Yöntemler: Değişkenlere benzer şekilde, statik yöntemlere doğrudan Sınıf Adı kullanılarak erişilebilir. Bir örnek oluşturmaya gerek yok.
Ancak unutmayın, statik bir yöntem python'da statik olmayan bir yöntemi çağıramaz.
>>> class A:
... @staticmethod
... def my_static_method():
... print("Yippey!!")
...
>>> A.my_static_method()
Yippey!!
Herhangi bir olası karışıklığı önlemek için, statik değişkenleri ve değişmez nesneleri karşılaştırmak istiyorum.
Tamsayılar, şamandıralar, dizgiler ve başlıklar gibi bazı ilkel nesne türleri Python'da değişmez. Bu, belirli bir adla atıfta bulunulan nesnenin, yukarıda belirtilen nesne türlerinden biriyse değişemeyeceği anlamına gelir. Ad farklı bir nesneye yeniden atanabilir, ancak nesnenin kendisi değiştirilemeyebilir.
Değişken statik yapmak, değişken isminin şu anda işaret ettiği herhangi bir nesneyi işaret etmesine izin vermeyerek bunu bir adım öteye taşır. (Not: Bu genel bir yazılım konseptidir ve Python'a özgü değildir; Python'da statik uygulama hakkında bilgi için lütfen başkalarının gönderilerine bakın).
Bulduğum en iyi yol başka bir sınıf kullanmak. Bir nesne oluşturabilir ve daha sonra diğer nesnelerde kullanabilirsiniz.
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()
Yukarıdaki örnekle, adlı bir sınıf yaptım staticFlag
.
Bu sınıf statik var __success
(Özel Statik Var) göstermelidir.
tryIt
sınıf, kullanmamız gereken normal sınıfı temsil ediyordu.
Şimdi bir bayrak ( staticFlag
) için bir nesne yaptım . Bu bayrak tüm normal nesnelere referans olarak gönderilecektir.
Tüm bu nesneler listeye ekleniyor tryArr
.
Bu Script Sonuçları:
False
False
False
False
False
True
True
True
True
True
Python3.6 ve üstü bir sınıf fabrikası kullanan herkes için nonlocal
anahtar kelimeyi kullanarak, oluşturulan sınıfın kapsamına / bağlamına aşağıdaki gibi ekleyin:
>>> 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
hasattr(SomeClass, 'x')
olduğunu False
. Herkes bu statik bir değişken tarafından ne anlama geliyor şüpheliyim.
some_var
, değişmez ve statik olarak tanımlanmış, yoksa değil mi? Dış alıcı erişiminin bir değişkenin statik olması ya da olmaması ile ne ilgisi var? Şimdi çok fazla sorum var. zaman geldiğinde bazı cevapları duymak isteriz.
some_var
yukarıdaki hiç bir sınıf üyesi değil. Python'da tüm sınıf üyelerine sınıfın dışından erişilebilir.
nonlocal
Keywoard değişken kapsamı "tümsekler". Sınıf gövdesi tanımının kapsamı nonlocal some_var
, yalnızca başka bir adlandırılmış nesneye yerel olmayan (okuma: sınıf tanımı kapsamında DEĞİL) ad başvurusu oluştururken kendi içinde bulduğu kapsamdan bağımsızdır . Bu nedenle, sınıf tanımına eklenmez, çünkü sınıf gövdesi kapsamında değildir.
Bu muhtemelen bir hack, ama ben eval(str)
piton 3'te statik bir nesne, biraz çelişki elde etmek için kullanıyorum .
class
Bazı bağımsız değişkenleri kaydeden statik yöntemlerle ve yapıcılarla tanımlanan nesnelerden başka hiçbir şeye sahip olmayan bir Records.py dosyası vardır . Sonra başka bir .py dosyasından ben import Records
ama dinamik olarak her nesneyi seçmek ve daha sonra okunan veri türüne göre istek üzerine somutlaştırmak gerekir.
Yani nerede object_name = 'RecordOne'
veya sınıf adı, ben çağırmak cur_type = eval(object_name)
ve sonra bunu örneklemek için cur_inst = cur_type(args)
Ancak , örnekleme önce statik cur_type.getName()
temelleri örneğin, soyut temel sınıf uygulaması gibi veya hedef ne olursa olsun çağırabilirsiniz . Ancak arka uçta, muhtemelen python içinde somutlaştırılır ve gerçekten statik değildir, çünkü eval bir nesne döndürüyor .... bu somutlaştırılmış olması gerekir .... statik benzeri davranış verir.
Örnekler arasında "statik davranış" elde etmek için bir liste veya sözlük kullanabilirsiniz.
class Fud:
class_vars = {'origin_open':False}
def __init__(self, origin = True):
self.origin = origin
self.opened = True
if origin:
self.class_vars['origin_open'] = True
def make_another_fud(self):
''' Generating another Fud() from the origin instance '''
return Fud(False)
def close(self):
self.opened = False
if self.origin:
self.class_vars['origin_open'] = False
fud1 = Fud()
fud2 = fud1.make_another_fud()
print (f"is this the original fud: {fud2.origin}")
print (f"is the original fud open: {fud2.class_vars['origin_open']}")
# is this the original fud: False
# is the original fud open: True
fud1.close()
print (f"is the original fud open: {fud2.class_vars['origin_open']}")
# is the original fud open: False
Örneğin, diğer örneklerde artırmak için statik bir değişkeni paylaşmaya çalışıyorsanız, bu komut dosyası gibi bir şey işe yarar:
# -*- coding: utf-8 -*-
class Worker:
id = 1
def __init__(self):
self.name = ''
self.document = ''
self.id = Worker.id
Worker.id += 1
def __str__(self):
return u"{}.- {} {}".format(self.id, self.name, self.document).encode('utf8')
class Workers:
def __init__(self):
self.list = []
def add(self, name, doc):
worker = Worker()
worker.name = name
worker.document = doc
self.list.append(worker)
if __name__ == "__main__":
workers = Workers()
for item in (('Fiona', '0009898'), ('Maria', '66328191'), ("Sandra", '2342184'), ('Elvira', '425872')):
workers.add(item[0], item[1])
for worker in workers.list:
print(worker)
print("next id: %i" % Worker.id)
@classmethod
üzerinde avantajları@staticmethod
her zaman bir alt sınıf olsa bile, yöntemin çağrıldığı sınıfın adını almak olmasıdır. Statik bir yöntemde bu bilgi yoktur, bu nedenle örneğin geçersiz kılınmış bir yöntem çağıramaz.