用Python装饰整个库

Hoo*_*ked 2 python decorator

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

作为我在这里要求的框架是这个类:

import math

class num(object):
  def __init__(self, x, flag):
    self.x = x
    self.flag = flag

  def __float__(self):
    return float(self.x)
Run Code Online (Sandbox Code Playgroud)

结果,这很好:

a = num(3, True)
print math.sqrt(a)
Run Code Online (Sandbox Code Playgroud)

然而,这应该(在我完美的世界),返回:

b = num(4, False)
print math.sqrt(b)
Run Code Online (Sandbox Code Playgroud)

有关如何应用于整个函数库的任何建议或提示?

Chr*_* B. 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)))
Run Code Online (Sandbox Code Playgroud)

可以自动化math模块中定义的函数列表,正如Alex演示的那样,但我认为明确地包含您感兴趣使用的函数是一种更好的方法.


Ale*_*lli 6

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

>>> 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
Run Code Online (Sandbox Code Playgroud)

请注意,此包装器还涵盖非一元函数math(None如果任何参数具有a,则返回False .flag)并允许其混合调用(其中一些args是实例,num其他是实际浮点数).

适用于任何"包装特定模块中的所有函数"任务的关键部分是使用模块inspect获取模块中函数的所有名称和值(内置与否)math,以及对包装器的显式调用(相同的语义)作为装饰器语法)将该名称设置为math模块中的包装值.