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