python:修改`globals`以动态地将事物置于范围内 [英] python: mutating `globals` to dynamically put things in scope

查看:57
本文介绍了python:修改`globals`以动态地将事物置于范围内的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个多么糟糕的主意?类monad实现了with接口以将事物放入和超出范围,因此我可以编写一个通用函数库,例如m_chain,它们引用函数unitbind,它们可以在运行时放入实现. (这些代码做什么或是否有个好主意都没有关系.)

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