3

インスタンス自体からインスタンス変数の一般的に使用されるメソッドを呼び出せるようにしたい状況があります。これは、プログラムが機能するために実際には必要ありません。bar.baz()ただし、とは対照的に、入力する方がはるかに便利bar.foo.baz()です。

これにアプローチするための最もPythonic/読み取り可能/最も一般的な方法は何でしょうか?関数デコレータを書こうと思っていました。しかし、私は他のアイデアを受け入れています。ソリューションは、継承に適している必要もあります。

例:

class Foo (object) :
    def baz (self) :
        return 324

class Bar (object) :
    def __init__ (self) :
        self.foo = Foo()

    # This is the current ugly solution.
    # It also results in an extra function call.
    def baz (self, *args, **kw) :
        return self.foo.baz(*args, **kw)

bar = Bar()
print bar.foo.baz()
print bar.baz() 

これはPython2.7.3、FYI用です。

4

3 に答える 3

4

と呼ばれることを行うことができますmixin。個人的な状態は実際にはありませんが、別のクラスに「ミックスイン」したい一般的な機能を備えたクラスを作成します。

class FooMixin(object) :
    def baz (self) :
        return 324

class Bar(object, FooMixin):
    def __init__ (self):
        pass

bar = Bar()
bar.baz()

*または、@Joachimが他の回答で提案しているような構成を使用します。

于 2012-08-10T05:41:08.413 に答える
2

これはもっと簡単です。

class Foo (object) :
    def baz (self) :
        return 324

class Bar (object) :
    def __init__ (self) :
        self.foo = Foo()
        self.baz = self.foo.baz;

bar = Bar()
print bar.foo.baz()
print bar.baz()
于 2012-08-10T05:40:55.150 に答える
1

それがただ1つの方法であるなら、あなたが持っているものは正直言ってそれほど悪くはありません。bazそれはのインターフェースの一部であると非常に率直に言っており、含まれているインスタンスBooに委任することでこれを実現しています。Foo

少し短いバージョンは、プロパティを使用することです。

class Foo (object) :
    def baz (self) :
        return 324

class Bar (object) :
    def __init__ (self) :
        self.foo = Foo()

    @property
    def baz(self):
        return self.foo.baz

    def __getattr__(self, attr):
        return getattr(self.foo, attr)

bar = Bar()
print bar.foo.baz()
print bar.baz()

bazただし、まだ余分な関数呼び出しがあり、メソッドであることが少しわかりにくいかもしれません。

baz継承ツリーを書き直すことに頼らずに、そのような含まれているインスタンスに委任する必要がある唯一のメソッドである場合は、あなたが持っているものを使用します。多くのメソッドを委任する場合は、いくつかのオプションがあります。

を含むインスタンスからすべてメソッドをFoo呼び出し可能にする場合は、次を使用してみてください。BarFoo__getattr__

class Foo (object) :
    def baz (self) :
        return 324

class Bar (object) :
    def __init__ (self) :
        self.foo = Foo()

    def __getattr__(self, attr):
        return getattr(self.foo, attr)

bar = Bar()
print bar.foo.baz()
print bar.baz()

しかし、これにはいくつかの明らかな欠点があります。

  1. Barソースコードを読んだり、内省したりして、実際にどのメソッドが提供するのかは明確ではありません。
  2. のすべてFooのメソッドと属性(によって直接提供されないBar)は、のインターフェイスを介して公開されBarますが、これは望ましくない場合があります。

もちろん、__getattr__メソッドにさらにロジックを追加して、すべてではなく特定のもののみを委任することもできます。

Barすべてのaがaの単純なラッパーである場合、私はこの種のアプローチを採用する傾向があります。これはFoo、「aBarはほとんどのように動作する」が(内部実装の詳細Fooではなく)概念インターフェイスの一部であり、それがのようではない方法を説明するための定義。FooBarFoo

もう1つのアプローチは、Pythonの動的な性質を使用して、すべてを手書きすることなく、Barそのデリゲートのプロパティを定義することです。Fooこのような何かがトリックを行います:

class Foo (object) :
    def baz (self) :
        return 324

class Bar (object) :
    def __init__ (self) :
        self.foo = Foo()

    for _method in ['baz', 'blob']:
        @property
        def _tmp_func(self, _name=_method):
            return getattr(self.foo, _name)
        locals()[_method] = _tmp_func
    # del to avoid name pollution
    del _method, _tmp_func

bar = Bar()
print bar.foo.baz()
print bar.baz()

このアプローチの利点は__getattr__、コードを読んでいるときにリダイレクトされるメソッドの明示的なリストがあり、それらはすべて通常のプロパティであるBarため、実行時にの通常のプロパティのように見えることです。ただし、これが1つまたは2つのメソッドにのみ必要な場合は、明らかに元のコードよりもはるかに多くのコードになります。そしてそれは少し微妙です( Pythonのクロージャが機能する方法のためにデフォルトの引数_method_tmp_func介して渡す必要があることは必ずしも明白ではありません)。ただし、クラスデコレータでこれを行うためのロジックをパッケージ化するのは比較的簡単です。これにより、メソッドの一部の実装を属性の1つに委任するクラスをさらに作成できるようになります。

あなたが思いつくことができるこれらの種類のものには多くのバリエーションがあります。

于 2012-08-10T06:47:07.487 に答える