मौजूदा ऑब्जेक्ट इंस्टेंस में कोई विधि जोड़ना

मैंने पढ़ा है कि पाइथन में किसी मौजूदा ऑब्जेक्ट (यानी, क्लास परिभाषा में नहीं) में कोई विधि जोड़ना संभव है।

मैं समझता हूं कि ऐसा करना हमेशा अच्छा नहीं होता है। लेकिन यह कैसे कर सकता है?

0
जोड़ा संपादित
विचारों: 1

18 उत्तर

मुझे पाइथन सिंटैक्स नहीं पता, लेकिन मुझे पता है रूबी इसे कर सकती है, और यह बदतर है। आइए मान लें कि आप ऐरे में एक विधि जोड़ना चाहते हैं जो लंबाई को मानक से प्रिंट करता है:

class Array
  def print_length
    puts length
  end
end

यदि आप पूरी कक्षा को संशोधित नहीं करना चाहते हैं, तो आप सरणी के एक उदाहरण में विधि जोड़ सकते हैं, और कोई अन्य सरणी में विधि नहीं होगी:

array = [1, 2, 3]
def array.print_length
  puts length
end

बस इस सुविधा का उपयोग करने में शामिल मुद्दों से अवगत रहें। जेफ एटवुड वास्तव में इसके बारे में लिखा बहुत पहले नहीं था।

0
जोड़ा

आप जो खोज रहे हैं वह है 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>
0
जोड़ा
क्या एप्रिंटमे = प्रिंटमे के बजाय setattr (ए, 'printme', printme) का उपयोग करने का कोई कारण है?
जोड़ा लेखक Tobias Kienzler, स्रोत
यह कक्षा <�कोड> ए </ कोड> को पैच कर रहा है, उदाहरण नहीं a
जोड़ा लेखक Ethan Furman, स्रोत
अगर कोई रनटाइम पर विधि का नाम बनाता है तो यह समझ में आता है।
जोड़ा लेखक rr-, स्रोत

किसी मौजूदा ऑब्जेक्ट इंस्टेंस में कोई विधि जोड़ना

     

मैंने पढ़ा है कि पाइथन में किसी मौजूदा ऑब्जेक्ट (उदा। कक्षा परिभाषा में नहीं) में कोई विधि जोड़ना संभव है।

     

मैं समझता हूं कि ऐसा करने का हमेशा अच्छा फैसला नहीं होता है। लेकिन, कोई यह कैसे कर सकता है?

हाँ, यह संभव है - लेकिन अनुशंसित नहीं है

मैं इसकी सिफारिश नहीं करता हूं। यह विचार अच्छा नहीं है। ऐसा मत करो

यहां कुछ कारण दिए गए हैं:

  • आप जो भी उदाहरण करते हैं, उसके लिए आप एक बाध्य वस्तु जोड़ देंगे। यदि आप ऐसा करते हैं, तो आप शायद बहुत सारी मेमोरी बर्बाद कर देंगे। बाउंड विधियों को आम तौर पर केवल उनकी कॉल की छोटी अवधि के लिए बनाया जाता है, और तब स्वचालित रूप से कचरा इकट्ठा होने पर वे अस्तित्व में रहते हैं। यदि आप इसे मैन्युअल रूप से करते हैं, तो आपके पास बाध्य विधि का संदर्भ देने वाला बाध्यकारी नाम होगा - जो इसके कचरा संग्रहण को उपयोग पर रोक देगा।
  • किसी दिए गए प्रकार के ऑब्जेक्ट उदाहरणों में आमतौर पर उस प्रकार की सभी ऑब्जेक्ट्स पर इसकी विधियां होती हैं। यदि आप कहीं और तरीकों को जोड़ते हैं, तो कुछ उदाहरणों में वे विधियां होंगी और अन्य नहीं होंगे। प्रोग्रामर इसकी अपेक्षा नहीं करेंगे, और आप कम से कम आश्चर्य का नियम का उल्लंघन करने का जोखिम उठाते हैं।
  • चूंकि ऐसा करने के लिए अन्य वास्तव में अच्छे कारण नहीं हैं, इसलिए यदि आप ऐसा करते हैं तो आप अतिरिक्त रूप से एक गरीब प्रतिष्ठा देंगे।

