একটি বিদ্যমান অবজেক্ট ইনস্ট্যান্সে একটি পদ্ধতি যুক্ত করা


642

আমি পড়েছি যে পাইথনের কোনও বিদ্যমান অবজেক্টে (যেমন শ্রেণীর সংজ্ঞায় নয়) একটি পদ্ধতি যুক্ত করা সম্ভব।

আমি বুঝতে পারি যে এটি করা সর্বদা ভাল নয়। তবে কীভাবে কেউ এটি করতে পারে?

উত্তর:


921

পাইথনে, ফাংশন এবং আবদ্ধ পদ্ধতির মধ্যে পার্থক্য রয়েছে।

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

বর্ণনাকারী এবং মেটাক্লাস প্রোগ্রামিং সম্পর্কে পড়ার মাধ্যমে আরও তথ্য পাওয়া যাবে ।


65
ম্যানুয়ালি একটি তৈরির পরিবর্তে MethodType, ডেস্ক্রিপ্টর প্রোটোকলটি ম্যানুয়ালি আহ্বান করুন এবং ফাংশনটি আপনার উদাহরণটি উত্পন্ন করুন: আবদ্ধ হওয়ার barFighters.__get__(a)জন্য একটি সীমাবদ্ধ পদ্ধতি তৈরি barFightersকরে a
মার্টিজন পিটারস

2
@ মার্তিজন পি descriptor protocolবনাম ব্যবহারের কোনও সুবিধা MethodTypeসম্ভবত কিছুটা বেশি পঠনযোগ্য হতে পারে a
এন্ডারম্যানএপিএম

17
@ এন্ডারম্যানএপিএম: বেশ কয়েকটি: এটির উদাহরণস্বরূপে অ্যাট্রিবিউটটি অ্যাক্সেস করার মতো কাজ ঠিক একইভাবে চালিয়ে যাওয়ার সম্ভাবনা বেশি। এটা তোলে জন্য কাজ করব classmethodএবং staticmethodএবং অন্যান্য বর্ণনাকারী খুব। এটি আর একটি আমদানির সাথে নেমস্পেসকে বিশৃঙ্খলা এড়ায়।
মার্টিজন পিটারস

34
প্রস্তাবিত বর্ণনাকারী পদ্ধতির জন্য পূর্ণ কোডa.barFighters = barFighters.__get__(a)
eqzx

98

অজগর ২.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'>

1
এই পদ্ধতিটি যুক্ত হওয়ার সাথে সাথে যদি নিজেকে বোঝার প্রয়োজন হয় তবে কীভাবে এটি কাজ করবে? আমার প্রথম চেষ্টাটি একটি সিনট্যাক্স ত্রুটির দিকে পরিচালিত করে, তবে পদ্ধতির সংজ্ঞাতে নিজেকে যুক্ত করা কাজ করবে বলে মনে হয় না। আমদানি প্রকারের ক্লাস এ (অবজেক্ট): # তবে পুরানো স্টাইলের অবজেক্টের জন্য খুব অ্যাক্সেস = 'কুড়াল' পাস ডিএফ প্যাচ_মে (টার্গেট): ডিফ মেথড (টার্গেট, এক্স): প্রিন্ট (সেলফ্যাক্স) প্রিন্ট ("x =" , এক্স) মুদ্রণ ("থেকে আহ্বান", লক্ষ্য) টার্গেট.মোথডো = প্রকারসমূহ। মেথডটাইপ (পদ্ধতি, লক্ষ্য) # প্রয়োজনে আরও যোগ করুন a = এ () মুদ্রণ (a.ax)
ওয়েস্টার

84

উপস্থাপনা - সামঞ্জস্যের উপর একটি নোট: অন্যান্য উত্তরগুলি কেবল পাইথন 2 এ কাজ করতে পারে - এই উত্তরটি পাইথন 2 এবং 3 এ পুরোপুরি ভালভাবে কাজ করা উচিত যদি কেবল পাইথন 3 লিখতে পারেন তবে আপনি স্পষ্টতই উত্তরাধিকার সূত্রে ছেড়ে যেতে পারেন object, তবে অন্যথায় কোডটি একই থাকবে should ।

