1. ホーム
  2. パイソン

[解決済み】既存のオブジェクトインスタンスにメソッドを追加する

2022-03-23 17:26:25

質問

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

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

どのように解決するのですか?

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

バインドされたメソッドはインスタンスに "bound"(どのように記述するか)されており、メソッドが呼び出されるたびにそのインスタンスが最初の引数として渡されます。

しかし、(インスタンスではなく)クラスの属性である callables はまだ束縛されていないので、好きなときにクラス定義を変更することができます。

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

問題は、1つのインスタンスにメソッドをアタッチしたい場合です。

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

より詳しい情報は、以下をご覧ください。 記述子 メタクラス プログラミング .