既存のオブジェクトインスタンスへのメソッドの追加


643

Pythonで既存のオブジェクト(つまり、クラス定義ではない)にメソッドを追加することが可能であることを読みました。

私はそうすることが常に良いとは限らないことを理解しています。しかし、これをどうやって行うのでしょうか?

回答:


921

Pythonでは、関数とバインドされたメソッドの間に違いがあります。

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

これをバインドするには、typesモジュールのMethodType関数を使用できます

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

2
@MartijnPieters は、多分もう少し読みやすくなることを別にして、descriptor protocolvsを使用する利点がありMethodTypeます。
EndermanAPM 2017年

17
@EndermanAPM:いくつか:インスタンスの属性にアクセスするのとまったく同じように動作し続ける可能性が高くなります。それはのために働くだろうclassmethodstaticmethodし、他の記述子すぎ。さらに別のインポートで名前空間が乱雑になるのを防ぎます。
Martijn Pieters

34
推奨される記述子アプローチの完全なコードはa.barFighters = barFighters.__get__(a)
eqzx

98

新しいモジュールはpython 2.6から非推奨になり、3.0で削除されました。型を使用してください

http://docs.python.org/library/new.htmlを参照してください

以下の例では、patch_me()関数から意図的に戻り値を削除しています。戻り値を与えることは、patchが新しいオブジェクトを返すと信じさせるかもしれないと思います、それは真実ではありません-それは入ってくるものを変更します。おそらくこれは、モンキーパッチのより規律ある使用を容易にすることができます。

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
追加されるメソッドが自分自身を参照する必要がある場合、これはどのように機能しますか?私の最初の試みは構文エラーにつながりますが、メソッドの定義にselfを追加してもうまくいかないようです。インポートタイプクラスA(オブジェクト):#しかし、古いスタイルのオブジェクトでも機能するようですax = 'ax' pass def patch_me(target):def method(target、x):print(self.ax)print( "x =" 、x)print( "from from"、target)target.method = types.MethodType(method、target)#必要に応じてさらに追加a = A()print(a.ax)
WesR

85

序文-互換性に関する注意:他の回答はPython 2でのみ機能する可能性があります-この回答はPython 2および3で完全に機能するはずです。Python3のみを作成する場合は、からの明示的な継承を省略できますがobject、それ以外の場合、コードは同じままです。 。

既存のオブジェクトインスタンスへのメソッドの追加

Pythonの既存のオブジェクト(クラス定義ではないなど)にメソッドを追加することが可能であることを読みました。

そうすることが常に良い決定とは限らないことを理解しています。しかし、どうすればこれを行うことができますか?

はい、可能ですが、お勧めできません

これはお勧めしません。これは悪い考えです。しないでください。

これにはいくつかの理由があります。

  • これを行うすべてのインスタンスにバインドされたオブジェクトを追加します。これをたくさん行うと、おそらく多くのメモリを浪費するでしょう。バインドされたメソッドは通常、呼び出しの短い期間にのみ作成され、自動的にガベージコレクションが行われると存在しなくなります。これを手動で行うと、バインドされたメソッドを参照する名前バインディングが作成され、使用時にガベージコレクションが行われなくなります。
  • 特定のタイプのオブジェクトインスタンスには、通常、そのタイプのすべてのオブジェクトに対するメソッドがあります。他の場所にメソッドを追加すると、一部のインスタンスにはそれらのメソッドが含まれ、その他のインスタンスには含まれません。プログラマーはこれを期待しないでしょう、そしてあなたは最小の驚きのルールに違反する危険を冒します。
  • これを行わない理由は他にもあるので、そうすると評判が悪くなります。

したがって、本当に正当な理由がない限り、これを行わないことをお勧めします。次のように、クラス定義で正しいメソッドを定義するか、それほど好ましくはありませんが、クラスを直接モンキーパッチする方がはるかに優れています

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

メソッド1-types.MethodType

まず、型をインポートします。そこからメソッドコンストラクターを取得します。

import types

次に、メソッドをインスタンスに追加します。これを行うには、typesモジュール(上記でインポートしたもの)のMethodTypeコンストラクターが必要です。

types.MethodTypeの引数シグネチャは次のとおりです(function, instance, class)

foo.sample_method = types.MethodType(sample_method, foo, Foo)

および使用法:

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

方法2:字句バインディング

まず、メソッドをインスタンスにバインドするラッパー関数を作成します。

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

方法3:functools.partial

部分関数は、最初の引数を関数(およびオプションでキーワード引数)に適用し、後で残りの引数(およびキーワード引数のオーバーライド)を使用して呼び出すことができます。したがって:

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

これは、バインドされたメソッドがインスタンスの部分的な関数であると考える場合に意味があります。

オブジェクト属性としての非バインド関数-これが機能しない理由:

クラスに追加する場合と同じ方法でsample_methodを追加しようとすると、インスタンスからバインド解除され、暗黙のselfを最初の引数として取りません。

>>> 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
免責事項は、私が思っていたものです。メソッド定義は、単にクラス定義内にネストされた関数です。
Atcold

1
@Atcold導入部でこれを回避する理由を拡大しました。
アーロンホール

この__get__メソッドには、次のパラメータとしてクラスも必要ですsample_method.__get__(foo, Foo)
Aidas Bendoraitis

