Как написать ленивые функции, которые являются цепочечными, в Python? - PullRequest
2 голосов
/ 16 июня 2010

Я хочу написать функции, которые являются ленивыми и цепными. Что было бы лучшим способом. Я знаю, что одним из способов было бы сделать yield вместо return.

Я хочу, чтобы эти функции были ленивыми, подобно тому, как функции sqlalchemy ленивы, когда их просят извлечь данные из БД.

1 Ответ

6 голосов
/ 16 июня 2010
Генераторы

(функции с yield вместо return) действительно могут рассматриваться как "ленивые" (и itertools.chain может связывать их так же, как и любой другой итератор, если вы это подразумеваете под "цепью").

Но если под «цепочкой» (и ленивым) вы подразумеваете, что хотите позвонить fee().fie().fo().fum(), и вся «тяжелая работа» происходит только в fum (что похоже на то, что делает SQLAlchemy)тогда генераторы не помогут - вам нужен шаблон проектирования «Обещание», где каждая функция / метод (кроме той, которая фактически выполняет всю работу) возвращает объект, который записывает все условия, параметры и ограниченияна операции, и одна трудолюбивая функция использует эту информацию, чтобы наконец выполнить работу.

Чтобы привести очень простой пример, скажем, что «тяжелая работа» выполняет вызов RPC вида remote(host, **kwargs).Вы можете одеть это в «ленивую цепную одежду» следующим образом:

class RPC(object):
    def __init__(self, host):
        self._host = host
        self._kws = {}
    def doit(self, **morekws):
        return remote(self._host, **dict(self._kws, **morekws))
    def __getattr__(self, name):
        def setkw(value):
            self._kws[name] = value
            return self
        return setkw

Теперь RPC(x).foo('bar').baz('bap').doit() вызывает remote(x, foo=bar, baz=bap) (и, конечно, вы можете сохранять промежуточные этапы цепочки, передавая их в качестве аргументови т. д. и т. п. до звонка на doit).

...