用Python装饰整个库

时间:2010-07-07 03:54:01

标签: python decorator

我对装饰者的想法很新(并且仍然试图绕过他们),但我认为我遇到了一个非常适合他们的问题。我希望在数学库中包含所有函数的类。更具体地说,我的班级有两个成员, x 标志。当 flag 为true时,我想要调用原始数学函数。当标记为false时,我想返回

作为我在这里要问的一个框架是班级:

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 个答案:

答案 0 :(得分:6)

虽然您不需要@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)))

可以自动化math模块中定义的函数列表,正如Alex演示的那样,但我认为明确包装你感兴趣的函数是更好的方法走。

答案 1 :(得分:5)

这是一般的想法......:

>>> 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)允许混合调用(有些args是num的实例,其他是实际的浮点数。)

适用于任何“包装特定模块中的所有函数”任务的关键部分是使用模块inspect来获取模块{{1中的函数的所有名称和值(内置与否)并且显式调用包装器(与装饰器语法相同的语义)将该名称设置为math模块中的包装值。