Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/287.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ajax/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用Python装饰整个库_Python_Decorator - Fatal编程技术网

用Python装饰整个库

用Python装饰整个库,python,decorator,Python,Decorator,我对装潢师的想法还不太熟悉(我仍在试图对他们进行思考),但我认为我遇到了一个非常适合他们的问题。我想要一个在数学库中所有函数上都有修饰的类。更具体地说,我的类有两个成员,x和flag。当flag为true时,我希望调用原始的数学函数。当标志为false时,我想返回无 作为我要问的问题的一个框架,这里有一节课: import math class num(object): def __init__(self, x, flag): self.x = x self.flag =

我对装潢师的想法还不太熟悉(我仍在试图对他们进行思考),但我认为我遇到了一个非常适合他们的问题。我想要一个在数学库中所有函数上都有修饰的类。更具体地说,我的类有两个成员,xflag。当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)
然而,这应该(在我的完美世界中)返回None

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

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

您可以为此使用decorator,尽管您不需要使用
@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演示的那样,您可以自动列出
数学
模块中定义的函数,但我认为明确包装您感兴趣的函数是一种更好的方法

这里是总体思路…:

>>> 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
中的非一元函数(如果任何参数具有
False
.flag
),则返回
None
),并允许对其进行混合调用(一些参数是
num
的实例,其他参数是实际浮点)


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

您意识到可以直接从Python中的
float
继承:
class my_float(float):pass
我认为您的答案使用了不适当的duck类型。在一个循环中,任何具有名为
flag
的成员的对象都被假定为
num
,而在另一个循环中,任何包含名为
x
的成员的对象都被假定为
num
。@Omnifarious,将任何其他类型的对象传递给math的函数都是错误的,因此我通过包装扩展math的函数,要同时接受具有这些属性的对象,类型检查将成为障碍。我还认为您的答案使用了不适当的duck类型。您应该使用
isinstance
,然后只需获取
标志的值即可。否则,传入的任何成员名为
flag
的内容都会被视为
num
。如果您向这些函数传递了大量无效输入,并且依赖函数拒绝这些输入,则您的代码会遇到更深层次的问题。感谢您的回答,通过学习你的代码和Alex的答案,我学到了很多。我只接受他的答案而不接受你的答案,因为它给了我一种按照要求包装整个库(带有inspect)的方法。不过,我可以从包装所需的函数中看出逻辑。再次感谢!