इस प्रकार, मेरा सुझाव है कि आप ऐसा तब तक नहीं करते जब तक आपके पास वास्तव में कोई अच्छा कारण न हो। क्लास परिभाषा में सही विधि को परिभाषित करना कहीं बेहतर है या कम अधिमानतः क्लार्क को सीधे बंदर-पैच करने के लिए, इस तरह:

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)

Method nought (0) - use the descriptor method, __get__

फ़ंक्शंस पर डॉट किए गए लुकअप उदाहरण के साथ फ़ंक्शन के __ प्राप्त __ विधि को कॉल करते हैं, ऑब्जेक्ट को विधि में बाध्य करते हैं और इस प्रकार "बाध्य विधि" बनाते हैं।

foo.sample_method = sample_method.__get__(foo)

और अब:

>>> foo.sample_method(1,2)
3

विधि एक - प्रकार। विधि टाइप

सबसे पहले, आयात प्रकार, जिससे हम विधि कन्स्ट्रक्टर प्राप्त करेंगे:

import types

अब हम उदाहरण के लिए विधि जोड़ते हैं। ऐसा करने के लिए, हमें प्रकार मॉड्यूल (जिसे हमने ऊपर आयात किया है) से मेथड टाइप कन्स्ट्रक्टर की आवश्यकता है।

प्रकारों के लिए तर्क हस्ताक्षर। MethodType (फ़ंक्शन, इंस्टेंस, क्लास) है:

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

विधि तीन: functools.partial

आंशिक फ़ंक्शन किसी फ़ंक्शन (और वैकल्पिक रूप से कीवर्ड तर्क) के लिए पहली तर्क (ओं) को लागू करता है, और बाद में शेष तर्क (और कीवर्ड तर्कों को ओवरराइड करने) के साथ बुलाया जा सकता है। इस प्रकार:

>>> from functools import partial
>>> foo.sample_method = partial(sample_method, foo)
>>> foo.sample_method(1,2)
3    

यह समझ में आता है जब आप मानते हैं कि बाध्य विधियां उदाहरण के आंशिक कार्य हैं।

ऑब्जेक्ट विशेषता के रूप में अनबाउंड फ़ंक्शन - यह क्यों काम नहीं करता है:

यदि हम sample_method को उसी तरीके से जोड़ने का प्रयास करते हैं जैसे हम इसे कक्षा में जोड़ सकते हैं, तो यह उदाहरण से अनबाउंड है, और अंतर्निहित स्वयं को पहले तर्क के रूप में नहीं लेता है।

>>> foo.sample_method = sample_method
>>> foo.sample_method(1,2)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: sample_method() takes exactly 3 arguments (2 given)

हम स्पष्ट रूप से उदाहरण (या कुछ भी) को पार करके अनबाउंड फ़ंक्शन काम कर सकते हैं, क्योंकि यह विधि वास्तव में self तर्क चर का उपयोग नहीं करती है), लेकिन यह अन्य उदाहरणों के अपेक्षित हस्ताक्षर के अनुरूप नहीं होगी (अगर हम इस उदाहरण को बंदर-पैचिंग कर रहे हैं):

>>> foo.sample_method(foo, 1, 2)
3

निष्कर्ष

अब आप इसे कर सकते हैं कई तरीकों से जानते हैं, लेकिन सभी गंभीरता में - ऐसा मत करें।

