цепочка методов в python
(не путать с itertools.цепь)
Я читал следующее: 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:Python27python.exe C:/Users/Robert/PycharmProjects/contests/sof.py
[9, 5, 3, 2, 1, 0]
"""
одна проблема-если вызов method(*args)
изменение self.o
а не None
. (тогда я должен вернуться self
или вернуть то, что method(*args)
возвращает.)
есть ли у кого-нибудь лучшие способы реализации цепочки? Есть наверное много способов сделать это.
должен ли я просто предположить, что метод всегда возвращает None
Так что я всегда могу вернуться self.o
?
3 ответов
есть очень удобнаяPipe
библиотека, которая может быть ответом на ваш вопрос. Например:
seq = fib() | take_while(lambda x: x < 1000000) \
| where(lambda x: x % 2) \
| select(lambda x: x * x) \
| sum()
это возможно, если вы используете только чистые функции чтобы методы не изменялись self.data
напрямую, но вместо этого верните измененную версию. Вы также должны вернуть Chainable
экземпляров.
вот пример использования коллекция конвейеризация со списками:
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
относится к itertools.chain
и не ОП chain
.
не будет никакого общего способа разрешить какой-либо метод любого объекта быть прикованным, так как вы не можете знать, какое значение этот метод возвращает и почему, не зная, как этот конкретный метод работает. Методы могут возвращать None
по любой причине; это не всегда означает, что метод изменяет объект. Аналогично, методы, которые возвращают значение, все равно могут не возвращать значение, которое может быть приковано. Нет способа связать такой метод, как list.index
: fakeList.index(1).sort()
не может иметь большие надежды работы, потому что весь смысл index
он возвращает число, и это число что-то значит, и его нельзя игнорировать только для цепочки исходного объекта.
если вы просто возитесь со встроенными типами Python для цепочки определенных конкретных методов (например, sort и remove), вам лучше просто обернуть эти конкретные методы явно (переопределив их в своем классе-оболочке), а не пытаться сделать общий механизм с __getattr__
.