web-dev-qa-db-ja.com

基本的なメソッドチェーン

これを見つけました pythonでのメソッドチェーン ですが、それでもPythonでのメソッドチェーンを理解できませんでした。

ここでの目標は2つです。コーディングの問題を解決し、メソッドチェーンを理解します(呼び出し可能オブジェクトに100%自信がない場合)。

問題の定義まで。

2つのメソッドを持つクラスが必要です。1つはobject = 'line'のパラメーターを設定し、もう1つは 'bar'に上書きします。

これは私がこれまでに得たものです:

class foo():
    def __init__(self, kind=None):
        self.kind = kind

    def __call__(self, kind=None):
        return foo(kind=kind)

    def my_print(self):
        print (self.kind)

    def line(self):
        return self(kind='line')
    def bar(self):
        return self(kind='bar')

悲しいことに、このコードでこれを行う私の目標を達成することができます

a = foo()
a.bar().line().bar().bar().line().my_print()

しかし、私はこのコードを書いて同じ結果を得たい

a = foo()
a.bar.line.bar.bar.line.my_print()

どうすればこれを達成できますか? __call__メソッドの定義方法に問題があると思います。よろしくお願いします。

22
Pezze

メソッドチェーンは、.second_func()が返すものに.first_func()を追加するだけです。すべてのチェーン可能なメソッドがselfを返すようにすることで、かなり簡単に実装できます。 (これは__call()__とは関係ないことに注意してください)。

_class foo():
    def __init__(self, kind=None):
        self.kind = kind
    def my_print(self):
        print (self.kind)
        return self
    def line(self):
        self.kind = 'line'
        return self
    def bar(self):
        self.kind='bar'
        return self
_

戻り値を無視することにより、チェーンなしでfooオブジェクトを使用できます。

_a = foo()
a.line()
a.my_print()
a.bar()
a.my_print()

assert a.kind == 'bar'
_

または、すべての関数がオブジェクト自体を返すようになったため、返された値を直接操作できます。この同等のコードでメソッドチェーンを使用できます。

_b = foo()
b.line().my_print().bar().my_print()
assert b.kind == 'bar'
_

あるいは:

_c = foo().line().my_print().bar().my_print()
assert c.kind == 'bar'
_

_()_呼び出し構文を取り除く問題は、完全に分離した概念メソッドチェーンからです。チェーンプロパティが必要で、それらのプロパティでオブジェクトを変更する場合は、_@property_デコレータを使用します。 (ただし、プロパティを介したオブジェクトの変更は危険なようです。メソッドを使用し、動詞で名前を付ける方が良いでしょう。たとえば、_.line_の代わりに.set_line()です。)

_class foo():
    def __init__(self, kind=None):
        self.kind = kind
    def my_print(self):
        print (self.kind)
        return self
    @property
    def line(self):
        self.kind = 'line'
        return self
    @property
    def bar(self):
        self.kind='bar'
        return self

a = foo()
a.line
a.my_print()
a.bar
a.my_print()

assert a.kind == 'bar'

b = foo()
b.line.my_print().bar.my_print()
assert b.kind == 'bar'

c = foo().line.my_print().bar.my_print()
assert c.kind == 'bar'
_
44
Robᵩ

プロパティ(記述子)を使用します。

class foo:
    def __init__(self, kind=None):
        self.kind = kind

    def __call__(self, kind=None):
        return foo(kind=kind)

    def my_print(self):
        print (self.kind)

    @property
    def line(self):
        return self(kind='line')

    @property
    def bar(self):
        return self(kind='bar')

ただし、何も上書きしないことに注意してください。変更はインプレースでは機能しません(これは間違いなく良いことです)。とにかく、ほとんどの実際のケースでは、これは適切な設計選択のようには見えません。ある時点でメソッドが引数を必要とするからです。

4
Eli Korvigo