python:修改`globals`以动态地将事物置于范围内 [英] python: mutating `globals` to dynamically put things in scope
问题描述
这是一个多么糟糕的主意?类monad
实现了with
接口以将事物放入和超出范围,因此我可以编写一个通用函数库,例如m_chain,它们引用函数unit
和bind
,它们可以在运行时放入实现. (这些代码做什么或是否有个好主意都没有关系.)
how terrible an idea is this? class monad
implements the with
interface to put things in and out of scope, so i can write a library of generic functions like m_chain who refer to functions unit
and bind
who can have an implementation put in at runtime. (It doesn't matter what all this code does or if it's a good idea.)
我尝试过的其他想法都是围绕传递包含unit/bind作为参数或kwarg的结构,或将m_chain放在类中,以self.unit和self.bind的方式实现,并派生类提供它们.但它增加了代码和语法的复杂性,并将单位/绑定与python中monads的表达方式绑定在一起.使用范围对此感觉好多了.
other ideas i tried all revolved around passing around a structure containing unit/bind as an argument or a kwarg, or putting m_chain in a class, implement it in terms of self.unit and self.bind and having derived classes provide them. but it added complexity to the code and syntax and tied unit/bind to the way monads are expressed in python. using scope for this just feels so much nicer.
class monad:
"""Effectively, put the monad definition in lexical scope.
Can't modify the execution environment `globals()` directly, because
after globals().clear() you can't do anything.
"""
def __init__(self, monad):
self.monad = monad
self.oldglobals = {}
def __enter__(self):
for k in self.monad:
if k in globals(): self.oldglobals[k]=globals()[k]
globals()[k]=self.monad[k]
def __exit__(self, type, value, traceback):
"""careful to distinguish between None and undefined.
remove the values we added, then restore the old value only
if it ever existed"""
for k in self.monad: del globals()[k]
for k in self.oldglobals: globals()[k]=self.oldglobals[k]
def m_chain(*fns):
"""returns a function of one argument which performs the monadic
composition of fns"""
def m_chain_link(chain_expr, step):
return lambda v: bind(chain_expr(v), step)
return reduce(m_chain_link, fns, unit)
identity_m = {
'bind':lambda v,f:f(v),
'unit':lambda v:v
}
with monad(identity_m):
assert m_chain(lambda x:2*x, lambda x:2*x)(2) == 8
maybe_m = {
'bind':lambda v,f:f(v) if v else None,
'unit':lambda v:v
}
with monad(maybe_m):
assert m_chain(lambda x:2*x, lambda x:2*x)(2) == 8
assert m_chain(lambda x:None, lambda x:2*x)(2) == None
推荐答案
我认为不断地对全局变量进行鸭式打孔绝对是一个糟糕的主意.依赖全局变量似乎是您在此处模拟的功能样式的对立面.
I think continuously duckpunching globals is definitely a terrible idea. Relying on globals seems like the antithesis of the functional style you're emulating here.
为什么不将m_chain定义为:
Why not define m_chain as:
def m_chain(bind, *fns):
"""returns a function of one argument which performs the monadic
composition of fns"""
def m_chain_link(chain_expr, step):
return lambda v: bind(chain_expr(v), step)
return reduce(m_chain_link, fns, unit)
然后:
identity_m = {
'bind':lambda v,f:f(v),
'unit':lambda v:v
}
with monad(identity_m):
assert m_chain(lambda x:2*x, lambda x:2*x)(2) == 8
变得简单:
assert m_chain(lambda v,f:f(v), lambda x:2*x, lambda x:2*x)(2) == 8
实际上,显式地传递函数似乎更具有Python风格,并且似乎不会导致您失去任何灵活性.
Actually passing the function explicitly seems more pythonic and doesn't seem to cause you to lose any flexibility.
这篇关于python:修改`globals`以动态地将事物置于范围内的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!