0
जोड़ा
मेरी टिप्पणी इस संदर्भ पर आधारित थी: python-context.readthedocs। io / en / latest / docs / dunderdsc / & hellip; अब मैं आधिकारिक दस्तावेज़ों से क्या देखता हूं, यह वैकल्पिक है: docs.python.org/3/howto/descriptor.html#descriptor-protocol
जोड़ा लेखक Aidas Bendoraitis, स्रोत
__ __ विधि प्राप्त करने के लिए कक्षा को अगले पैरामीटर के रूप में भी आवश्यक है: sample_method .__ __ (foo, foo) प्राप्त करें।
जोड़ा लेखक Aidas Bendoraitis, स्रोत
@AidasBendoraitis मैं इसे "जरूरत" नहीं कहूंगा, यह एक वैकल्पिक पैरामीटर है जो डिस्क्रिप्टर प्रोटोकॉल को लागू करते समय आपूर्ति की जाती है - लेकिन पायथन फ़ंक्शन तर्क का उपयोग नहीं करते हैं: github.com/python/cpython/blob/master/Objects/funcobject.c#L‌ 581
जोड़ा लेखक Aaron Hall, स्रोत
@ एटकोल्ड मैंने परिचय में ऐसा करने से बचने के कारणों पर विस्तार किया है।
जोड़ा लेखक Aaron Hall, स्रोत
अस्वीकरण वह है जो मैं सोच रहा था। विधि परिभाषा केवल वर्ग परिभाषा के भीतर घोंसला कार्य करती है।
जोड़ा लेखक Atcold, स्रोत

Module new is deprecated since python 2.6 and removed in 3.0, use types

see 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 
0
जोड़ा

type.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
<__main__.A instance at 0x973ec6c>>
>>> 
>>> def foo(firstargument):
...  print 'im foo, invoked with: ', firstargument

>>> foo

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
<__main__.A instance at 0x973ec6c>>

2:

>>> instancemethod = type(A.m)
>>> instancemethod

>>> a.foo2 = instancemethod(foo, a, type(a))
>>> a.foo2()
im foo, invoked with:  <__main__.A instance at 0x973ec6c>
>>> a.foo2
<__main__.A instance at 0x973ec6c>>

Useful links:
Data model - invoking descriptors
Descriptor HowTo Guide - invoking descriptors

0
जोड़ा

चूंकि इस प्रश्न ने गैर-पायथन संस्करणों के लिए पूछा है, यहां जावास्क्रिप्ट है:

a.methodname = function() { console.log("Yay, a new method!") }
0
जोड़ा

मुझे लगता है कि उपरोक्त उत्तरों मुख्य बिंदु से चूक गए हैं।

चलो एक विधि के साथ एक कक्षा है:

class A(object):
    def m(self):
        pass

अब, आईपीथॉन में इसके साथ खेलते हैं:

In [2]: A.m
Out[2]: 

ठीक है, इसलिए m() किसी भी तरह की एक अनबाउंड विधि बन जाता है। लेकिन क्या यह वास्तव में ऐसा है?

In [5]: A.__dict__['m']
Out[5]: 

यह पता चला है कि m() केवल एक फ़ंक्शन है, जिसका संदर्भ कक्षा शब्दकोश में जोड़ा गया है - इसमें कोई जादू नहीं है। तो क्यों एएम हमें एक अनबाउंड विधि देता है? ऐसा इसलिए है क्योंकि डॉट का अनुवाद एक साधारण शब्दकोश लुकअप में नहीं किया जाता है। यह वास्तव में ए .__ वर्ग __.__ getatribute __ (ए, 'एम') का आह्वान है:

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

अब, मुझे यकीन नहीं है कि मेरे सिर के शीर्ष से क्यों पिछली पंक्ति दो बार मुद्रित की जाती है, लेकिन फिर भी यह स्पष्ट है कि वहां क्या हो रहा है।

अब, डिफ़ॉल्ट __getattribute__ क्या करता है यह यह जांचता है कि क्या विशेषता एक तथाकथित है वर्णनकर्ता या नहीं, यानी यदि यह एक विशेष __get__ विधि लागू करता है। यदि यह उस विधि को लागू करता है, तो वापस लौटाया जाता है जो __get__ विधि को कॉल करने का परिणाम होता है। हमारे वर्ग के पहले संस्करण पर वापस जाकर, हमारे पास यह है:

In [28]: A.__dict__['m'].__get__(None, A)
Out[28]: 

और क्योंकि पाइथन कार्यकर्ता डिस्क्रिप्टर प्रोटोकॉल को कार्यान्वित करता है, अगर उन्हें किसी ऑब्जेक्ट की तरफ से बुलाया जाता है, तो वे स्वयं को उस ऑब्जेक्ट को अपनी __get__ विधि में बाध्य करते हैं।