একটি বিদ্যমান অবজেক্ট ইনস্ট্যান্সে একটি পদ্ধতি যুক্ত করা

আমি পড়েছি যে পাইথনের কোনও বিদ্যমান অবজেক্টে (উদাহরণস্বরূপ শ্রেণির সংজ্ঞায় নয়) একটি পদ্ধতি যুক্ত করা সম্ভব।

আমি বুঝতে পারি যে এটি করা সবসময় ভাল সিদ্ধান্ত নয়। কিন্তু, কেউ কীভাবে এটি করতে পারে?

হ্যাঁ, এটি সম্ভব - তবে প্রস্তাবিত নয়

আমি এটি সুপারিশ করি না। এটি একটি খারাপ ধারণা। এটা করবেন না।

এখানে বেশ কয়েকটি কারণ রয়েছে:

  • আপনি এটি প্রতিটি ক্ষেত্রে একটি সীমাবদ্ধ অবজেক্ট যুক্ত করবেন। আপনি যদি এটি অনেক কিছু করেন তবে আপনি সম্ভবত প্রচুর স্মৃতি নষ্ট করবেন। বাউন্ড পদ্ধতিগুলি সাধারণত তাদের কলের স্বল্প সময়ের জন্য তৈরি করা হয় এবং স্বয়ংক্রিয়ভাবে আবর্জনা সংগ্রহ করার পরে সেগুলি অস্তিত্ব অর্জন বন্ধ করে দেয়। আপনি যদি ম্যানুয়ালি এটি করেন তবে আপনার কাছে একটি নাম বেধে দেওয়া আবদ্ধ পদ্ধতিটি উল্লেখ করা হবে - যা ব্যবহারের ক্ষেত্রে এর আবর্জনা সংগ্রহ আটকাবে।
  • প্রদত্ত টাইপের অবজেক্টের দৃষ্টান্তগুলির সাধারণত সেই ধরণের সমস্ত বস্তুর উপর তার পদ্ধতি থাকে। আপনি যদি অন্য কোথাও পদ্ধতিগুলি যুক্ত করেন, কিছু কিছু ক্ষেত্রে সেই পদ্ধতিগুলি থাকবে এবং অন্যরা তা করবে না। প্রোগ্রামাররা এটি আশা করবে না, এবং আপনি অন্তত বিস্ময়ের নিয়ম লঙ্ঘন করার ঝুঁকিপূর্ণ ।
  • যেহেতু এটি না করার জন্য সত্যিকারের আরও অনেক ভাল কারণ রয়েছে তাই আপনি যদি এটি করেন তবে অতিরিক্ত আপনি নিজেকে স্বল্প খ্যাতি দিন।

সুতরাং, আমি আপনাকে পরামর্শ দিচ্ছি যে যদি আপনি সত্যিকারের কোনও ভাল কারণ না পান তবে আপনি এটি করবেন না। এটা তোলে অনেক ভালো বর্গ সংজ্ঞা সঠিক পদ্ধতি নির্ধারণ করতে হয় বা কম ভালো, বানর-প্যাচ থেকে বাঞ্ছনীয় বর্গ সরাসরি:

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)

পদ্ধতি নথ (0) - বর্ণনাকারী পদ্ধতিটি ব্যবহার করুন, __get__

ফাংশনগুলিতে বিন্দুযুক্ত __get__দৃষ্টিকোণগুলি ফাংশনটির পদ্ধতিটিকে দৃষ্টান্তের সাথে কল করে , বস্তুকে পদ্ধতির সাথে আবদ্ধ করে এবং এইভাবে একটি "আবদ্ধ পদ্ধতি" তৈরি করে।

foo.sample_method = sample_method.__get__(foo)

এবং এখন:

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

পদ্ধতি এক - প্রকারের.মাথোডটাইপ

প্রথমত, আমদানির প্রকারগুলি, যেখান থেকে আমরা পদ্ধতিটি নির্মাণকারী পেয়ে যাব:

import types

এখন আমরা উদাহরণটি পদ্ধতিতে যুক্ত করব। এটি করার জন্য, আমাদের typesমডিউলটি (যা আমরা উপরে আমদানি করেছি) থেকে মেথডটাইপ নির্মাণকারী প্রয়োজন ।

