Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/317.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 如何正确使用装饰师?(TypeError:wrapper()接受0个位置参数,但给出了1个)_Python_Module_Package_Decorator_Python Decorators - Fatal编程技术网

Python 如何正确使用装饰师?(TypeError:wrapper()接受0个位置参数,但给出了1个)

Python 如何正确使用装饰师?(TypeError:wrapper()接受0个位置参数,但给出了1个),python,module,package,decorator,python-decorators,Python,Module,Package,Decorator,Python Decorators,我正在尝试编写一个装饰程序,在使用函数之前检查特定的包是否可用 在下面的示例中,numpy不应抛出错误,但不存在的测试包应通知用户需要安装包才能使用此功能。这一点是为了减少依赖性 基于@henry harutyunyan建议的更新 将numpy导入为np 导入导入库 def检查可用软件包(软件包): 如果isinstance(软件包、str): 软件包=[软件包] packages=np.asarray(已排序(集合(packages))) def包装器(func): 已安装=列表() 对于包

我正在尝试编写一个装饰程序,在使用函数之前检查特定的包是否可用

在下面的示例中,
numpy
不应抛出错误,但
不存在的测试包
应通知用户需要安装包才能使用此功能。这一点是为了减少依赖性

基于@henry harutyunyan建议的更新
将numpy导入为np
导入导入库
def检查可用软件包(软件包):
如果isinstance(软件包、str):
软件包=[软件包]
packages=np.asarray(已排序(集合(packages)))
def包装器(func):
已安装=列表()
对于包中包:
尝试:
globals()[package]=importlib.import\u模块(包)
已安装。追加(True)
除恐怖外:
已安装。追加(False)
已安装=np.asarray(已安装)
assert np.all(installed),“请安装以下软件包以使用此功能:\n{}.format(“,”.join(map(lambda x:“{}”.format(x),packages[~installed]))
返回函数
返回包装器
@检查可用的软件包([“numpy”])
def():
打印(“这起作用”)
@检查可用的测试包([“numpy”、“不存在的测试包”])
def():
打印(“这不应该起作用”)
# ---------------------------------------------------------------------------
#AssertionError回溯(上次最近的调用)
#在
#23打印(“这起作用”)
#      24 
#-->25@check\u available\u包([“numpy”,“不存在的\u test\u包])
#26 def():
#27打印(“这不应该起作用”)
#内包装(func)
#15已安装。追加(False)
#16已安装=np.asarray(已安装)
#-->17 assert np.all(installed),“请安装以下软件包以使用此功能:\n{}.format(“,”.join(map(lambda x:“{}”).format(x),packages[~installed]))
#18返回函数
#19返回包装器
#AssertionError:请安装以下软件包以使用此功能:
#“不存在测试包”
现在,decorator似乎是在运行时检查包是否存在,而不是在实际调用函数时检查包是否存在。如何调整此代码

这会有用的

将numpy导入为np
导入导入库
def检查可用软件包(软件包):
如果isinstance(软件包、str):
软件包=[软件包]
packages=np.asarray(已排序(集合(packages)))
def装饰器(func):
def包装器():
已安装=列表()
对于包中包:
尝试:
globals()[package]=importlib.import\u模块(包)
已安装。追加(True)
除恐怖外:
已安装。追加(False)
已安装=np.asarray(已安装)
assert np.all(installed),“请安装以下软件包以使用此功能:\n{}”(
“,”.join(包[~已安装])
func()
返回包装器
返回装饰器
@检查可用的软件包([“numpy”])
def foo():
打印(“这起作用”)
@检查可用的测试包([“numpy”、“不存在的测试包”])
def bar():
打印(“这不应该起作用”)
foo()
bar()
问题是您拥有的
wrapper()
函数正在接受一个参数,而根据定义,它不需要任何参数。因此,在这条语句中传递
包装器()将完成这项工作

\u
是虚拟的,它不能被使用,但它仍然是一些东西。IDE也不会抱怨未使用的变量


要仅在调用函数时执行decorator,需要如上所述使用decorator工厂。有关更多详细信息,请参阅。

如果希望在调用基础函数时进行检查,则需要对其进行额外的包装:

import functools

def check_available_packages(packages):
    if isinstance(packages,str):
        packages = [packages]
    packages = sorted(set(packages))
    def decorator(func):                # we need an extra layer of wrapping
        @functools.wraps(func)          # the wrapper replaces func in the global namespace
        def wrapper(*args, **kwargs):   # so it needs to accept any arguments that func does
            missing_packages = []       # no need for fancy numpy array indexing, a list will do
            for package in packages:
                try: 
                    globals()[package] = importlib.import_module(package)
                except ImportError:
                    missing_packages.append(package)
            assert not missing_packages, "Please install the following packages to use this functionality:\n{}".format(", ".join(missing_packages))
            return func(*args, **kwargs)  # call the function after doing the library checking!
        return wrapper
    return decorator

我从代码中删除了对
numpy
的依赖,这对我来说似乎完全没有必要,尤其是如果您正在测试是否安装了
numpy
,那么要求它来进行检查是没有意义的。

check\u available\u packages
是一家装饰工厂,它返回一个decorator,该decorator必须接受一个参数——要修饰的函数。见,谢谢。所以这是一种工作。除非调用了
f()
,否则我不希望对
check\u available\u包进行评估。现在,它看起来像是在运行时检查包,而不是在调用函数时检查包。我如何才能适应此功能?@O.rka Ohh我明白了,请将其添加到问题中,让我看看我们可以做什么。@O.rka修改为仅在调用该功能时执行。谢谢!这比以前干净多了。另外,谢谢你解释发生了什么。我需要进一步研究functools.wrapps。那么,当我没有额外的层
decorator
函数,只有
wrapper
时会发生什么呢?你不需要
functools.wrapps
,当你没有返回包装来代替原来的函数时,这真是太好了。它将
包装器
函数的
名称
文档
属性(以及其他一些东西,我忘记了所有细节)替换为
func
中的属性,这样以后就更容易了解函数的功能。没有它,装饰功能就可以正常工作。无论如何,如果没有额外的层,在应用装饰器时必须进行库检查,因为以后无法拦截对函数的调用。
import functools

def check_available_packages(packages):
    if isinstance(packages,str):
        packages = [packages]
    packages = sorted(set(packages))
    def decorator(func):                # we need an extra layer of wrapping
        @functools.wraps(func)          # the wrapper replaces func in the global namespace
        def wrapper(*args, **kwargs):   # so it needs to accept any arguments that func does
            missing_packages = []       # no need for fancy numpy array indexing, a list will do
            for package in packages:
                try: 
                    globals()[package] = importlib.import_module(package)
                except ImportError:
                    missing_packages.append(package)
            assert not missing_packages, "Please install the following packages to use this functionality:\n{}".format(", ".join(missing_packages))
            return func(*args, **kwargs)  # call the function after doing the library checking!
        return wrapper
    return decorator