これを見つけました 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__
メソッドの定義方法に問題があると思います。よろしくお願いします。
メソッドチェーンは、.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'
_
プロパティ(記述子)を使用します。
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')
ただし、何も上書きしないことに注意してください。変更はインプレースでは機能しません(これは間違いなく良いことです)。とにかく、ほとんどの実際のケースでは、これは適切な設計選択のようには見えません。ある時点でメソッドが引数を必要とするからです。