প্রকারের জন্য আর্গুমেন্ট স্বাক্ষর eth মেথডটাইপটি হ'ল (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

পদ্ধতি তিনটি: functools.partial

একটি আংশিক ফাংশন কোনও ফাংশনে প্রথম যুক্তি (গুলি) প্রয়োগ করে (এবং allyচ্ছিকভাবে কীওয়ার্ড আর্গুমেন্টগুলি), এবং পরে অবশিষ্ট আর্গুমেন্টগুলি (এবং কীওয়ার্ড আর্গুমেন্টকে ওভাররাইডিং) দিয়ে ডাকা যেতে পারে। এভাবে:

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

আপনি যখন বিবেচনা করেন যে আবদ্ধ পদ্ধতিগুলি উদাহরণের আংশিক ফাংশন are

অবজেক্ট অ্যাট্রিবিউট হিসাবে আনবাউন্ড ফাংশন - কেন এটি কাজ করে না:

আমরা যদি ক্লাসে এটি যোগ করতে পারে সেভাবে নমুনা_ thodতিহ্যকে যুক্ত করার চেষ্টা করি, এটি উদাহরণ থেকে অবিরাম, এবং অন্তর্নিহিত স্বটিকে প্রথম যুক্তি হিসাবে গ্রহণ করে না।

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

উপসংহার

আপনি এখন বেশ কয়েকটি উপায়ে জানেন যে আপনি এটি করতে পারেন তবে সমস্ত গম্ভীরতার সাথে - এটি করবেন না।


1
দাবি পরিত্যাগী কি আমি সম্পর্কে হতাশ হয়। পদ্ধতির সংজ্ঞাটি ক্লাস সংজ্ঞায় কেবল নেস্ট করা ফাংশন।
আটকোল্ড

1
@ অ্যাটকোল্ডটি প্রবর্তনে এটি না করার কারণগুলিতে আমি প্রসারিত করেছি।
অ্যারন হল

__get__পদ্ধতি পরবর্তী প্যারামিটার হিসাবে বর্গ দরকার: sample_method.__get__(foo, Foo)
এডাস বেনডোরাইটিস 31'18

2
@ আইডাসবেনডোরাইটিস আমি এটির "প্রয়োজন" বলব না, এটি একটি alচ্ছিক প্যারামিটার যা সরবরাহকারীর প্রোটোকল প্রয়োগ করার সময় সরবরাহ করা হয় - তবে পাইথন ফাংশনগুলি যুক্তিটি ব্যবহার করে না: github.com/python/cpython/blob/master/Objects/funcobject .c # L581
অ্যারন হল

আমার মন্তব্যটি এই রেফারেন্সের ভিত্তিতে তৈরি হয়েছিল: পাইথন- রেফারেন্স.ড্রেডহেডোকস.আইও / স্পেন / স্লেস্ট / ডকস / ডান্ডারডস্ক / আমি এখন অফিসিয়াল ডক্স থেকে যা দেখছি, এটি alচ্ছিক
এডাস বেনডোরাইটিস

35

আমি মনে করি যে উপরের উত্তরগুলি মূল পয়েন্টটি মিস করেছে।

একটি পদ্ধতি সহ একটি ক্লাস করা যাক:

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 .__ শ্রেণির কল __.__ getattribute __ (এ, 'মি'):

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__ পদ্ধতি কল করার ফলাফল of আমাদের ক্লাসের প্রথম সংস্করণে ফিরে যাওয়া , এটি আমাদের কাছে রয়েছে:

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

এবং পাইথন ফাংশনগুলি ডেস্ক্রিপ্টর প্রোটোকল বাস্তবায়িত করে, যদি তাদের কোনও বস্তুর পক্ষে ডাকা হয়, তারা তাদের __get__ পদ্ধতিতে সেই বস্তুর সাথে আবদ্ধ হয়।

ঠিক আছে, সুতরাং একটি বিদ্যমান অবজেক্টে কীভাবে একটি পদ্ধতি যুক্ত করবেন? ধরে নিই যে আপনার প্যাচিং ক্লাসটি আপত্তি নেই, এটি এতটা সহজ:

