python - स्थिर वर्ग चर संभव हैं?
class methods (11)
क्या पाइथन में स्थिर वर्ग चर या विधियां हो सकती हैं? ऐसा करने के लिए क्या वाक्यविन्यास की आवश्यकता है?
क्लास फैक्ट्री में स्टेटिक वेरिएबल्स पायथन 3.6
किसी भी व्यक्ति के लिए python3.6 के साथ क्लास फैक्ट्री का उपयोग करने के लिए और nonlocal
लोकल कीवर्ड का उपयोग उस वर्ग के दायरे / संदर्भ में जोड़ने के लिए करें:
>>> 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
स्टेटिक और क्लास तरीके
जैसा कि अन्य उत्तरों ने ध्यान दिया है, अंतर्निहित सजावटी का उपयोग करके स्थिर और वर्ग विधियों को आसानी से पूरा किया जाता है:
class Test(object):
# regular instance method:
def MyMethod(self):
pass
# class method:
@classmethod
def MyClassMethod(klass):
pass
# static method:
@staticmethod
def MyStaticMethod():
pass
हमेशा की तरह, MyMethod()
लिए पहला तर्क क्लास इंस्टेंस ऑब्जेक्ट से जुड़ा हुआ है। इसके विपरीत, MyClassMethod()
लिए पहला तर्क क्लास ऑब्जेक्ट से ही जुड़ा हुआ है (उदाहरण के लिए, इस मामले में, Test
)। MyStaticMethod()
, कोई भी तर्क बाध्य नहीं है, और तर्क भी बिल्कुल वैकल्पिक है।
"स्टेटिक वैरिएबल"
हालांकि, "स्थैतिक चर" को लागू करना (अच्छी तरह से, परिवर्तनीय स्थैतिक चर, वैसे भी, यदि यह शर्तों में विरोधाभास नहीं है ...) सीधे आगे नहीं है। चूंकि मिलरदेव ने अपने जवाब में बताया , समस्या यह है कि पायथन के वर्ग गुण वास्तव में "स्थैतिक चर" नहीं हैं। विचार करें:
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
ऐसा इसलिए है क्योंकि लाइन xi = 12
ने Test
क्लास i
विशेषता के मान को बदलने के बजाय x
को एक नया इंस्टेंस विशेषता जोड़ा है।
आंशिक अपेक्षित स्थैतिक चर व्यवहार, यानी, कई उदाहरणों के बीच विशेषता का समन्वय (लेकिन कक्षा के साथ नहीं ; नीचे "गॉचा" देखें), वर्ग गुण को किसी संपत्ति में बदलकर हासिल किया जा सकता है:
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)
अब आप कर सकते हैं:
x1 = Test()
x2 = Test()
x1.i = 50
assert x2.i == x1.i # no error
assert x2.i == 50 # the property is synced
स्थैतिक चर अब सभी वर्ग के उदाहरणों के बीच सिंक में रहेगा।
(नोट: वह तब तक है जब तक कि एक क्लास इंस्टेंस _i
अपने संस्करण को परिभाषित करने का फैसला नहीं करता है! लेकिन अगर कोई ऐसा करने का फैसला करता है, तो वे जो भी प्राप्त करते हैं उसके लायक होते हैं, है ना?)
ध्यान दें कि तकनीकी रूप से बोलते हुए, i
अभी भी 'स्थिर चर' नहीं हूं; यह एक property
, जो एक विशेष प्रकार का वर्णनकर्ता है। हालांकि, property
व्यवहार अब सभी वर्ग उदाहरणों में समन्वयित (म्यूटेबल) स्थैतिक चर के बराबर है।
अपरिवर्तनीय "स्टेटिक वैरिएबल"
अपरिवर्तनीय स्थैतिक चर व्यवहार के लिए, बस 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)
अब i
विशेषता उदाहरण सेट करने का प्रयास कर रहा i
एक AttributeError
:
x = Test()
assert x.i == 3 # success
x.i = 12 # ERROR
एक Gotcha के बारे में पता होना चाहिए
ध्यान दें कि उपर्युक्त विधियां केवल आपकी कक्षा के उदाहरणों के साथ काम करती हैं - कक्षा का उपयोग करते समय वे काम नहीं करेंगे। तो उदाहरण के लिए:
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'
लाइन assert Test.i == xi
एक त्रुटि उत्पन्न करता है, क्योंकि i
Test
और x
की विशेषता दो अलग-अलग वस्तुएं हैं।
बहुत से लोगों को यह आश्चर्यजनक लगेगा। हालांकि, यह नहीं होना चाहिए। अगर हम वापस जाते हैं और हमारी Test
क्लास परिभाषा (दूसरा संस्करण) का निरीक्षण करते हैं, तो हम इस पंक्ति पर ध्यान देते हैं:
i = property(get_i)
जाहिर है, Test
का सदस्य i
एक property
वस्तु होना चाहिए, जो property
समारोह से लौटाई गई वस्तु का प्रकार है।
यदि आपको उपर्युक्त भ्रमित लगता है, तो आप अभी भी अन्य भाषाओं (जैसे जावा या सी ++) के परिप्रेक्ष्य से इसके बारे में सोच रहे हैं। आपको उस ऑब्जेक्ट के बारे में property
ऑब्जेक्ट का अध्ययन करना चाहिए जिसमें पाइथन गुण लौटाए जाते हैं, वर्णनकर्ता प्रोटोकॉल, और विधि समाधान आदेश (एमआरओ)।
मैं उपरोक्त 'गॉचा' के लिए एक समाधान प्रस्तुत करता हूं; हालांकि मैं सुझाव assert Test.i = xi
- assert Test.i = xi
- कि आप निम्न की तरह कुछ करने की कोशिश नहीं करते - कम से कम - आप पूरी तरह से समझते हैं कि क्यों assert Test.i = xi
एक त्रुटि का कारण बनता है।
असली, वास्तविक स्थिर चर - Test.i == xi
मैं केवल जानकारी के उद्देश्यों के लिए नीचे (पायथन 3) समाधान प्रस्तुत करता हूं। मैं इसे "अच्छा समाधान" के रूप में समर्थन नहीं दे रहा हूं। मुझे अपने संदेह हैं कि पाइथन में अन्य भाषाओं के स्थिर परिवर्तनीय व्यवहार को अनुकरण करना वास्तव में आवश्यक है। हालांकि, इस पर ध्यान दिए बिना कि यह वास्तव में उपयोगी है या नहीं, नीचे दी जानी चाहिए कि पाइथन कैसे काम करता है।
अद्यतन: यह प्रयास वास्तव में बहुत भयानक है ; यदि आप इस तरह कुछ करने का आग्रह करते हैं (संकेत: कृपया नहीं; पाइथन एक बहुत ही सुरुचिपूर्ण भाषा है और जूता-इसे किसी अन्य भाषा की तरह व्यवहार करने में जरूरी नहीं है), इसके बजाय एथन फर्मन के जवाब में कोड का उपयोग करें।
मेटाक्लास का उपयोग करके अन्य भाषाओं के स्थैतिक चर व्यवहार का अनुकरण करना
एक मेटाक्लास एक वर्ग की कक्षा है। पायथन में सभी वर्गों के लिए डिफ़ॉल्ट मेटाक्लास (यानी, "नई शैली" कक्षाओं के बाद पायथन 2.3 मुझे विश्वास है) type
। उदाहरण के लिए:
type(int) # class 'type'
type(str) # class 'type'
class Test(): pass
type(Test) # class 'type'
हालांकि, आप इस तरह अपने मेटाक्लास को परिभाषित कर सकते हैं:
class MyMeta(type): pass
और इसे अपनी खुद की कक्षा में लागू करें (केवल पायथन 3):
class MyClass(metaclass = MyMeta):
pass
type(MyClass) # class MyMeta
नीचे एक मेटाक्लास है जिसे मैंने बनाया है जो अन्य भाषाओं के "स्थैतिक चर" व्यवहार को अनुकरण करने का प्रयास करता है। यह मूल रूप से डिफॉल्ट गेटर, सेटर और डिलीटर को उन संस्करणों के साथ बदलकर काम करता है जो यह देखने के लिए जांचते हैं कि क्या विशेषता का अनुरोध किया जा रहा है "स्थिर चर" है।
"स्थिर चर" की एक सूची StaticVarMeta.statics
विशेषता में संग्रहीत है। सभी विशेषता अनुरोधों को शुरू में एक विकल्प संकल्प आदेश का उपयोग करके हल करने का प्रयास किया जाता है। मैंने इसे "स्थिर संकल्प आदेश" या "एसआरओ" कहा है। यह किसी दिए गए वर्ग (या उसके मूल वर्ग) के लिए "स्थैतिक चर" के सेट में अनुरोधित विशेषता की तलाश करके किया जाता है। यदि विशेषता "एसआरओ" में प्रकट नहीं होती है, तो कक्षा डिफ़ॉल्ट विशेषता पर वापस आ जाएगी / व्यवहार / हटाएं (यानी, "एमआरओ")।
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
आप फ्लाई पर कक्षाओं में कक्षा चर भी जोड़ सकते हैं
>>> 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
और कक्षा के उदाहरण वर्ग चर बदल सकते हैं
class X:
l = []
def __init__(self):
self.l.append(1)
print X().l
print X().l
>python test.py
[1]
[1, 1]
आप मेटाक्लास का उपयोग करके स्थिर होने के लिए कक्षा को भी लागू कर सकते हैं।
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
फिर जब भी आप दुर्घटना से MyClass प्रारंभ करने का प्रयास करते हैं तो आपको एक StaticClassError मिल जाएगा।
कक्षा परिभाषा के अंदर घोषित चर, लेकिन एक विधि के अंदर वर्ग या स्थैतिक चर नहीं हैं:
>>> class MyClass:
... i = 3
...
>>> MyClass.i
3
चूंकि @ millerdev बताते हैं, यह कक्षा-स्तर i
चर बनाता है, लेकिन यह किसी भी आवृत्ति-स्तर i
चर से अलग है, इसलिए आप हो सकते हैं
>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)
यह सी ++ और जावा से अलग है, लेकिन सी # से इतना अलग नहीं है, जहां एक स्थिर सदस्य को किसी उदाहरण के संदर्भ में उपयोग नहीं किया जा सकता है।
देखें कि पाइथन ट्यूटोरियल कक्षाओं और वर्ग वस्तुओं के विषय पर क्या कहना है ।
@ स्टेव जॉनसन ने पहले से ही स्थिर तरीकों के बारे में उत्तर दिया है, जो पाइथन लाइब्रेरी संदर्भ में "अंतर्निहित कार्यों" के तहत भी दस्तावेज किया गया है ।
class C:
@staticmethod
def f(arg1, arg2, ...): ...
@beidy क्लासमेड्स को classmethod पर अनुशंसा करता है, क्योंकि विधि को कक्षा के पहले तर्क के रूप में प्राप्त होता है, लेकिन मैं अभी भी staticmethod पर इस दृष्टिकोण के फायदों पर थोड़ा अस्पष्ट हूं। यदि आप भी हैं, तो शायद इससे कोई फर्क नहीं पड़ता।
किसी भी संभावित भ्रम से बचने के लिए, मैं स्थैतिक चर और अपरिवर्तनीय वस्तुओं को विपरीत बनाना चाहता हूं।
पाइथन में कुछ प्राचीन वस्तु प्रकार जैसे पूर्णांक, फ्लोट, तार और स्पर्श अपरिवर्तनीय हैं। इसका अर्थ यह है कि किसी दिए गए नाम से संदर्भित ऑब्जेक्ट को तब नहीं बदला जा सकता है जब यह उपरोक्त ऑब्जेक्ट प्रकारों में से एक है। नाम को किसी भिन्न ऑब्जेक्ट पर पुन: असाइन किया जा सकता है, लेकिन ऑब्जेक्ट स्वयं ही बदला नहीं जा सकता है।
परिवर्तनीय स्थैतिक बनाना किसी ऑब्जेक्ट को इंगित करने के लिए वेरिएबल नाम को अस्वीकार कर एक कदम आगे ले जाता है लेकिन यह वर्तमान में इंगित करता है। (नोट: यह एक सामान्य सॉफ्टवेयर अवधारणा है और पायथन के लिए विशिष्ट नहीं है; कृपया पाइथन में स्टेटिक्स को लागू करने के बारे में जानकारी के लिए दूसरों की पोस्ट देखें)।
नीचे दिए गए उदाहरण में दिखाए गए स्थिर गुणों और उदाहरण गुणों के बारे में ध्यान देने योग्य एक विशेष बात:
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
इसका मतलब है आवृत्ति संपत्ति के मूल्य को निर्दिष्ट करने से पहले, यदि हम 'उदाहरण के माध्यम से संपत्ति तक पहुंचने का प्रयास करते हैं, तो स्थिर मान का उपयोग किया जाता है। पाइथन कक्षा में घोषित प्रत्येक संपत्ति में हमेशा स्मृति में एक स्थिर स्लॉट होता है ।
पाइथन की विशेषता लुकअप के बारे में एक बहुत ही रोचक बिंदु यह है कि इसका उपयोग " virtual चर" बनाने के लिए किया जा सकता है:
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!
आम तौर पर बनाए जाने के बाद इन्हें कोई असाइनमेंट नहीं होता है। ध्यान दें कि लुकअप self
का उपयोग करता है क्योंकि, हालांकि किसी विशेष उदाहरण से जुड़े नहीं होने के अर्थ में label
स्थिर है, मान अभी भी (वर्ग की) उदाहरण पर निर्भर करता है।
बिल्कुल हां, पाइथन के पास स्पष्ट रूप से कोई स्थिर डेटा सदस्य नहीं है, लेकिन हम ऐसा करके कर सकते हैं
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())
उत्पादन
0
0
1
1
व्याख्या
here object (x) alone increment the counter variable
from 0 to 1 by not object y. But result it as "static counter"
मुझे मिला सबसे अच्छा तरीका एक और वर्ग का उपयोग करना है। आप एक ऑब्जेक्ट बना सकते हैं और फिर इसे अन्य ऑब्जेक्ट्स पर इस्तेमाल कर सकते हैं।
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()
उपरोक्त उदाहरण के साथ, मैंने staticFlag
नामक एक वर्ग बनाया है।
इस वर्ग को स्थिर var __success
(निजी स्टेटिक वार) प्रस्तुत करना चाहिए।
tryIt
कक्षा ने नियमित कक्षा का प्रतिनिधित्व किया जिसे हमें उपयोग करने की आवश्यकता है।
अब मैंने एक झंडा ( staticFlag
) के लिए एक वस्तु बनाई है। यह ध्वज सभी नियमित वस्तुओं के संदर्भ के रूप में भेजा जाएगा।
इन सभी वस्तुओं को tryArr
सूची में जोड़ा जा रहा है।
यह स्क्रिप्ट परिणाम:
False
False
False
False
False
True
True
True
True
True
static
वर्ग चर होना संभव है, लेकिन शायद प्रयास के लायक नहीं है।
यहां पाइथन 3 में लिखा गया एक सबूत-अवधारणा है - यदि कोई सटीक विवरण गलत है तो कोड को static variable
द्वारा जो भी मतलब है, उसके बारे में मिलान करने के लिए कोड को tweaked किया जा सकता है:
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)
और उपयोग में:
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')
और कुछ परीक्षण:
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