2011-11-30 16 views
9

私はちょうどあなたがPythonでこれを行うことができますことに気づいた。つまりPythonのクラスレスメソッドは何にも役立ちますか?

def f(self): 
    print self.name 

class A: 
    z=f 
    name="A" 

class B: 
    z=f 
    name = "B" 

...

print a.z() 

>>> A 

、任意のクラスで定義されていませんが、に取り付けることができる方法のようなf()振る舞います1。もちろん、それが存在しないオブジェクトに添付されているオブジェクトのメソッドやフィールドが必要な場合は、ランタイムエラーが発生します。

私の質問:これは便利ですか?それは目的を果たすか?それが問題を解決する状況はありますか?多分それはインターフェイスを定義する方法でしょうか?

答えて

6

から詳細をお読みください目的もありますが、これを行う必要はまれです。クラスを定義した後でクラスにパッチを適用する必要があると思うなら、それが本当に最善の方法であるかどうかを常に止めて検討する必要があります。

1つの状況は、猿のパッチです。私は大規模なPloneシステムでこれをやったことがありますが、いくつかのメソッドには微妙な調整が必要でしたが、正常に動作をオーバーライドする簡単な方法はありませんでした。複雑なライブラリがある状況では、元のライブラリを変更することなく、新しい動作や変更された動作を簡単に挿入できます。

その他の状況では、自動的に生成できるメソッドがたくさんある場合があります。例えばデータ駆動テスト。

def createTest(testcase, somedata, index): 
    def test(self): 
     "Do something with somedata and assert a result" 
    test_name = "test_%d" % index 
    setattr(testcase, test_name, test) 

for index, somedata in enumerate(somebigtable): 
    createTest(MyTestCase, somedata, index) 

MyTestCaseがたunittest.TestCaseのときにデータのすべてを通過するが、それが失敗したデータの行を把握しようとするために持っているよりも最初の失敗で停​​止し、あなたの一つのテストを持つことができます。メソッドを動的に作成することで、すべてのテストが別々に実行され、テスト名によってどの名前が失敗したかがわかります(上のコードの元は実際にはデータの一部とインデックスを含む意味のある名前を作成しました)。

定義が完了する前に、クラス自体またはその辞書を参照する方法がないため、クラス本体の内部ではその操作を行うことはできません。しかし、メタクラスと似たようなことをすることができます。それは、クラス自体を作成する前にクラスを修正することができます。また、同じことを行うよりきれいな方法です。

注意すべき点は、これが機能しない状況があることです。一部の__xxx__特殊メソッドは、クラスの作成後にオーバーライドできません。元の定義はクラスの__dict__以外の場所に保存されるため、後で変更する場合は無視される可能性があります。また、メタクラスで作業する場合、メタクラスがクラス定義の一部として属性に与える処理を追加機能で取得できないことがあります。

+0

興味深い!これはまた、他の価値がクラスの中心ではないメソッドの定義を他の場所に移しているかもしれないことを示唆しています。明らかに特別な状況のために。 –

2

興味深い事実:Pythonで

  1. 機能がタイプです:だから

    type(f) # prints <type: function> 
    
  2. 、関数が呼び出し可能なインスタンスであるので、どこにでも接続することができます。

  3. 機能を移植可能にし、プラグアンドプレイ機能をエミュレートするために使用できます。

  4. これは、開発中に、本当に便利です - 私たちは、インポート機能を持つクラスメソッドを置き換えることができますので、さまざまなロジックを試すために(異なる機能をプラグインすることで)

  5. これは、ロジックの上に抽象化を提供します。

しかし、私はそれを使ってインターフェイスをエミュレートすることはできません。

3

関数オブジェクトには__get __(...)メソッドがあるため、非データ記述子です。

あなたは、クラスAにメソッドを定義するとき、それは.__ dict__にでちょうど関数オブジェクトです:

In [78]: class A(object): 
    ....:  def f1(self): 
    ....:   pass 
    ....: 

In [79]: A.__dict__["f1"] 
Out[79]: <function f1 at 0x0D39A070> 

いますが、属性によって、インスタンスまたはクラスからこの関数を得るとき、あなたはバインドメソッドまたは結合していないメソッドを取得します。

In [80]: A.f1 
Out[80]: <unbound method A.f1> 

In [81]: A().f1 
Out[81]: <bound method A.f1 of <__main__.A object at 0x0D2F1CD0>> 

これは方法の仕組みです。だから、あなたは後者の方法を追加することができます。

In [82]: A.f2 = lambda self: id(self) 

In [83]: A().f2() 
Out[83]: 221189392 

をだからあなたのコードはほとんど同じです:

class A: 
    def z(self): 
     print self.name 
    name="A" 

はい、それは有用であり、それが機能しないhttp://docs.python.org/howto/descriptor.html

+0

はい、このイディオムは何にも役立ちますか? –

関連する問題