B.m = m

তারপরে বিএম "আনবাউন্ড পদ্ধতি" হয়ে যায়, বর্ণনাকারী যাদুটির জন্য ধন্যবাদ।

এবং যদি আপনি কোনও একক বস্তুতে কোনও পদ্ধতি যুক্ত করতে চান, তবে আপনাকে নিজেই প্রকারগুলি ব্যবহার করে যন্ত্রপাতিটি অনুকরণ করতে হবে ethমেথডটাইপ:

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

19

পাইথনে বানর প্যাচিং সাধারণত কোনও শ্রেণি ওভাররাইট করে আপনার নিজের সাথে স্বাক্ষর ফাংশন করে works নীচে জোপ উইকির একটি উদাহরণ দেওয়া হল :

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

এই কোডটি ক্লাসে স্পোক নামক একটি পদ্ধতি ওভাররাইট / তৈরি করবে। বানর প্যাচিংয়ের বিষয়ে জেফ আতউডের সাম্প্রতিক পোস্টে । তিনি সি # 3.0 এ একটি উদাহরণ দেখান যা আমি কাজের জন্য বর্তমান ভাষা ব্যবহার করি।


6
তবে এটি ক্লাসের সমস্ত উদাহরণকে প্রভাবিত করে , কেবল একটিই নয়।
glglgl

14

আপনি কোনও পদ্ধতির সাথে আবদ্ধ হতে লাম্বদা ব্যবহার করতে পারেন:

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

9

উদাহরণ ছাড়াই কোনও পদ্ধতি সংযুক্ত করার জন্য কমপক্ষে দুটি উপায় রয়েছে 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>>

দরকারী লিঙ্কগুলি:
ডেটা মডেল - বর্ণনাকারী বর্ণনাকারী
ডেস্ক্রিপ্টর হাওটো গাইড - ইনোভাকিং ডিসক্রিপটর


7

আপনি যা খুঁজছেন তা 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>

8
এটি ক্লাসটি প্যাচ করছে A, উদাহরণটি নয় a
ইথান ফুরম্যান

5
সরল setattr(A,'printme',printme)পরিবর্তে ব্যবহার করার কোনও কারণ আছে কি A.printme = printme?
টোবিয়াস কেইনজলার

1
যদি কোনও রানটাইমে পদ্ধতির নাম তৈরি করে তবে তা বোধগম্য হয়।
rr-

6

যেহেতু এই প্রশ্নটি পাইথনবিহীন সংস্করণগুলির জন্য জিজ্ঞাসা করেছে, তাই এখানে জাভাস্ক্রিপ্ট রয়েছে:

a.methodname = function () { console.log("Yay, a new method!") }

5

জেসন প্র্যাট এবং সম্প্রদায় উইকি উত্তরগুলি একত্রিত করে বাইন্ডিংয়ের বিভিন্ন পদ্ধতির ফলাফলগুলি দেখুন:

বিশেষত নোট করুন কীভাবে বন্ডিং ফাংশনটি ক্লাসের পদ্ধতি হিসাবে যুক্ত করে তা কার্যকর করে তবে রেফারেন্সিং সুযোগটি ভুল।

#!/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 )সমস্যা সমাধান করে
অ্যান্টনি হ্যাচকিন্স

5

এটি আসলে "জেসন প্র্যাট" এর উত্তরের সংযোজন

যদিও জেসনস উত্তরটি কাজ করে, এটি কেবল তখনই কাজ করে যদি কেউ কোনও ক্লাসে কোনও ফাংশন যুক্ত করতে চায়। আমি .py উত্স কোড ফাইল থেকে ইতিমধ্যে বিদ্যমান পদ্ধতিটি পুনরায় লোড করার চেষ্টা করার সময় এটি আমার পক্ষে কার্যকর হয়নি।