2
@AidasBendoraitis「​​必要」とは言いませんが、これは記述子プロトコルを適用するときに提供されるオプションのパラメーターですが、Python関数は引数を使用しません:github.com/python/cpython/blob/master/Objects/funcobject .c#L581
アーロンホール

私のコメントはこのリファレンスに基づいていました:python-reference.readthedocs.io/en/latest/docs/dunderdsc/… 公式ドキュメントから今見ると、これはオプションです:docs.python.org/3/howto/descriptor.html#記述子プロトコル
アイダスベンドラティス

35

上記の答えは要点を逃したと思います。

メソッドを持つクラスを作ってみましょう:

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

それでは、ipythonで遊んでみましょう。

In [2]: A.m
Out[2]: <unbound method A.m>

さて、m()はどういうわけかAのバインドされていないメソッドになります。しかし、それは本当にそうですか?

In [5]: A.__dict__['m']
Out[5]: <function m at 0xa66b8b4>

これは、ことが判明メートル()がに追加されているだけの機能、リファレンスである魔法はありません-クラスの辞書。では、なぜAmは非拘束メソッドを提供するのでしょうか。これは、ドットが単純な辞書検索に変換されないためです。これは、事実上のA .__ class __.__ getattribute __(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

さて、なぜ最後の行が2度印刷されるのか、頭の上ではわからないのですが、何が起こっているのかは明らかです。

ここで、デフォルトの__getattribute__が行うことは、属性がいわゆる記述子であるかどうか、つまり、特別な__get__メソッドを実装しているかどうかをチェックすることです。そのメソッドを実装している場合、返されるのはその__get__メソッドを呼び出した結果です。Aクラスの最初のバージョンに戻ると、次のようになります。

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

また、Python関数は記述子プロトコルを実装しているため、オブジェクトの代わりに呼び出された場合、__ get__メソッドでそのオブジェクトにバインドされます。

では、既存のオブジェクトにメソッドを追加する方法は?パッチクラスを気にしなければ、次のように簡単です。

B.m = m

次に、Bmは記述子マジックのおかげで、バインドされていないメソッドになります。

また、単一のオブジェクトにのみメソッドを追加する場合は、types.MethodTypeを使用して、自分で機構をエミュレートする必要があります。

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

20

Pythonでは、モンキーパッチは通常、クラスまたは関数のシグネチャを独自のもので上書きすることで機能します。以下はZope Wikiの例です:

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

そのコードは、クラスで話すというメソッドを上書き/作成します。Jeff Atwoodの最近のサルのパッチに関する投稿。彼はC#3.0の例を示しています。これは、私が現在使用している言語です。


6
ただし、1つのインスタンスだけでなく、クラスのすべてのインスタンスに影響ます。
glglgl 2014年

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

なしでインスタンスにメソッドをアタッチするには、少なくとも2つの方法があります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
イーサンファーマン2011

5
setattr(A,'printme',printme)単に使用する代わりに使用する理由はありA.printme = printmeますか?
Tobias Kienzler 2013

1
実行時にメソッド名を作成することは理にかなっています。
rr-

6

この質問はPython以外のバージョンを要求するため、ここにJavaScriptがあります。

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

5

Jason Prattとコミュニティwikiの回答を統合し、さまざまなバインディング方法の結果を確認します。

特に、クラスメソッドとして結合機能を追加する方法を注意した作品が、参照範囲が正しくありません。

#!/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 )て問題を解決します
Antony Hatchkins '

5

これは実際には「Jason Pratt」の答えのアドオンです

Jasonsの回答は機能しますが、クラスに関数を追加したい場合にのみ機能します。.pyソースコードファイルから既存のメソッドをリロードしようとしても、うまくいきませんでした。

回避策を見つけるのに何年もかかりましたが、トリックは単純なようです... 1.ソースコードファイルからコードをインポートします。2.リロードを強制します。3.タイプを使用します。Type.FunctionType(...)を変換します。インポートされ、関数にバインドされたメソッドは、現在のグローバル変数に渡すこともできます。リロードされたメソッドは別の名前空間にあるため、types.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

3

それが何らかの助けになるかもしれない場合、私は最近、Gorillaという名前のPythonライブラリをリリースして、サルのパッチ適用プロセスをより便利にしました。

needle()という名前のモジュールにパッチを当てる関数を使用するとguineapig、次のようになります。

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

しかし、ドキュメントのFAQに示されているように、より興味深いユースケースも処理します。

コードはGitHubで入手できます


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

そこで、関数とインスタンスをバインダーデコレーターに渡すと、最初の関数と同じコードオブジェクトで新しい関数が作成されます。次に、指定されたクラスのインスタンスが、新しく作成された関数の属性に格納されます。デコレーターは、コピーされた関数を自動的に呼び出す(3番目の)関数を返し、インスタンスを最初のパラメーターとして指定します。

結論として、クラスインスタンスへのバインディングをシミュレートする関数を取得します。元の機能を変更させない。


2

Jason Prattが投稿したものは正しいです。

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

ご覧のとおり、Pythonはb()とa()の違いを考慮していません。Pythonでは、すべてのメソッドはたまたま関数である単なる変数です。


7
クラスTestのインスタンスではなく、クラスにパッチを適用しています。
イーサンファーマン2011

オブジェクトのインスタンスではなく、クラスにメソッドを追加しています。
TomSawyer

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.