Packaged
-> hachibeeDI / letexpr
C'est une histoire
Monade d'État en Python J'écrivais cet article et je voulais une expression let comme Haskell en Python, alors j'y ai pensé.
Ensuite, dans le post associé Créez une programmation en une ligne Parce qu'il y avait quelque chose comme ça, je vais faire du bien de le détourner. J'ai pensé, mais j'ai abandonné la diversion parce que cela ressemble à appliquer. Alors je ferai de mon mieux.
L'expression let semble se lier à l'intérieur du let et évaluer l'expression avec in. De plus, il semble que les variables liées dans let puissent être référencées à partir de l'expression let entière.
Pour le moment, lions le résultat à quelque chose de variable afin qu'il puisse être utilisé dans
class let(object):
def __init__(self, action=None):
if action is None:
name, act = action
self.lets = {name: act()}
else:
self.lets = {}
def __or__(self, action):
''' :type action: (str, func) '''
name, f = action
self.lets[name] = f()
return self
def in_(self, func):
return func(**self.lets)
if __name__ == '__main__':
x = let(('xx', lambda : 1 + 2)) | ('y', lambda : 'yyy') | ('z', lambda : 5)
print x.in_(lambda xx, y, z: str(xx) + y + str(z))
C'est devenu une forme pour le moment. Cependant, comme c'est le cas, il n'est pas possible de faire référence à la valeur entre les expressions let, donc je vais le faire sentir bien.
Comme mentionné ci-dessus, en Python, vous pouvez passer une valeur à l'argument correspondant à la clé en passant un ** dictionnaire
à l'argument de la fonction, mais contrairement à certains langages populaires, l'argument Une erreur sera lancée pour excès ou insuffisance.
En d'autres termes, il vous suffit de transmettre les valeurs dont chacun a besoin dans les résultats stockés dans self.lets_
.
Dans un tel cas, le module ʻinspect est pratique, alors utilisez la fonction
getargspec` pour ne transmettre que les arguments nécessaires.
from inspect import getargspec
class let(object):
def __init__(self, action=None):
if action is not None:
name, act = action
self.lets = {name: act()}
else:
self.lets = {}
def __or__(self, action):
''' :type action: (str, func) '''
name, f = action
require_arg_keys = getargspec(f).args
self.lets[name] = f(
**self.__extract_require_args(require_arg_keys)
)
return self
def __extract_require_args(self, arg_keys):
return {k: v for k, v in self.lets.iteritems() if k in arg_keys}
def in_(self, func):
require_arg_keys = getargspec(func).args
return func(
**self.__extract_require_args(require_arg_keys)
)
Maintenant, essayons de passer une expression qui nécessite en fait divers arguments. Rendons le retrait cool.
measure = \
(let()
| ('x', lambda : 10)
| ('y', lambda : 20)
| ('size', lambda x, y: x * y)
| ('hoge', lambda x, y: 'fooo')
) \
.in_(lambda x, y, size:
'x = {x}, y = {y}, x * y = {size}'.format(x=x, y=y, size=size))
print measure # => x = 10, y = 20, x * y = 200
Vous l'avez fait, pas vous. Dans la situation actuelle, nous évaluons de haut en bas, nous ne pouvons donc pas obtenir la valeur supérieure du lambda inférieur, mais si nous faisons de notre mieux pour retarder l'évaluation de l'expression, nous pourrons le faire également. Je suis d'accord. Je pensais que la normale est la meilleure parce que celui qui l'a écrit normalement peut le lire normalement.
Recommended Posts