যুগে যুগে কাজটি খুঁজে পেতে আমার পক্ষে সময় লাগল, তবে কৌশলটি সহজ বলে মনে হচ্ছে ... 1. প্রথম উত্স কোড ফাইল থেকে কোডটি আমদানি করুন 2. এবং পুনরায় লোড করার জন্য বাধ্য করুন 3..rd ব্যবহার করুন.আর ফাংশনটাইপ (...) রূপান্তর করতে কোনও ফাংশনে আমদানিকৃত এবং আবদ্ধ পদ্ধতি আপনি বর্তমান বৈশ্বিক চলকগুলিতেও পাস করতে পারেন, কারণ পুনরায় লোড করা পদ্ধতিটি ভিন্ন নাম স্পেসের ৪ র্থ হতে পারে এখন আপনি টাইপস.মেথডটাইপ ব্যবহার করে "জেসন প্র্যাট" পরামর্শ অনুসারে চালিয়ে যেতে পারেন (... )

উদাহরণ:

# 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

3

যদি এটি কোনও উপকারে আসতে পারে তবে বানর প্যাচিংয়ের প্রক্রিয়াটিকে আরও সুবিধাজনক করার জন্য আমি সম্প্রতি গরিলা নামে একটি পাইথন গ্রন্থাগার প্রকাশ করেছি।

needle()নামের একটি মডিউলটি প্যাচ করার জন্য একটি ফাংশন ব্যবহার guineapigকরা নিম্নরূপ:

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

তবে এটি ডকুমেন্টেশন থেকে এফএকিউতে দেখানো হিসাবে আরও আকর্ষণীয় ব্যবহারের ক্ষেত্রেও যত্ন নেয় ।

কোডটি গিটহাবটিতে উপলব্ধ


3

এই প্রশ্নটি বেশ কয়েক বছর আগে খোলা হয়েছিল, তবে ওহে, সাজসজ্জার ব্যবহার করে কোনও শ্রেণীর উদাহরণের সাথে কোনও ফাংশনের বাঁধাই অনুকরণ করার সহজ উপায় রয়েছে:

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

সেখানে, যখন আপনি ফাংশনটি এবং দৃষ্টান্তটি বাইদার সজ্জাটির কাছে পাস করবেন, এটি একটি নতুন ফাংশন তৈরি করবে, প্রথমটির মতো একই কোড অবজেক্টের সাথে। তারপরে, শ্রেণীর প্রদত্ত উদাহরণ সদ্য নির্মিত ফাংশনের একটি বৈশিষ্ট্যে সংরক্ষণ করা হয়। সাজসজ্জারটি স্বয়ংক্রিয়ভাবে অনুলিপি করা একটি (তৃতীয়) ফাংশনটি অনুলিপি করে প্রথম পরামিতি হিসাবে উদাহরণ দেয়।

উপসংহারে আপনি একটি ফাংশন অনুকরণ করে যা এটি শ্রেণীর উদাহরণের সাথে বাধ্যতামূলক। আসল ফাংশনটি অপরিবর্তিত রাখা।


2

জেসন প্র্যাট যা পোস্ট করেছেন তা সঠিক।

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

যেমন আপনি দেখতে পাচ্ছেন, পাইথন খ () এর চেয়ে বি () এর চেয়ে আলাদা কিছু বিবেচনা করে না। পাইথনে সমস্ত পদ্ধতি কেবল ভেরিয়েবল যা ফাংশন হিসাবে ঘটে।


7
আপনি ক্লাসটি প্যাচ করছেন Test, এর উদাহরণ নয়।
ইথান ফুরম্যান

আপনি কোনও ক্লাসে পদ্ধতি যুক্ত করছেন, কোনও বস্তুর উদাহরণ নয়।
টমসওয়ায়ার

2

আমি এটি আশ্চর্যজনক মনে করি যে কেউ উল্লিখিত হয়নি যে উপরে তালিকাভুক্ত সমস্ত পদ্ধতি যুক্ত পদ্ধতি এবং উদাহরণের মধ্যে একটি চক্র রেফারেন্স তৈরি করে, যার ফলে আবর্জনা সংগ্রহের সময় অবধি অবিরত থাকবে। অবজেক্টটির শ্রেণি বাড়িয়ে একটি বর্ণনাকারী যুক্ত করার একটি পুরানো কৌশল ছিল:

def addmethod(obj, name, func):
    klass = obj.__class__
    subclass = type(klass.__name__, (klass,), {})
    setattr(subclass, name, func)
    obj.__class__ = subclass

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.