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

用python装饰整个库

  •  2
  • Hooked  · 技术社区  · 15 年前

    我对装饰师的想法还不太熟悉(我仍然想把脑袋绕在他们周围),但我认为我遇到了一个很适合他们的问题。我想在数学图书馆的所有功能中都布置一个班级。更具体地说,我的班级有两个成员, X 旗帜 . 什么时候? 旗帜 是的,我希望调用原始的数学函数。什么时候? 旗帜 是假的,我想回去 没有 .

    作为我要问的一个框架,这里是类:

    import math
    
    class num(object):
      def __init__(self, x, flag):
        self.x = x
        self.flag = flag
    
      def __float__(self):
        return float(self.x)
    

    因此,这项工作很好:

    a = num(3, True)
    print math.sqrt(a)
    

    然而,这应该(在我完美的世界里)回归 没有 :

    b = num(4, False)
    print math.sqrt(b)
    

    关于如何在整个函数库中应用这一点,有什么建议或提示吗?

    2 回复  |  直到 15 年前
        1
  •  5
  •   Alex Martelli    15 年前

    总的来说……:

    >>> class num(object):
    ...   def __init__(self, x, flag):
    ...     self.x = x
    ...     self.flag = flag
    ...   def __float__(self):
    ...     return float(self.x)
    ...   from functools import wraps
    >>> def wrapper(f):
    ...   @wraps(f)
    ...   def wrapped(*a):
    ...     if not all(getattr(x, 'flag', True) for x in a):
    ...       return None
    ...     return f(*(getattr(x, 'x', x) for x in a))
    ...   return wrapped
    ... 
    >>> import inspect
    >>> import math
    >>> for n, v in inspect.getmembers(math, inspect.isroutine):
    ...   setattr(math, n, wrapper(v))
    ... 
    
    >>> a = num(3, True)
    >>> print math.sqrt(a)
    1.73205080757
    >>> b = num(4, False)
    >>> print math.sqrt(b)
    None
    

    注意,这个包装器还包括 math (回来) None 如果 任何 自变量有 False .flag )并允许混合调用(其中一些参数是 num 其他的是实际的浮动)。

    适用于任何“在特定模块中包装所有功能”任务的关键部分是使用模块 inspect 获取模块中函数(内置或不内置)的所有名称和值 数学 以及对包装器的显式调用(与decorator语法相同的语义),以将该名称设置为 数学 模块。

        2
  •  6
  •   Chris B.    15 年前

    尽管你不需要 @decorator 语法。

    下面的代码从 math 将模块封装到当前模块的命名空间中,并将其封装到定义的装饰器中。它应该给你一个基本的想法。

    from functools import wraps
    def check_flag(func):
        @wraps(func)
        def _exec(x, *args, **kw):
            if getattr(x, 'flag', False):
                return None
    
            return func(x, *args, **kw)
    
        return _exec
    
    import sys, math
    _module = sys.modules[__name__]
    for func in ('exp', 'log', 'sqrt'):
        setattr(_module, func, check_flag(getattr(math, func)))
    

    能够 自动列出在 数学 模块,正如Alex所演示的,但是我认为显式包装您感兴趣的函数是更好的方法。

    推荐文章