我对装饰者的想法很新(并且仍然试图绕过他们),但我认为我遇到了一个非常适合他们的问题。我希望在数学库中包含所有函数的类。更具体地说,我的班级有两个成员, 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)
有关如何在整个函数库中应用这些内容的任何建议或提示吗?
答案 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
模块中的包装值。