python内存注入代码_python - 如何使用装饰器将变量注入作用域? - 堆栈内存溢出...

===============>>#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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值