(itertools.chainと混同しないでください)
私は以下を読んでいました: http://en.wikipedia.org/wiki/Method_chaining
私の質問は:Pythonでメソッドチェーンを実装する最良の方法は何ですか?
これが私の試みです:
_class chain():
def __init__(self, my_object):
self.o = my_object
def __getattr__(self, attr):
x = getattr(self.o, attr)
if hasattr(x, '__call__'):
method = x
return lambda *args: self if method(*args) is None else method(*args)
else:
prop = x
return prop
list_ = chain([1, 2, 3, 0])
print list_.extend([9, 5]).sort().reverse()
"""
C:\Python27\python.exe C:/Users/Robert/PycharmProjects/contests/sof.py
[9, 5, 3, 2, 1, 0]
"""
_
1つの問題は、method(*args)
を呼び出すと_self.o
_が変更されてもNone
が返されない場合です。 (その後、self
を返すか、method(*args)
が返すものを返す必要があります)。
誰かが連鎖を実装するより良い方法を持っていますか?それを行うには、おそらく多くの方法があります。
メソッドが常にNone
を返すと仮定するだけでよいので、常に_self.o
_を返すことができますか?
私はClass
関数をチェーンするために似たようなものを探していましたが、良い答えは見つかりませんでした。そこで、私が何をして、非常に単純なチェーン方法だと思いました:self
オブジェクトを返すだけです。
だからここに私のセットアップです:
Class Car():
def __init__(self, name=None):
self.name = name
self.mode = 'init'
def set_name(self, name):
self.name = name
return self
def drive(self):
self.mode = 'drive'
return self
これで、車に名前を付けて、次のように呼び出してドライブ状態にすることができます。
my_car = Car()
my_car.set_name('Porche').drive()
警告:これは、データを返すつもりのないクラス関数でのみ機能します。
お役に立てれば!
非常に便利な Pipe
ライブラリがあり、これがあなたの質問の答えになるかもしれません。例えば::
seq = fib() | take_while(lambda x: x < 1000000) \
| where(lambda x: x % 2) \
| select(lambda x: x * x) \
| sum()
pure functions のみを使用して、メソッドがself.data
を直接変更せずに、変更されたバージョンを返すようにすることもできます。また、Chainable
インスタンスを返す必要があります。
リストで collection pipelining を使用する例を次に示します。
import itertools
try:
import builtins
except ImportError:
import __builtin__ as builtins
class Chainable(object):
def __init__(self, data, method=None):
self.data = data
self.method = method
def __getattr__(self, name):
try:
method = getattr(self.data, name)
except AttributeError:
try:
method = getattr(builtins, name)
except AttributeError:
method = getattr(itertools, name)
return Chainable(self.data, method)
def __call__(self, *args, **kwargs):
try:
return Chainable(list(self.method(self.data, *args, **kwargs)))
except TypeError:
return Chainable(list(self.method(args[0], self.data, **kwargs)))
次のように使用します。
chainable_list = Chainable([3, 1, 2, 0])
(chainable_list
.chain([11,8,6,7,9,4,5])
.sorted()
.reversed()
.ifilter(lambda x: x%2)
.islice(3)
.data)
>> [11, 9, 7]
.chain
はOPのchain
ではなくitertools.chain
を指すことに注意してください。
その特定のメソッドがどのように機能するかを知らないと、そのメソッドが返す値の種類と理由を知ることができないため、オブジェクトのメソッドをチェーンできるようにする一般的な方法はありません。メソッドは、何らかの理由でNone
を返す場合があります。メソッドがオブジェクトを変更したことを常に意味するわけではありません。同様に、値を返すメソッドでも、連鎖可能な値が返されない場合があります。 list.index
のようなメソッドをチェーンする方法はありません。fakeList.index(1).sort()
は機能する可能性があまりありません。index
の重要な点は、数値を返すということであり、その数値は何か、元のオブジェクトをチェーンするだけでは無視できません。
特定の特定のメソッド(並べ替えや削除など)をチェーン化するためにPythonの組み込み型をいじるだけの場合は、(ラッパークラスでオーバーライドすることにより)特定のメソッドを明示的にラップする方が、 __getattr__
を使用した一般的なメカニズム。