2010-06-16 4 views
2

Je veux écrire des fonctions aussi paresseuses que chaînables. Quel serait le meilleur moyen. Je sais que l'one-way serait de faire yield au lieu de return. Je veux que ces fonctions soient paresseuses de la même manière que les fonctions de sqlalchemy sont paresseuses lorsqu'on leur demande de récupérer les données de DB.Comment écrire des fonctions paresseuses qui sont chaînables, en python?

+3

Pouvez-vous donner un exemple? –

Répondre

5

Générateurs (fonctions avec yield au lieu de return) peuvent en effet être considérés comme « paresseux » (et itertools.chain peut les enchaîner tout aussi bien que tout autre iterator, si c'est ce que vous entendez par « chainable »).

Mais si par « chainable » (et paresseux) que vous voulez dire que vous voulez appeler fee().fie().fo().fum() et ont tout le « travail » se produire que dans fum (qui semble plus proche de ce SQLAlchemy fait), alors générateurs ne va pas aider - - ce dont vous avez besoin, c'est le modèle de conception "Promise", où chaque fonction/méthode (sauf celle qui fait tout le travail) renvoie un objet qui enregistre toutes les conditions, les paramètres et les contraintes de l'opération, et l'un fonction laborieuse utilise cette information pour finalement effectuer le travail.

Pour donner un exemple très simple, dites que "le travail acharné" effectue un appel RPC de la forme remote(host, **kwargs). Vous pouvez habiller cela dans « vêtements chainable paresseux » comme suit:

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 

Maintenant, RPC(x).foo('bar').baz('bap').doit() appels remote(x, foo=bar, baz=bap) (et bien sûr, vous pouvez enregistrer les étapes intermédiaires de la chaîne, les passer autour comme arguments, etc, etc, jusqu'à ce que l'appel au doit).

+0

peut-on faire quelque chose de similaire avec des fonctions seules, sans utiliser de classes? – roopesh

+1

@roopesh, chaque appel de fonction doit renvoyer un objet de type _some_, ce qui permet de "chaîner", c'est-à-dire d'appeler d'autres méthodes arbitraires: quel type prédéfini avez-vous en tête pour appeler une méthode arbitraire? instances? Il n'y en a pas - chaque type intégré a un ensemble bien défini de méthodes, et vous ne pouvez pas faire appel à ses méthodes d'instances autres que celles-ci, bien sûr. Donc, il est évident que ** a ** pour être un type codé par l'utilisateur ... qui est également connu comme "une classe". La contrainte «chainable» est clairement le principal déterminant de ceci - quelle que soit la raison pour laquelle vous l'avez définie. –

Questions connexes