ठीक है, तो किसी मौजूदा ऑब्जेक्ट में कोई विधि कैसे जोड़ें? मान लीजिए कि आप पैचिंग क्लास को ध्यान में रखते हैं, यह उतना आसान है जितना:

B.m = m

फिर बीएम वर्णनकर्ता जादू के लिए धन्यवाद, एक अनबाउंड विधि बन जाता है।

और यदि आप केवल एक ही ऑब्जेक्ट में कोई विधि जोड़ना चाहते हैं, तो आपको प्रकारों का उपयोग करके मशीनरी को स्वयं अनुकरण करना होगा। विधि टाइप:

b.m = types.MethodType(m, b)

वैसे:

In [2]: A.m
Out[2]: 

In [59]: type(A.m)
Out[59]: 

In [60]: type(b.m)
Out[60]: 

In [61]: types.MethodType
Out[61]: 
0
जोड़ा

यह सवाल साल पहले खोला गया था, लेकिन हे, सजावट का उपयोग कर एक वर्ग के उदाहरण में एक समारोह के बाध्यकारी अनुकरण करने का एक आसान तरीका है:

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 ()

There, when you pass the function and the instance to the binder decorator, it will create a new function, with the same code object as the first one. Then, the given instance of the class is stored in an attribute of the newly created function. The decorator return a (third) function calling automatically the copied function, giving the instance as the first parameter.

In conclusion you get a function simulating it's binding to the class instance. Letting the original function unchanged.

0
जोड़ा

बाध्यकारी के विभिन्न तरीकों के परिणामों पर नजर डालने के साथ जेसन प्रैट और सामुदायिक विकी जवाबों को समेकित करना:

विशेष रूप से ध्यान दें कि बाध्यकारी फ़ंक्शन को क्लास विधि works के रूप में कैसे जोड़ना है, लेकिन संदर्भ का दायरा गलत है।

#!/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__ <__main__.C instance at 0x000000000230FD88>>
# addmethod <__main__.C instance at 0x000000000230FD88>>
# f0 <__main__.C instance at 0x000000000230FD88>>

print '\nattributes of b:'
listattr(b)
# OUT:
# attributes of b:
# __init__ <__main__.C instance at 0x000000000230FE08>>
# addmethod <__main__.C instance at 0x000000000230FE08>>
# f0 <__main__.C instance at 0x000000000230FE08>>
# f1 >
# f2 <__main__.C instance at 0x000000000230FE08>>
# f3 <__main__.C instance at 0x000000000230FE08>>
# f4 <__main__.C instance at 0x000000000230FE08>>

print '\nattributes of c:'
listattr(c)
# OUT:
# attributes of c:
# __init__ <__main__.C instance at 0x0000000002313108>>
# addmethod <__main__.C instance at 0x0000000002313108>>
# f0 <__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__ <__main__.C instance at 0x0000000002303508>>
# addmethod <__main__.C instance at 0x0000000002303508>>
# f0 <__main__.C instance at 0x0000000002303508>>
# f1 <__main__.C instance at 0x0000000002303508>>
# f2 <__main__.C instance at 0x0000000002303508>>
# f3 <__main__.C instance at 0x0000000002303508>>
# f4 <__main__.C instance at 0x0000000002303508>>
0
जोड़ा
addmethod निम्न तरीके से पुनः लिखा गया def addmethod (self, method, name): self .__ dict __ [name] = type.MethodType (विधि, स्वयं) समस्या हल करता है
जोड़ा लेखक Antony Hatchkins, स्रोत

पायथन बंदर पैचिंग में आम तौर पर एक वर्ग या कार्यों के हस्ताक्षर को ओवरराइट करके काम करता है। नीचे ज़ोप विकी का एक उदाहरण है:

from SomeOtherProduct.SomeModule import SomeClass
def speak(self):
   return "ook ook eee eee eee!"
SomeClass.speak = speak

