我想知道装饰函数是否有办法引用装饰器的包装程序创建的对象。当我考虑使用装饰器进行装饰时,我的问题出现了:
但是,装饰函数需要引用包装器创建的图形。装饰函数如何引用该对象?我们是否必须使用全局变量?
这是一个简短的示例,其中我在修饰的函数中引用了在包装器中创建的变量(但在不调整全局变量的情况下,我无法做到这一点):
def my_decorator(func):
def my_decorator_wrapper(*args, **kwargs):
global x
x = 0
print("x in wrapper:", x)
return func(*args, **kwargs)
return my_decorator_wrapper
@my_decorator
def decorated_func():
global x
x += 1
print("x in decorated_func:", x)
decorated_func()
# prints:
# x in wrapper: 0
# x in decorated_func: 1
我知道在课堂上很容易做到这一点,但是出于好奇,我在问这个问题。
答案 0 :(得分:1)
是的,该函数可以通过查看自身来引用它。
如果看起来有点复杂,那是因为带有参数的装饰器需要这种特殊的结构才能工作。参见Decorators with parameters?
def declare_view(**kwds):
"""declaratively assocatiate a Django View function with resources
"""
def actual_decorator(func):
for k, v in kwds.items():
setattr(func, k, v)
return func
return actual_decorator
@declare_view(
x=2
)
def decorated_func():
#the function can look at its own name, because the function exists
#by the time it gets called.
print("x in decorated_func:", decorated_func.x)
decorated_func()
x in decorated_func: 2
实际上,我已经使用了很多。对我来说,这个想法是将Django视图功能与必须与之协作的特定后端数据类和模板相关联。因为它是声明性的,所以我可以对所有Django视图进行自省,并跟踪其关联的URL以及自定义数据对象和模板。效果很好,但是可以,该函数确实希望某些属性本身存在。它不知道是由装饰者设置的。
哦,在我的情况下,没有充分的理由将这些变量作为用例中的参数传递,这些变量具有从功能的POV基本上不变的,永远不变的硬编码值。
乍一看很奇怪,但是功能强大,并且没有运行时或维护方面的缺点。
下面是一些生动的示例,将其放在上下文中。
@declare_view(
viewmanager_cls=backend.VueManagerDetailPSCLASSDEFN,
template_name="pssecurity/detail.html",
objecttype=constants.OBJECTTYPE_PERMISSION_LIST[0],
bundle_name="pssecurity/detail.psclassdefn",
)
def psclassdefn_detail(request, CLASSID, dbr=None, PORTAL_NAME="EMPLOYEE"):
"""
"""
f_view = psclassdefn_detail
viewmanager = f_view.viewmanager_cls(request, mdb, f_view=f_view)
...do things based on the parameters...
return viewmanager.HttpResponse(f_view.template_name)
答案 1 :(得分:1)
尝试avoid using global variables。
有一种将值传递给函数的规范方法:参数。
调用包装程序时,将对象作为参数传递给修饰的函数。
from functools import wraps
def decorator(f):
obj = 1
@wraps(f)
def wrapper(*args):
return f(obj, *args)
return wrapper
@decorator
def func(x)
print(x)
func() # prints 1
如果需要将同一对象传递给所有函数,则可以将其存储为装饰器的默认参数。
from functools import wraps
def decorator(f, obj={}):
@wraps(f)
def wrapper(*args):
return f(obj, *args)
return wrapper
@decorator
def func(params)
params['foo'] = True
@decorator
def gunc(params)
print(params)
func()
# proof that gunc receives the same object
gunc() # prints {'foo': True}
以上内容创建了一个公用的专用dict
,只能由修饰的函数访问。由于dict
是可变的,因此更改将在函数调用中反映出来。
答案 2 :(得分:0)
This article指向类作为装饰器,这似乎是一种指向装饰器中定义的状态的更优雅的方法。它依赖于函数属性,并在装饰类中使用特殊的.__call__()
方法。
这是我的示例,其中使用类而不是函数作为修饰器:
class my_class_decorator:
def __init__(self, func):
self.func = func
self.x = 0
def __call__(self, *args, **kwargs):
print("x in wrapper:", self.x)
return self.func(*args, **kwargs)
@my_class_decorator
def decorated_func():
decorated_func.x += 1
print("x in decorated_func:", decorated_func.x)
decorated_func()
# prints:
# x in wrapper: 0
# x in decorated_func: 1