【问题标题】:python: mutating `globals` to dynamically put things in scopepython:变异`globals`以动态地将事物放在范围内
【发布时间】:2012-07-21 16:53:06
【问题描述】:

这是多么可怕的想法? monad 类实现 with 接口以将事物放入和超出范围,因此我可以编写一个通用函数库,例如 m_chain 引用函数 unitbind 可以在运行时放入实现. (所有这些代码的作用或它是否是一个好主意都无关紧要。)

我尝试过的其他想法都围绕着传递一个包含 unit/bind 作为参数或 kwarg 的结构,或者将 m_chain 放在一个类中,根据 self.unit 和 self.bind 实现它,并让派生类提供它们.但它增加了代码和语法的复杂性,并将单元/绑定绑定到 monad 在 python 中的表达方式。为此使用范围感觉好多了。

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

【问题讨论】:

  • 似乎合法。我对一些答案很感兴趣。我挖掘了效果,让您可以根据需要换入和换出功能的变体。如果有缺点,我看不到。我可能会小心提供m_chains 将要使用的函数的默认定义,或者如果未设置它们,则抛出一个有意义的异常,否则我可以看到一些像样的应用程序。

标签: python monads


【解决方案1】:

我认为不断打鸭式全局变量绝对是一个糟糕的主意。依赖全局变量似乎与您在此处模拟的功能样式相反。

为什么不将 m_chain 定义为:

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 风格,并且似乎不会导致您失去任何灵活性。

【讨论】:

    猜你喜欢
    • 2018-02-24
    • 2010-10-23
    • 1970-01-01
    • 2020-02-18
    • 1970-01-01
    • 2015-10-14
    • 1970-01-01
    • 1970-01-01
    • 2011-08-09
    相关资源
    最近更新 更多