वह कोड कक्षा पर बोलने वाली विधि को ओवरराइट / बना देगा। जेफ एटवुड के बंदर पैचिंग पर हालिया पोस्ट में। वह सी # 3.0 में एक उदाहरण दिखाता है जो वर्तमान भाषा है जिसका उपयोग मैं काम के लिए करता हूं।

0
जोड़ा
लेकिन यह कक्षा के सभी उदाहरणों को प्रभावित करता है, केवल एक ही नहीं।
जोड़ा लेखक glglgl, स्रोत

पायथन में, कार्यों और बाध्य तरीकों के बीच एक अंतर है।

>>> def foo():
...     print "foo"
...
>>> class A:
...     def bar( self ):
...         print "bar"
...
>>> a = A()
>>> foo

>>> a.bar
<__main__.A instance at 0x00A9BC88>>
>>>

बाउंड विधियों को एक उदाहरण के लिए "बाध्य" (वर्णनात्मक) किया गया है, और जब भी विधि कहा जाता है तो वह उदाहरण पहले तर्क के रूप में पारित किया जाएगा।

कॉलबेल जो क्लास के गुण हैं (उदाहरण के विपरीत) अभी भी अनबाउंड हैं, इसलिए जब भी आप चाहें कक्षा परिभाषा को संशोधित कर सकते हैं:

>>> def fooFighters( self ):
...     print "fooFighters"
...
>>> A.fooFighters = fooFighters
>>> a2 = A()
>>> a2.fooFighters
<__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 "", line 1, in 
TypeError: barFighters() takes exactly 1 argument (0 given)

जब यह सीधे किसी उदाहरण से जुड़ा होता है तो फ़ंक्शन स्वचालित रूप से बाध्य नहीं होता है:

>>> a.barFighters

इसे बाध्य करने के लिए, हम टाइप मॉड्यूल में विधि टाइप प्रकार का उपयोग कर सकते हैं :

>>> import types
>>> a.barFighters = types.MethodType( barFighters, a )
>>> a.barFighters
<__main__.A instance at 0x00A9BC88>>
>>> a.barFighters()
barFighters

इस बार कक्षा के अन्य उदाहरण प्रभावित नहीं हुए हैं:

>>> a2.barFighters()
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: A instance has no attribute 'barFighters'

अधिक जानकारी वर्णनकर्ता और मेटाक्लास प्रोग्रामिंग

0
जोड़ा
सी # में एक्सटेंशन विधियों के समान पाइथन में बाध्य विधियां हैं?
जोड़ा लेखक Andy, स्रोत
@EndermanAPM: कई: उदाहरण के लिए विशेषता को एक्सेस करने के समान ही काम करना जारी रखने की अधिक संभावना है। यह classmethod और staticmethod और अन्य वर्णनकर्ताओं के लिए भी काम करेगा। यह अभी तक एक और आयात के साथ नामस्थान को अव्यवस्थित करने से बचाता है।
जोड़ा लेखक Martijn Pieters, स्रोत
सुझाए गए वर्णनकर्ता दृष्टिकोण के लिए पूर्ण कोड a.barFighters = barFighters .__ प्राप्त होता है __ (ए)
जोड़ा लेखक eqzx, स्रोत
@MartijnPieters descriptor प्रोटोकॉल बनाम एक MethodType बनाकर थोड़ा और अधिक पठनीय होने का उपयोग करने के किसी भी फायदे का उपयोग करने के किसी भी फायदे हैं।
जोड़ा लेखक EndermanAPM, स्रोत

जोसन प्रैट पोस्ट किया गया सही है।

>>> class Test(object):
...   def a(self):
...     pass
... 
>>> def b(self):
...   pass
... 
>>> Test.b = b
>>> type(b)

>>> type(Test.a)

>>> type(Test.b)

जैसा कि आप देख सकते हैं, पाइथन बी() को किसी() से अलग नहीं मानता है। पायथन में सभी विधियां केवल वे चर हैं जो कार्य होने लगती हैं।

0
जोड़ा
आप वर्ग <�कोड> टेस्ट को पैच कर रहे हैं, इसका एक उदाहरण नहीं।
जोड़ा लेखक Ethan Furman, स्रोत

