मुझे पायथन में वर्णक प्रोटोकॉल की सूक्ष्मता को समझने में थोड़ी सी मदद की ज़रूरत है, क्योंकि यह विशेष रूप से staticmethod
ऑब्जेक्ट्स के व्यवहार से संबंधित है। मैं एक छोटी सी उदाहरण के साथ iteratively शुरू करेंगे, और फिर इसे विस्तार, की जांच यह प्रत्येक चरण में व्यवहार है:कक्षा को सजाने के लिए डिस्क्रिप्टर प्रोटोकॉल क्यों तोड़ता है, इस प्रकार staticmethod ऑब्जेक्ट्स को अपेक्षित व्यवहार से रोकता है?
class Stub:
@staticmethod
def do_things():
"""Call this like Stub.do_things(), with no arguments or instance."""
print "Doing things!"
इस बिंदु पर, इस बर्ताव की उम्मीद के रूप में, लेकिन यहाँ क्या हो रहा है थोड़ा सूक्ष्म है: जब आप Stub.do_things()
पर कॉल करें, आप सीधे do_things का आह्वान नहीं कर रहे हैं। इसके बजाय, Stub.do_things
एक staticmethod
उदाहरण को संदर्भित करता है, जिसने हम अपने स्वयं के वर्णनकर्ता प्रोटोकॉल के अंदर जो फ़ंक्शन चाहते हैं उसे लपेट लिया है, जैसे कि आप वास्तव में staticmethod.__get__
का आविष्कार कर रहे हैं, जो पहले हम जिस फ़ंक्शन को चाहते हैं उसे वापस लौटाते हैं, और तब बाद में कॉल किया जाता है।
>>> Stub
<class __main__.Stub at 0x...>
>>> Stub.do_things
<function do_things at 0x...>
>>> Stub.__dict__['do_things']
<staticmethod object at 0x...>
>>> Stub.do_things()
Doing things!
अब तक इतना अच्छा है। इसके बाद, मैं एक डेकोरेटर उस वर्ग इन्स्टेन्शियशन अनुकूलित करने के लिए उपयोग किया जाएगा में वर्ग रैप करने के लिए की जरूरत है - डेकोरेटर निर्धारित करेगा कि क्या नया instantiations अनुमति देने के लिए या कैश की गई उदाहरणों प्रदान: अब
def deco(cls):
def factory(*args, **kwargs):
# pretend there is some logic here determining
# whether to make a new instance or not
return cls(*args, **kwargs)
return factory
@deco
class Stub:
@staticmethod
def do_things():
"""Call this like Stub.do_things(), with no arguments or instance."""
print "Doing things!"
, स्वाभाविक रूप से इस भाग के रूप में-है staticmethods तोड़ने की उम्मीद की जाएगी, क्योंकि कक्षा अब इसके सजावट के पीछे छिपी हुई है, यानी Stub
बिल्कुल कक्षा नहीं है, लेकिन factory
का एक उदाहरण है जो Stub
के उदाहरणों को उत्पन्न करने में सक्षम है। वास्तव में:
>>> Stub
<function factory at 0x...>
>>> Stub.do_things
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'function' object has no attribute 'do_things'
>>> Stub()
<__main__.Stub instance at 0x...>
>>> Stub().do_things
<function do_things at 0x...>
>>> Stub().do_things()
Doing things!
अब तक मैं समझता हूं कि यहां क्या हो रहा है। मेरा लक्ष्य staticmethods
की कार्यक्षमता को पुनर्स्थापित करने के लिए है, जैसा कि आप उन्हें उम्मीद करेंगे, भले ही कक्षा लपेटी हो। भाग्य के रूप में, पाइथन stdlib में functools नामक कुछ शामिल है, जो केवल इस उद्देश्य के लिए कुछ औजार प्रदान करता है, यानी, फ़ंक्शन को अन्य कार्यों की तरह व्यवहार करने की तरह व्यवहार करता है। तो मैं इस तरह देखने के लिए मेरी डेकोरेटर बदलने: अब
def deco(cls):
@functools.wraps(cls)
def factory(*args, **kwargs):
# pretend there is some logic here determining
# whether to make a new instance or not
return cls(*args, **kwargs)
return factory
, बातें दिलचस्प पाने के लिए शुरू:
>>> Stub
<function Stub at 0x...>
>>> Stub.do_things
<staticmethod object at 0x...>
>>> Stub.do_things()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'staticmethod' object is not callable
>>> Stub()
<__main__.Stub instance at 0x...>
>>> Stub().do_things
<function do_things at 0x...>
>>> Stub().do_things()
Doing things!
प्रतीक्षा .... क्या?functools
रैपिंग फ़ंक्शन पर staticmethod की प्रतिलिपि बनाता है, लेकिन यह कॉल करने योग्य नहीं है? क्यों नहीं? मुझे यहाँ क्या याद आया?
मैं थोड़ी देर के लिए इसके साथ खेल रहा था और मैं वास्तव में staticmethod
के अपने स्वयं के पुनर्मूल्यांकन के साथ आया था जो इसे इस स्थिति में काम करने की अनुमति देता है, लेकिन मुझे वास्तव में समझ में नहीं आता कि यह क्यों जरूरी था या यदि यह भी है इस समस्या का सबसे अच्छा समाधान।
class staticmethod(object):
"""Make @staticmethods play nice with decorated classes."""
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
"""Provide the expected behavior inside decorated classes."""
return self.func(*args, **kwargs)
def __get__(self, obj, objtype=None):
"""Re-implement the standard behavior for undecorated classes."""
return self.func
def deco(cls):
@functools.wraps(cls)
def factory(*args, **kwargs):
# pretend there is some logic here determining
# whether to make a new instance or not
return cls(*args, **kwargs)
return factory
@deco
class Stub:
@staticmethod
def do_things():
"""Call this like Stub.do_things(), with no arguments or instance."""
print "Doing things!"
वास्तव में यह बिल्कुल के रूप में की उम्मीद काम करता है:: यहाँ पूरा उदाहरण है
>>> Stub
<function Stub at 0x...>
>>> Stub.do_things
<__main__.staticmethod object at 0x...>
>>> Stub.do_things()
Doing things!
>>> Stub()
<__main__.Stub instance at 0x...>
>>> Stub().do_things
<function do_things at 0x...>
>>> Stub().do_things()
Doing things!
क्या दृष्टिकोण आप एक सजाया वर्ग के भीतर की उम्मीद के रूप में एक staticmethod व्यवहार बनाने के लिए ले जाएगा? क्या यह सबसे अच्छा तरीका है? अंतर्निहित staticmethod __call__
को अपने आप पर क्यों लागू नहीं करता है ताकि यह बिना किसी झगड़े के काम कर सके?
धन्यवाद।
def deco(cls):
class factory(cls):
def __new__(cls_factory, *args, **kwargs):
# pretend there is some logic here determining
# whether to make a new instance or not
return cls.__new__(*args, **kwargs)
return factory
है कि यह करना चाहिए:
क्लास विधि का उपयोग क्यों नहीं करें? इसे एक ही तरीके से कहा जा सकता है, लेकिन यह अधिक शक्तिशाली है और (I * think *) इस और अन्य मेटाप्रोग्रामिंग के साथ अधिक संगत है। – delnan
यह मेरे लिए 'classmethod 'का उपयोग करने के लिए हुआ, हालांकि वे या तो कॉल करने योग्य नहीं हैं (जिसका अर्थ है कि यह वही समस्या है जो मैं वर्तमान में कर रहा हूं), और यह भी कि क्योंकि मैं कुछ हद तक' Stub.class_attribute का संदर्भ देने के स्पष्टीकरण की तरह हूं '' classmethod' के अंदर 'cls.class_attribute' के बजाय' staticmethod' के अंदर '। – robru