जवाबों:
पायथन में, कार्यों और बाध्य विधियों के बीच अंतर है।
>>> def foo():
... print "foo"
...
>>> class A:
... def bar( self ):
... print "bar"
...
>>> a = A()
>>> foo
<function foo at 0x00A98D70>
>>> a.bar
<bound method A.bar of <__main__.A instance at 0x00A9BC88>>
>>>
बाउंड विधियाँ एक उदाहरण के लिए "बाउंड" (कैसे वर्णनात्मक) हैं, और उस उदाहरण को पहले तर्क के रूप में पारित किया जाएगा जब भी विधि को बुलाया जाएगा।
एक वर्ग की विशेषताएँ (उदाहरण के विपरीत) अभी भी अनबाउंड हैं, हालाँकि, जब भी आप चाहें तो आप क्लास की परिभाषा को संशोधित कर सकते हैं:
>>> def fooFighters( self ):
... print "fooFighters"
...
>>> A.fooFighters = fooFighters
>>> a2 = A()
>>> a2.fooFighters
<bound method A.fooFighters of <__main__.A instance at 0x00A9BEB8>>
>>> a2.fooFighters()
fooFighters
पहले से परिभाषित उदाहरणों को भी अपडेट किया जाता है (जब तक कि उन्होंने स्वयं विशेषता को ओवरराइड नहीं किया है):
>>> a.fooFighters()
fooFighters
समस्या तब आती है जब आप किसी विधि को किसी एकल उदाहरण से जोड़ना चाहते हैं:
>>> def barFighters( self ):
... print "barFighters"
...
>>> a.barFighters = barFighters
>>> a.barFighters()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: barFighters() takes exactly 1 argument (0 given)
जब यह सीधे एक उदाहरण से जुड़ा होता है तो फ़ंक्शन स्वचालित रूप से बाध्य नहीं होता है:
>>> a.barFighters
<function barFighters at 0x00A98EF0>
इसे बांधने के लिए, हम टाइप मॉड्यूल में मेथडाइप फ़ंक्शन का उपयोग कर सकते हैं :
>>> import types
>>> a.barFighters = types.MethodType( barFighters, a )
>>> a.barFighters
<bound method ?.barFighters of <__main__.A instance at 0x00A9BC88>>
>>> a.barFighters()
barFighters
इस बार कक्षा के अन्य उदाहरण प्रभावित नहीं हुए हैं:
>>> a2.barFighters()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: A instance has no attribute 'barFighters'
अधिक जानकारी डिस्क्रिप्टर और मेटाक्लास प्रोग्रामिंग के बारे में पढ़कर पाई जा सकती है ।
descriptor protocol
बनाम का उपयोग करने के किसी भी लाभ के एक MethodType
तरफ एक और अधिक पठनीय होने के नाते पैदा कर सकता है।
classmethod
और staticmethod
और अन्य वर्णनकर्ता भी। यह अभी तक एक और आयात के साथ नाम स्थान को अव्यवस्थित करने से बचता है।
a.barFighters = barFighters.__get__(a)
पायथन 2.6 से मॉड्यूल नया निकाला गया है और 3.0 में हटा दिया गया है, प्रकार का उपयोग करें
http://docs.python.org/library/new.html देखें
नीचे दिए गए उदाहरण में मैंने patch_me()
फ़ंक्शन से जानबूझकर रिटर्न वैल्यू हटा दी है। मुझे लगता है कि रिटर्न वैल्यू देने से कोई यह विश्वास कर सकता है कि पैच एक नई वस्तु देता है, जो सच नहीं है - यह आने वाले को संशोधित करता है। संभवतः यह मंकीपैकिंग के अधिक अनुशासित उपयोग की सुविधा प्रदान कर सकता है।
import types
class A(object):#but seems to work for old style objects too
pass
def patch_me(target):
def method(target,x):
print "x=",x
print "called from", target
target.method = types.MethodType(method,target)
#add more if needed
a = A()
print a
#out: <__main__.A object at 0x2b73ac88bfd0>
patch_me(a) #patch instance
a.method(5)
#out: x= 5
#out: called from <__main__.A object at 0x2b73ac88bfd0>
patch_me(A)
A.method(6) #can patch class too
#out: x= 6
#out: called from <class '__main__.A'>
प्रस्तावना - संगतता पर एक नोट: अन्य उत्तर केवल पायथन 2 में काम कर सकते हैं - यह उत्तर पायथन 2 और 3 में पूरी तरह से काम करना चाहिए। यदि केवल 3 पायथन लिख रहा है, तो आप स्पष्ट रूप से विरासत में छोड़ सकते हैं object
, लेकिन अन्यथा कोड समान रहना चाहिए ।
मौजूदा वस्तु उदाहरण के लिए एक विधि जोड़ना
मैंने पढ़ा है कि पायथन में मौजूदा ऑब्जेक्ट (उदाहरण के लिए वर्ग परिभाषा में नहीं) के लिए एक विधि जोड़ना संभव है।
मैं समझता हूं कि ऐसा करना हमेशा अच्छा निर्णय नहीं होता है। लेकिन, कोई ऐसा कैसे कर सकता है?
मैं इसकी अनुशंसा नहीं करता। यह विचार अच्छा नहीं है। यह मत करो।
यहाँ कारणों की एक जोड़ी है:
इस प्रकार, मेरा सुझाव है कि आप ऐसा नहीं करते हैं जब तक कि आपके पास वास्तव में अच्छा कारण न हो। कक्षा की परिभाषा में सही विधि को परिभाषित करना बेहतर है या कक्षा को सीधे इस तरह से बंदर-पैच करने के लिए अधिमानतः कम करना है:
Foo.sample_method = sample_method
चूंकि यह शिक्षाप्रद है, हालांकि, मैं आपको ऐसा करने के कुछ तरीके दिखाने जा रहा हूं।
यहाँ कुछ सेटअप कोड है। हमें एक वर्ग की परिभाषा चाहिए। यह आयात किया जा सकता है, लेकिन यह वास्तव में कोई फर्क नहीं पड़ता।
class Foo(object):
'''An empty class to demonstrate adding a method to an instance'''
एक उदाहरण बनाएँ:
foo = Foo()
इसे जोड़ने के लिए एक विधि बनाएँ:
def sample_method(self, bar, baz):
print(bar + baz)
__get__
फ़ंक्शन पर बिंदीदार लुकअप फ़ंक्शन की __get__
विधि को उदाहरण के साथ कॉल करते हैं , ऑब्जेक्ट को विधि से बांधते हैं और इस प्रकार "बाध्य विधि" बनाते हैं।
foo.sample_method = sample_method.__get__(foo)
और अब:
>>> foo.sample_method(1,2)
3
सबसे पहले, आयात प्रकार, जिसमें से हमें विधि निर्माता मिलेगा:
import types
अब हम उदाहरण के लिए विधि को जोड़ते हैं। ऐसा करने के लिए, हमें types
मॉड्यूल से मेथडाइप कंस्ट्रक्टर की आवश्यकता होती है (जिसे हमने ऊपर आयात किया था)।
Type.MethodType के लिए तर्क हस्ताक्षर है (function, instance, class)
:
foo.sample_method = types.MethodType(sample_method, foo, Foo)
और उपयोग:
>>> foo.sample_method(1,2)
3
सबसे पहले, हम एक रैपर फ़ंक्शन बनाते हैं जो उदाहरण के लिए विधि को बांधता है:
def bind(instance, method):
def binding_scope_fn(*args, **kwargs):
return method(instance, *args, **kwargs)
return binding_scope_fn
उपयोग:
>>> foo.sample_method = bind(foo, sample_method)
>>> foo.sample_method(1,2)
3
एक आंशिक फ़ंक्शन एक फ़ंक्शन (और वैकल्पिक रूप से कीवर्ड तर्क) के लिए पहला तर्क (ओं) को लागू करता है, और बाद में शेष तर्कों (और कीवर्ड तर्क को ओवरराइड करने) के साथ बुलाया जा सकता है। इस प्रकार:
>>> from functools import partial
>>> foo.sample_method = partial(sample_method, foo)
>>> foo.sample_method(1,2)
3
यह समझ में आता है जब आप मानते हैं कि बाध्य तरीके उदाहरण के आंशिक कार्य हैं।
यदि हम नमूना_मिथोड को उसी तरह से जोड़ने का प्रयास करते हैं जैसे हम इसे कक्षा में जोड़ सकते हैं, तो यह उदाहरण से अनबाउंड है, और पहले तर्क के रूप में निहित स्वयं को नहीं लेता है।
>>> foo.sample_method = sample_method
>>> foo.sample_method(1,2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: sample_method() takes exactly 3 arguments (2 given)
हम स्पष्ट रूप से उदाहरण (या कुछ भी, क्योंकि यह विधि वास्तव में self
तर्क चर का उपयोग नहीं करती है) द्वारा अनबाउंड फ़ंक्शन कार्य कर सकती है , लेकिन यह अन्य उदाहरणों के अपेक्षित हस्ताक्षर के अनुरूप नहीं होगा (यदि हम बंदर-पैचिंग कर रहे हैं यह उदाहरण):
>>> foo.sample_method(foo, 1, 2)
3
अब आप कई तरीकों से जानते हैं कि आप ऐसा कर सकते हैं, लेकिन पूरी गंभीरता से - ऐसा न करें।
__get__
विधि को भी अगले पैरामीटर के रूप में वर्ग की जरूरत है: sample_method.__get__(foo, Foo)
।
मुझे लगता है कि उपरोक्त उत्तर महत्वपूर्ण बिंदु से चूक गए।
चलो एक विधि के साथ एक वर्ग है:
class A(object):
def m(self):
pass
अब, आइपीथन में इसके साथ खेलते हैं:
In [2]: A.m
Out[2]: <unbound method A.m>
ठीक है, तो मी () किसी तरह ए की एक अनबाउंड विधि बन जाती है । लेकिन क्या वास्तव में ऐसा है?
In [5]: A.__dict__['m']
Out[5]: <function m at 0xa66b8b4>
यह पता चला है कि एम () केवल एक फ़ंक्शन है, जिसके संदर्भ को ए श्रेणी के शब्दकोश में जोड़ा जाता है - कोई जादू नहीं है। फिर एम हमें एक अनबाउंड विधि क्यों देता है? इसका कारण यह है कि डॉट को सरल शब्दकोश लुकअप में अनुवादित नहीं किया गया है। यह वास्तविक रूप से A .__ वर्ग __.__ की पुकार है __ (A, 'm'):
In [11]: class MetaA(type):
....: def __getattribute__(self, attr_name):
....: print str(self), '-', attr_name
In [12]: class A(object):
....: __metaclass__ = MetaA
In [23]: A.m
<class '__main__.A'> - m
<class '__main__.A'> - m
अब, मुझे यकीन नहीं है कि मेरे सिर के ऊपर से आखिरी पंक्ति दो बार क्यों छपी है, लेकिन फिर भी यह स्पष्ट है कि वहां क्या चल रहा है।
अब, डिफ़ॉल्ट __getattribute__ क्या करता है, यह जांचता है कि क्या विशेषता एक तथाकथित डिस्क्रिप्टर है या नहीं, यदि यह एक विशेष __get__ विधि को लागू करता है। यदि यह उस विधि को लागू करता है, तो जो लौटा है वह उस __get__ विधि को कॉल करने का परिणाम है। हमारे ए वर्ग के पहले संस्करण पर वापस जाना , यही हमारे पास है:
In [28]: A.__dict__['m'].__get__(None, A)
Out[28]: <unbound method A.m>
और क्योंकि पायथन फ़ंक्शंस डिस्क्रिप्टर प्रोटोकॉल को लागू करते हैं, अगर उन्हें किसी ऑब्जेक्ट की ओर से बुलाया जाता है, तो वे अपने आप को अपने __get__ विधि में उस ऑब्जेक्ट से बांधते हैं।
ठीक है, तो किसी मौजूदा वस्तु में विधि कैसे जोड़ें? यह मानते हुए कि आप पैचिंग क्लास को बुरा नहीं मानते, यह उतना ही सरल है:
B.m = m
फिर बी.एम. "डिस्क्रिप्टर मैजिक की बदौलत" एक अनबाउंड तरीका बन जाता है।
और यदि आप किसी एकल ऑब्जेक्ट में सिर्फ एक विधि जोड़ना चाहते हैं, तो आपको type.MethotTech का उपयोग करके, मशीनरी का अनुकरण करना होगा:
b.m = types.MethodType(m, b)
वैसे:
In [2]: A.m
Out[2]: <unbound method A.m>
In [59]: type(A.m)
Out[59]: <type 'instancemethod'>
In [60]: type(b.m)
Out[60]: <type 'instancemethod'>
In [61]: types.MethodType
Out[61]: <type 'instancemethod'>
पायथन बंदर में पैचिंग आम तौर पर अपने स्वयं के साथ एक वर्ग या फ़ंक्शन हस्ताक्षर को ओवरराइट करके काम करता है। नीचे Zope Wiki से एक उदाहरण दिया गया है :
from SomeOtherProduct.SomeModule import SomeClass
def speak(self):
return "ook ook eee eee eee!"
SomeClass.speak = speak
वह कोड क्लास पर बोलने नामक एक विधि को अधिलेखित / निर्मित करेगा। जेफ एटवुड में हाल ही में बंदर के पेटिंग पर पोस्ट । वह C # 3.0 में एक उदाहरण दिखाता है जो वर्तमान भाषा है जो मैं काम के लिए उपयोग करता हूं।
एक विधि को उदाहरण के लिए बाँधने के लिए आप लैम्ब्डा का उपयोग कर सकते हैं:
def run(self):
print self._instanceString
class A(object):
def __init__(self):
self._instanceString = "This is instance string"
a = A()
a.run = lambda: run(a)
a.run()
आउटपुट:
This is instance string
बिना किसी इंस्टेंस के एक विधि को संलग्न करने के लिए कम से कम दो तरीके हैं types.MethodType
:
>>> class A:
... def m(self):
... print 'im m, invoked with: ', self
>>> a = A()
>>> a.m()
im m, invoked with: <__main__.A instance at 0x973ec6c>
>>> a.m
<bound method A.m of <__main__.A instance at 0x973ec6c>>
>>>
>>> def foo(firstargument):
... print 'im foo, invoked with: ', firstargument
>>> foo
<function foo at 0x978548c>
1:
>>> a.foo = foo.__get__(a, A) # or foo.__get__(a, type(a))
>>> a.foo()
im foo, invoked with: <__main__.A instance at 0x973ec6c>
>>> a.foo
<bound method A.foo of <__main__.A instance at 0x973ec6c>>
2:
>>> instancemethod = type(A.m)
>>> instancemethod
<type 'instancemethod'>
>>> a.foo2 = instancemethod(foo, a, type(a))
>>> a.foo2()
im foo, invoked with: <__main__.A instance at 0x973ec6c>
>>> a.foo2
<bound method instance.foo of <__main__.A instance at 0x973ec6c>>
उपयोगी लिंक:
डेटा मॉडल - डिस्क्रिप्टर
डिस्क्रिप्टर हॉवेटो गाइड - इनवॉइसिंग डिस्क्रिप्टर
आप जिस चीज की तलाश कर रहे हैं, setattr
मुझे विश्वास है। किसी ऑब्जेक्ट पर विशेषता सेट करने के लिए इसका उपयोग करें।
>>> def printme(s): print repr(s)
>>> class A: pass
>>> setattr(A,'printme',printme)
>>> a = A()
>>> a.printme() # s becomes the implicit 'self' variable
< __ main __ . A instance at 0xABCDEFG>
A
, उदाहरण के लिए नहीं a
।
setattr(A,'printme',printme)
बस के बजाय उपयोग करने के लिए एक कारण है A.printme = printme
?
चूंकि यह सवाल गैर-पायथन संस्करणों के लिए पूछा गया था, यहाँ जावास्क्रिप्ट है:
a.methodname = function () { console.log("Yay, a new method!") }
बाध्यकारी के विभिन्न तरीकों के परिणामों पर एक नज़र के साथ, जेसन प्रैट और समुदाय विकि उत्तरों को समेकित करना:
विशेष रूप से ध्यान दें कि एक वर्ग पद्धति के रूप में बाध्यकारी समारोह को जोड़ने का काम करता है , लेकिन संदर्भित गुंजाइश गलत है।
#!/usr/bin/python -u
import types
import inspect
## dynamically adding methods to a unique instance of a class
# get a list of a class's method type attributes
def listattr(c):
for m in [(n, v) for n, v in inspect.getmembers(c, inspect.ismethod) if isinstance(v,types.MethodType)]:
print m[0], m[1]
# externally bind a function as a method of an instance of a class
def ADDMETHOD(c, method, name):
c.__dict__[name] = types.MethodType(method, c)
class C():
r = 10 # class attribute variable to test bound scope
def __init__(self):
pass
#internally bind a function as a method of self's class -- note that this one has issues!
def addmethod(self, method, name):
self.__dict__[name] = types.MethodType( method, self.__class__ )
# predfined function to compare with
def f0(self, x):
print 'f0\tx = %d\tr = %d' % ( x, self.r)
a = C() # created before modified instnace
b = C() # modified instnace
def f1(self, x): # bind internally
print 'f1\tx = %d\tr = %d' % ( x, self.r )
def f2( self, x): # add to class instance's .__dict__ as method type
print 'f2\tx = %d\tr = %d' % ( x, self.r )
def f3( self, x): # assign to class as method type
print 'f3\tx = %d\tr = %d' % ( x, self.r )
def f4( self, x): # add to class instance's .__dict__ using a general function
print 'f4\tx = %d\tr = %d' % ( x, self.r )
b.addmethod(f1, 'f1')
b.__dict__['f2'] = types.MethodType( f2, b)
b.f3 = types.MethodType( f3, b)
ADDMETHOD(b, f4, 'f4')
b.f0(0) # OUT: f0 x = 0 r = 10
b.f1(1) # OUT: f1 x = 1 r = 10
b.f2(2) # OUT: f2 x = 2 r = 10
b.f3(3) # OUT: f3 x = 3 r = 10
b.f4(4) # OUT: f4 x = 4 r = 10
k = 2
print 'changing b.r from {0} to {1}'.format(b.r, k)
b.r = k
print 'new b.r = {0}'.format(b.r)
b.f0(0) # OUT: f0 x = 0 r = 2
b.f1(1) # OUT: f1 x = 1 r = 10 !!!!!!!!!
b.f2(2) # OUT: f2 x = 2 r = 2
b.f3(3) # OUT: f3 x = 3 r = 2
b.f4(4) # OUT: f4 x = 4 r = 2
c = C() # created after modifying instance
# let's have a look at each instance's method type attributes
print '\nattributes of a:'
listattr(a)
# OUT:
# attributes of a:
# __init__ <bound method C.__init__ of <__main__.C instance at 0x000000000230FD88>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x000000000230FD88>>
# f0 <bound method C.f0 of <__main__.C instance at 0x000000000230FD88>>
print '\nattributes of b:'
listattr(b)
# OUT:
# attributes of b:
# __init__ <bound method C.__init__ of <__main__.C instance at 0x000000000230FE08>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x000000000230FE08>>
# f0 <bound method C.f0 of <__main__.C instance at 0x000000000230FE08>>
# f1 <bound method ?.f1 of <class __main__.C at 0x000000000237AB28>>
# f2 <bound method ?.f2 of <__main__.C instance at 0x000000000230FE08>>
# f3 <bound method ?.f3 of <__main__.C instance at 0x000000000230FE08>>
# f4 <bound method ?.f4 of <__main__.C instance at 0x000000000230FE08>>
print '\nattributes of c:'
listattr(c)
# OUT:
# attributes of c:
# __init__ <bound method C.__init__ of <__main__.C instance at 0x0000000002313108>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x0000000002313108>>
# f0 <bound method C.f0 of <__main__.C instance at 0x0000000002313108>>
व्यक्तिगत रूप से, मैं बाहरी ADDMETHOD फ़ंक्शन मार्ग को पसंद करता हूं, क्योंकि यह मुझे इट्रेटर के साथ-साथ गतिशील रूप से नए तरीके के नाम प्रदान करने की अनुमति देता है।
def y(self, x):
pass
d = C()
for i in range(1,5):
ADDMETHOD(d, y, 'f%d' % i)
print '\nattributes of d:'
listattr(d)
# OUT:
# attributes of d:
# __init__ <bound method C.__init__ of <__main__.C instance at 0x0000000002303508>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x0000000002303508>>
# f0 <bound method C.f0 of <__main__.C instance at 0x0000000002303508>>
# f1 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
# f2 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
# f3 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
# f4 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
addmethod
निम्नलिखित तरीके से लिखित def addmethod(self, method, name): self.__dict__[name] = types.MethodType( method, self )
समस्या हल करती है
हालांकि जैसन जवाब देता है, यह केवल तभी काम करता है जब कोई वर्ग में कोई फ़ंक्शन जोड़ना चाहता है। मेरे लिए यह तब काम नहीं किया जब मैंने .py स्रोत कोड फ़ाइल से पहले से मौजूद पद्धति को फिर से लोड करने का प्रयास किया।
मुझे वर्कअराउंड खोजने में उम्र लग गई, लेकिन चाल आसान लगती है ... 1. स्रोत कोड फ़ाइल से कोड आयात करें। 2. फिर से लोड करने के लिए मजबूर करें। 3. प्रकार का उपयोग करें। FunctionType (...) कन्वर्ट करने के लिए एक फ़ंक्शन में आयातित और बाध्य विधि आप वर्तमान वैश्विक चर पर भी पास कर सकते हैं, क्योंकि पुनः लोड की गई विधि एक अलग नामस्थान 4. में होगी। अब आप "जेसन प्रैट" द्वारा सुझाए गए प्रकारों का उपयोग करके जारी रख सकते हैं। MethodType (... )
उदाहरण:
# this class resides inside ReloadCodeDemo.py
class A:
def bar( self ):
print "bar1"
def reloadCode(self, methodName):
''' use this function to reload any function of class A'''
import types
import ReloadCodeDemo as ReloadMod # import the code as module
reload (ReloadMod) # force a reload of the module
myM = getattr(ReloadMod.A,methodName) #get reloaded Method
myTempFunc = types.FunctionType(# convert the method to a simple function
myM.im_func.func_code, #the methods code
globals(), # globals to use
argdefs=myM.im_func.func_defaults # default values for variables if any
)
myNewM = types.MethodType(myTempFunc,self,self.__class__) #convert the function to a method
setattr(self,methodName,myNewM) # add the method to the function
if __name__ == '__main__':
a = A()
a.bar()
# now change your code and save the file
a.reloadCode('bar') # reloads the file
a.bar() # now executes the reloaded code
अगर यह किसी भी मदद के लिए हो सकता है, तो मैंने हाल ही में गोरिल्ला नामक पायथन लाइब्रेरी को जारी किया है ताकि बंदर के पेटिंग की प्रक्रिया को और अधिक सुविधाजनक बनाया जा सके।
needle()
एक मॉड्यूल का उपयोग करने के लिए एक फ़ंक्शन का उपयोग करके नाम guineapig
इस प्रकार है:
import gorilla
import guineapig
@gorilla.patch(guineapig)
def needle():
print("awesome")
लेकिन यह अधिक दिलचस्प उपयोग के मामलों का भी ध्यान रखता है जैसा कि प्रलेखन से एफएक्यू में दिखाया गया है ।
यह प्रश्न वर्षों पहले खोला गया था, लेकिन हे, डेकोरेटरों का उपयोग करके एक फ़ंक्शन के बंधन को क्लास इंस्टेंस पर अनुकरण करने का एक आसान तरीका है:
def binder (function, instance):
copy_of_function = type (function) (function.func_code, {})
copy_of_function.__bind_to__ = instance
def bound_function (*args, **kwargs):
return copy_of_function (copy_of_function.__bind_to__, *args, **kwargs)
return bound_function
class SupaClass (object):
def __init__ (self):
self.supaAttribute = 42
def new_method (self):
print self.supaAttribute
supaInstance = SupaClass ()
supaInstance.supMethod = binder (new_method, supaInstance)
otherInstance = SupaClass ()
otherInstance.supaAttribute = 72
otherInstance.supMethod = binder (new_method, otherInstance)
otherInstance.supMethod ()
supaInstance.supMethod ()
वहां, जब आप बाइंडर डेकोरेटर को फंक्शन और इंस्टेंस पास करते हैं, तो यह एक नया फंक्शन बनाएगा, जिसमें पहले वाले कोड ऑब्जेक्ट होंगे। फिर, वर्ग के दिए गए उदाहरण को नए बनाए गए फ़ंक्शन की विशेषता में संग्रहीत किया जाता है। डेकोरेटर एक (तीसरे) फ़ंक्शन को स्वचालित रूप से कॉपी किए गए फ़ंक्शन को कॉल करता है, उदाहरण के लिए पहला पैरामीटर।
निष्कर्ष में, आप एक फ़ंक्शन का अनुकरण कर रहे हैं जो वर्ग उदाहरण के लिए बाध्यकारी है। मूल फ़ंक्शन को अपरिवर्तित करने दें।
जेसन प्रैट ने जो पोस्ट किया है वह सही है।
>>> class Test(object):
... def a(self):
... pass
...
>>> def b(self):
... pass
...
>>> Test.b = b
>>> type(b)
<type 'function'>
>>> type(Test.a)
<type 'instancemethod'>
>>> type(Test.b)
<type 'instancemethod'>
जैसा कि आप देख सकते हैं, पायथन बी () a (a) से भिन्न नहीं मानता है। पायथन में सभी विधियां केवल चर हैं जो फ़ंक्शन होती हैं।
Test
, इसका कोई उदाहरण नहीं।
मुझे यह अजीब लगता है कि किसी ने भी उल्लेख नहीं किया है कि ऊपर सूचीबद्ध सभी तरीके जोड़े गए विधि और उदाहरण के बीच एक चक्र संदर्भ बनाता है, जिससे ऑब्जेक्ट कचरा संग्रहण तक लगातार बना रहता है। ऑब्जेक्ट के वर्ग का विस्तार करके एक डिस्क्रिप्टर को जोड़ने की एक पुरानी चाल थी:
def addmethod(obj, name, func):
klass = obj.__class__
subclass = type(klass.__name__, (klass,), {})
setattr(subclass, name, func)
obj.__class__ = subclass
from types import MethodType
def method(self):
print 'hi!'
setattr( targetObj, method.__name__, MethodType(method, targetObj, type(method)) )
इसके साथ ही आप सेल्फ पॉइंटर का इस्तेमाल कर सकते हैं
MethodType
, डिस्क्रिप्टर प्रोटोकॉल को मैन्युअल रूप से लागू करें और फ़ंक्शन को आपके उदाहरण का उत्पादन करें:barFighters.__get__(a)
बाध्य करने के लिए एक बाध्य विधि का उत्पादन करताbarFighters
हैa
।