22

クラスのインスタンスを作成するときに関数と等しいクラス属性を定義すると、その属性がバインドされたメソッドになることに気付きました。誰かがこの動作の理由を説明できますか?

In [9]: def func():
   ...:     pass
   ...: 

In [10]: class A(object):
   ....:     f = func
   ....:     

In [11]: a = A()

In [12]: a.f
Out[12]: <bound method A.func of <__main__.A object at 0x104add190>>

In [13]: a.f()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-13-19134f1ad9a8> in <module>()
----> 1 a.f()
    global a.f = <bound method A.func of <__main__.A object at 0x104add190>>

TypeError: func() takes no arguments (1 given)
4

3 に答える 3

2

Python はメッセージ ベースのオブジェクト指向システムではありません1。代わりに、JavaScript と同様に、プロパティはファーストクラスの関数に解決されてから呼び出されます。発見されたように、動作はそのようなメカニズムで少し異なります。

Python の要件は、メソッドが少なくとも 1 つのパラメーター (通常は と呼ばれる) を持っていることです。このパラメーターは、メソッドとして呼び出されたときselfに関連付けられたインスタンスに自動的に提供されます。

さらに (そしておそらく質問のポイントまで)、Python はインスタンス メンバー バインディングを使用def f..する場合と確立する場合を区別しません。f = some_func()おそらく、これはクラス外の動作と一致します。

例では、関数をインスタンスに割り当てると、「インスタンス メソッドのように扱われることを期待するようになります」。どちらの場合も呼び出されるのは、まったく同じ (パラメーターなしの) 関数です。そのようなものの将来の使用のみが関連しています。

現在、JavaScript とは異なり、Python はバインドされたメソッドの概念を通じてメソッドとオブジェクトの関連付けを処理します。メソッドとして解決される関数は常に「バインド」されます。

a.fバインドされたメソッド (バインドされたオブジェクトを最初のパラメーターに自動的に提供する関数) を返す動作はself、関数のソースとは無関係に行われます。この場合、パラメーターを受け入れないため、「バインド」されている場合、パラメーターなしの関数を使用できないことを意味しselfます。

デモンストレーションとして、ソースの基になるメソッドがインスタンスを引数として受け入れるための最小要件を満たしていないため、以下は同じように失敗します。

g = a.f
g()

この場合、 を呼び出すことg()は を呼び出すことと同じfunc(a)です。


1比較のために、Java、C#、Ruby、および SmallTalk はメッセージ ベースのオブジェクト指向システムです。これらのシステムでは、メソッド (または関数) を呼び出すことができる値として解決する代わりに、オブジェクトは「名前」によってメソッドを呼び出すように指示されます。 .

于 2016-02-10T17:24:20.513 に答える
0

パーティーには少し遅れましたが、別の実行可能な解決策は、クラスの属性である辞書として関数を格納することです。

# Some arbitrary function
def f(x):
  return x

# A class, which will wrap the function as a dictionary object, which is a class attr
class Test:
  def __init__(self,f):
    self.f = {'f':f}
  
  def func(self,x):
    return self.f['f'](x)

# Now let's test the Test object
t = Test(f=f)
t.func(3)

>>>
3

このアプローチは、受け入れられている回答よりも冗長ですが、静的メソッド、デコレータ、またはその他の高度なトピックには触れていません。したがって、他の好ましいアプローチに怯えている場合、これはピンチで機能します。

編集:これをキーワード引数を処理するのに十分堅牢にしたい場合:

class Test:
  def __init__(self,f):
    self.f = {'f':f}
  
  def func(self,p):
    return self.f['f'](**p)

def f(**p):
  return p['x'] * p['y']

t = Test(f=f)
t.func({'x':2,'y':3})

>>>
6
于 2021-05-03T17:36:13.983 に答える