आप लोगों को वास्तव में वर्जित फल देखना चाहिए, यह एक पायथन लाइब्रेरी है जो किसी भी पायथन कक्षा को बंदर बंद करने के लिए समर्थन प्रदान करती है, यहां तक ​​कि तार भी।

0
जोड़ा
आम तौर पर, किसी टूल या लाइब्रेरी से लिंक उपयोग नोट्स या कुछ नमूना कोड के साथ होना चाहिए, या यदि संभव हो तो दोनों। हालांकि, यह कम से कम लिंक किए गए पोस्ट में न्यूनतम मानक को पूरा करता है जिसमें एक विशिष्ट स्पष्टीकरण शामिल है कि लिंक संसाधन किस प्रकार समस्या पर लागू होता है।
जोड़ा लेखक Nathan Tuggy, स्रोत

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

guineapig नामक मॉड्यूल को पैच करने के लिए फ़ंक्शन सुई() का उपयोग करके निम्नानुसार जाता है:

import gorilla
import guineapig
@gorilla.patch(guineapig)
def needle():
    print("awesome")

लेकिन यह FAQ में दिखाए गए अनुसार अधिक रोचक उपयोग मामलों का भी ख्याल रखता है दस्तावेज़ीकरण

कोड GitHub पर उपलब्ध है।

0
जोड़ा

आप उदाहरण के लिए विधि को बांधने के लिए लैम्ब्डा का उपयोग कर सकते हैं:

def run(self):
    print self._instanceString

class A(object):
    def __init__(self):
        self._instanceString = "यह उदाहरण स्ट्रिंग है"

a = A()
a.run = lambda: run(a)
a.run()

यह उदाहरण स्ट्रिंग है

निकास कोड 0 के साथ प्रक्रिया समाप्त हो गई

0
जोड़ा

यह वास्तव में "जेसन प्रैट" के जवाब में एक एडन है

यद्यपि जेसन ने जवाब दिया है, यह केवल तभी काम करता है जब कोई कक्षा में कोई फ़ंक्शन जोड़ना चाहता हो। जब मैंने .py स्रोत कोड फ़ाइल से पहले से मौजूद मौजूदा विधि को पुनः लोड करने का प्रयास किया तो यह मेरे लिए काम नहीं करता था।

यह मुझे कामकाज खोजने के लिए उम्र के लिए ले गया, लेकिन चाल सरल लगता है ... 1. स्रोत कोड फ़ाइल से कोड आयात करें 2. एक रीलोड बल 3. वें उपयोग प्रकार। फ़ंक्शन टाइप (...) आयातित और बाध्य विधि को किसी फ़ंक्शन में कनवर्ट करने के लिए आप वर्तमान वैश्विक चर भी पास कर सकते हैं, क्योंकि पुनः लोड की गई विधि एक अलग नामस्थान में होगी 4. अब आप "जेसन प्रैट" द्वारा सुझाए गए अनुसार जारी रख सकते हैं   प्रकारों का उपयोग करना। विधि टाइप (...)

उदाहरण:

# 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
0
जोड़ा

मुझे यह अजीब लगता है कि किसी ने भी उल्लेख नहीं किया है कि ऊपर सूचीबद्ध सभी विधियां अतिरिक्त विधि और उदाहरण के बीच चक्र संदर्भ बनाती हैं, जिससे ऑब्जेक्ट कचरा संग्रह तक लगातार बना रहता है। ऑब्जेक्ट की कक्षा को विस्तारित करके एक वर्णक जोड़कर एक पुरानी चाल थी:

def addmethod(obj, name, func):
    klass = obj.__class__
    subclass = type(klass.__name__, (klass,), {})
    setattr(subclass, name, func)
    obj.__class__ = subclass
0
जोड़ा
from types import MethodType

def method(self):
   print 'hi!'


setattr( targetObj, method.__name__, MethodType(method, targetObj, type(method)) )

इसके साथ, आप स्वयं सूचक का उपयोग कर सकते हैं

0
जोड़ा