代码之家  ›  专栏  ›  技术社区  ›  Wang

截获函数调用的Pythonic方法?

  •  4
  • Wang  · 技术社区  · 14 年前

    os.getenv , sys.version 等等),使查询撒谎通常比实际伪造环境更方便。这里有一个上下文管理器,它为一个 一次呼叫:

    from __future__ import with_statement
    from contextlib import contextmanager
    import os
    
    @contextmanager
    def fake_env(**fakes):
        '''fakes is a dict mapping variables to their values. In the
        fake_env context, os.getenv calls try to return out of the fakes
        dict whenever possible before querying the actual environment.
        '''
    
        global os
        original = os.getenv
    
        def dummy(var):
            try: return fakes[var]
            except KeyError: return original(var)
    
        os.getenv = dummy
        yield
        os.getenv = original
    
    if __name__ == '__main__':
    
        print os.getenv('HOME') 
        with fake_env(HOME='here'):
            print os.getenv('HOME') 
        print os.getenv('HOME') 
    

    操作系统获取环境 如果我允许有多个参数的函数,语法会变得有点笨拙。我猜是在 ast code / exec / eval 我可以扩展它,将要重写的函数作为一个参数,但不是很干净。同时,我也会在去格林斯潘第十届的路上。有更好的办法吗?

    2 回复  |  直到 14 年前
        1
  •  4
  •   Alex Martelli    14 年前

    你很容易就通过了 os.getenv 作为第一个参数,然后在上下文管理器中分析它 ast code 等等:

    >>> os.getenv.__name__
    'getenv'
    >>> os.getenv.__module__
    'os'
    

    之后,为了合理的通用性,可以返回result对象,或者从参数(可能是元组)到结果的映射。这个 faker 上下文管理器还可以选择性地接受一个用于伪造的可调用函数。

    例如,非常简单:

    import sys
    
    def faker(original, fakefun):
    
        original = os.getenv
        themod = sys.modules[original.__module__]
        thename = original.__name__
    
        def dummy(*a, **k):
            try: return fakefun(*a, **k)
            except BaseException: return original(*a, **k)
    
        setattr(themod, thename, dummy)
        yield
        setattr(themod, thename, original)
    

    你的具体例子可以是:

    with faker(os.getenv, dict(HOME='here').__getitem__):
       ...
    

    当然,如果您希望传播某些异常而不是将其绑定到原始函数,或者在某些常见情况下提供fakefun callable很笨拙,那么可能需要稍微复杂一点,等等。但是没有理由要这样一个普通的骗子 许多的 比你特定的更复杂。

        2
  •  1
  •   Katriel    14 年前

    为什么不自己写(假的) sys os ,&c。模块?

    import fakeSys as sys