[Python] स्थिर वर्ग चर संभव हैं?


Answers

@ ब्लेयर कॉनराड ने कहा कि कक्षा परिभाषा के अंदर घोषित स्थैतिक चर, लेकिन एक विधि के अंदर वर्ग या "स्थैतिक" चर नहीं हैं:

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

यहां कुछ गॉचा हैं। ऊपर दिए गए उदाहरण से आगे बढ़ना:

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

ध्यान दें कि जब आवृत्ति i सीधे t पर सेट की गई थी, तो "स्थिर" वर्ग चर के साथ इंस्टेंस वैरिएबल ti सिंक हो गया था। ऐसा इसलिए है क्योंकि i t नेमस्पेस के भीतर फिर से बंधे थे, जो Test नेमस्पेस से अलग है। यदि आप "स्थैतिक" चर के मान को बदलना चाहते हैं, तो आपको इसे दायरे (या ऑब्जेक्ट) में बदलना चाहिए जहां इसे मूल रूप से परिभाषित किया गया था। मैंने उद्धरणों में "स्थिर" रखा क्योंकि पाइथन में वास्तव में स्थिर चर नहीं हैं क्योंकि सी ++ और जावा करते हैं।

हालांकि यह स्थैतिक चर या विधियों के बारे में कुछ भी विशिष्ट नहीं कहता है, लेकिन पाइथन ट्यूटोरियल में कक्षाओं और वर्ग वस्तुओं पर कुछ प्रासंगिक जानकारी है।

@ स्टेव जॉनसन ने पाइथन लाइब्रेरी रेफरेंस में "बिल्ट-इन फ़ंक्शंस" के तहत भी स्टैटिक विधियों के बारे में उत्तर दिया।

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

@beid ने classmethod का भी उल्लेख किया है, जो staticmethod के समान है। क्लासमेड का पहला तर्क क्लास ऑब्जेक्ट है। उदाहरण:

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

Question

क्या पाइथन में स्थिर वर्ग चर या विधियां हो सकती हैं? ऐसा करने के लिए क्या वाक्यविन्यास की आवश्यकता है?




मुझे मिला सबसे अच्छा तरीका एक और वर्ग का उपयोग करना है। आप एक ऑब्जेक्ट बना सकते हैं और फिर इसे अन्य ऑब्जेक्ट्स पर इस्तेमाल कर सकते हैं।

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



पायथन में स्थिर तरीकों को classmethod एस कहा जाता है। निम्नलिखित कोड पर एक नज़र डालें

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 विधि को कॉल करते हैं, तो हमें एक त्रुटि मिलती है। ऐसा इसलिए है क्योंकि इस वर्ग के उदाहरण पर उस विधि को बुलाया जाना आवश्यक है। विधि myStaticMethod को सजावटी @classmethod का उपयोग करके क्लासमेड के रूप में सेट किया गया है।

सिर्फ किक्स और गिगल्स के लिए, हम क्लास के उदाहरण में गुजरकर कक्षा में myInstanceMethod को कॉल कर सकते हैं, जैसे:

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



जब किसी भी सदस्य विधि के बाहर कुछ सदस्य चर परिभाषित करते हैं, चर वैरिएबल व्यक्त किए जाने के आधार पर वैरिएबल या तो स्थैतिक या गैर स्थैतिक हो सकता है।

  • CLASSNAME.var स्थिर चर है
  • INSTANCENAME.var स्थिर चर नहीं है।
  • वर्ग के अंदर self.var स्थिर चर नहीं है।
  • कक्षा सदस्य समारोह के अंदर var परिभाषित नहीं किया गया है।

उदाहरण के लिए:

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

परिणाम हैं

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



आप फ्लाई पर कक्षाओं में कक्षा चर भी जोड़ सकते हैं

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



क्लास फैक्ट्री में स्टेटिक वेरिएबल्स पायथन 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



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



पाइथन की विशेषता लुकअप के बारे में एक बहुत ही रोचक बिंदु यह है कि इसका उपयोग " 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 स्थिर है, मान अभी भी (वर्ग की) उदाहरण पर निर्भर करता है।