===============>>#1 票数:52 已采纳
你不能 作用域名称(闭包)在编译时确定,不能在运行时添加更多。
您可以期望实现的最好结果是使用函数自己的全局名称空间添加全局名称:
def decorator_factory(value):
def msg_decorator(f):
def inner_dec(*args, **kwargs):
g = f.__globals__ # use f.func_globals for py < 2.6
sentinel = object()
oldvalue = g.get('var', sentinel)
g['var'] = value
try:
res = f(*args, **kwargs)
finally:
if oldvalue is sentinel:
del g['var']
else:
g['var'] = oldvalue
return res
return inner_dec
return msg_decorator
f.__globals__是包装函数的全局名称空间,因此即使装饰器位于其他模块中,该函数也可以使用。 如果已将var定义为全局变量,则将其替换为新值,并在调用函数后恢复全局变量。
之所以可行,是因为在函数中任何未分配给且在周围范围内都找不到的名称都被标记为全局名称。
演示:
>>> c = 'Message'
>>> @decorator_factory(c)
... def msg_printer():
... print var
...
>>> msg_printer()
Message
>>> 'var' in globals()
False
但是除了修饰之外,我还可以直接在全局范围内定义var 。
请注意,更改全局变量不是线程安全的,并且对同一模块中其他函数的任何瞬时调用也仍将看到该相同的全局变量。
===============>>#2 票数:6
这是一种将多个变量注入函数范围的方法,其方式类似于@Martijn Pieters在其答案中所做的 。 我主要张贴,因为它是一个更广泛的解决方案,就不需要使用多次这样做-正如他(和许多其他的)答案是必需的。
from functools import wraps
def inject_variables(context):
""" Decorator factory. """
def variable_injector(func):
@wraps(func)
def decorator(*args, **kwargs):
try:
func_globals = func.__globals__ # Python 2.6+
except AttributeError:
func_globals = func.func_globals # Earlier versions.
saved_values = func_globals.copy() # Shallow copy of dict.
func_globals.update(context)
try:
result = func(*args, **kwargs)
finally:
func_globals = saved_values # Undo changes.
return result
return decorator
return variable_injector
if __name__ == '__main__':
namespace = {'a': 5, 'b': 3}
@inject_variables(namespace)
def test():
print('a:', a)
print('b:', b)
test()
===============>>#3 票数:5
你不能 Python具有词法作用域 。 这意味着标识符的含义仅取决于查看源代码时实际围绕其的范围。
===============>>#4 票数:3
Python具有词法范围,因此,恐怕没有没有可能的讨厌副作用的干净方法来做您想要的事情。 我建议只通过装饰器将var传递给函数。
c = 'Message'
def decorator_factory(value):
def msg_decorator(f):
def inner_dec(*args, **kwargs):
res = f(value, *args, **kwargs)
return res
inner_dec.__name__ = f.__name__
inner_dec.__doc__ = f.__doc__
return inner_dec
return msg_decorator
@decorator_factory(c)
def msg_printer(var):
print var
msg_printer() # prints 'Message'
===============>>#5 票数:3
有一种不使用全局变量即可执行所需操作的干净方法。 如果您想成为无状态线程安全的对象,那么您别无选择。
使用“ kwargs”变量:
c = 'Message'
def decorator_factory(value):
def msg_decorator(f):
def inner_dec(*args, **kwargs):
kwargs["var"] = value
res = f(*args, **kwargs)
return res
return inner_dec
return msg_decorator
@decorator_factory(c)
def msg_printer(*args, **kwargs):
print kwargs["var"]
msg_printer()
===============>>#6 票数:1
def merge(d1, d2):
d = d1.copy()
d.update(d2)
return d
# A decorator to inject variables
def valueDecorator(*_args, **_kargs):
def wrapper(f):
def wrapper2(*args, **kargs):
return f(*args, **kargs)
wrapper2.__name__ = f.__name__
wrapper2.__doc__ = f.__doc__
oldVars = getattr(f, 'Vars', [])
oldNamedVars = getattr(f, 'NamedVars', {})
wrapper2.Vars = oldVars + list(_args)
wrapper2.NamedVars = merge(oldNamedVars, _kargs)
return wrapper2
return wrapper
@valueDecorator(12, 13, a=2)
@valueDecorator(10, 11, a=1)
def func():
print(func.Vars)
print(func.NamedVars)
与其修改全局范围,不如更改带注释的函数本身更为合理。
===============>>#7 票数:0
这是使用修饰符将变量添加到函数范围内的简单演示。
>>> def add_name(name):
... def inner(func):
... # Same as defining name within wrapped
... # function.
... func.func_globals['name'] = name
...
... # Simply returns wrapped function reference.
... return func
...
... return inner
...
>>> @add_name("Bobby")
... def say_hello():
... print "Hello %s!" % name
...
>>> print say_hello()
Hello Bobby!
>>>
===============>>#8 票数:0
假设在python函数中是对象,则可以执行...
#!/usr/bin/python3
class DecorClass(object):
def __init__(self, arg1, arg2):
self.a1 = arg1
self.a2 = arg2
def __call__(self, function):
def wrapped(*args):
print('inside class decorator >>')
print('class members: {0}, {1}'.format(self.a1, self.a2))
print('wrapped function: {}'.format(args))
function(*args, self.a1, self.a2)
return wrapped
@DecorClass(1, 2)
def my_function(f1, f2, *args):
print('inside decorated function >>')
print('decorated function arguments: {0}, {1}'.format(f1, f2))
print('decorator class args: {}'.format(args))
if __name__ == '__main__':
my_function(3, 4)
结果是:
inside class decorator >>
class members: 1, 2
wrapped function: (3, 4)
inside decorated function >>
decorated function arguments: 3, 4
decorator class args: (1, 2)
===============>>#9 票数:0
更新__globals__对我__globals__ 。
def f():
print(a)
def with_context(**kw):
def deco(fn):
g = fn.__globals__
g.update(kw)
return fn
return deco
with_context(a=3)(f)() # 3
===============>>#10 票数:0
我发现使用全局变量的解决方案存在问题。
当您有多个并发请求时,全局上下文可能会被覆盖。 我以为那是不可能的,但这是-过了一段时间,如果请求不是很快的话,我就赶上了上下文(全局变量)的更改。 更好的解决方案是使用kwargs传递变量:
def is_login(old_fuction):
def new_function(request, *args, **kwargs):
secret_token = request.COOKIES.get('secret_token')
if secret_token:
items = SomeModel.objects.get(cookie = secret_token)
if len(items) > 0:
item = items[0]
kwargs['current_user'] = item
return old_fuction(request, *args, **kwargs)
else:
return HttpResponse('error')
return HttpResponse(status=404)
return new_function
@is_login
def some_func(request, current_user):
return HttpResponse(current_user.name)
您必须为每个装饰函数添加额外的参数。
ask by beardc translate from so