装饰者和全局

时间:2017-11-17 19:07:02

标签: python python-2.7 python-decorators

该应用程序有一个模块A,其中包含一个装饰器,它将函数添加到列表中,该列表是A中的模块级全局。函数列表用于模块中的其他函数。

A.py

import functools


things = []


def register(func):
    @functools.wraps(func)
    def inner(*args, **kwargs):
        things.append(func)
        return func
    return inner


@register
def foo():pass


@register
def bar():pass


foo()
bar()

print(things)

此模式已复制到应用程序的其他部分,因此许多模块包含寄存器功能和模块级列表。

我希望通过在一个位置实现A.register来减少重复量,但导入的模块需要拥有自己的本地功能列表。

我尝试导入A并创建提供列表:

B.py

import A

things = []


@A.register
def baz():pass


@A.register
def quux():pass


baz()
quux()

print(things)

但所有功能都在A.things注册:

>>> import A
[<function foo at 0x7f3ecdf466e0>, <function bar at 0x7f3ecdf467d0>]
>>> import B
[]
>>> print A.things
[<function foo at 0x7f3ecdf466e0>, <function bar at 0x7f3ecdf467d0>, <function baz at 0x7f3ecdf46410>, <function quux at 0x7f3ecdf469b0>]

有没有办法单独实现A.register,但要在其导入的模块中填充列表?那是

>>> print A.things
[<function foo at 0x7f3ecdf466e0>, <function bar at 0x7f3ecdf467d0>] 


>>> print B.things
[<function baz at 0x7f3ecdf46410>, <function quux at 0x7f3ecdf469b0>]

3 个答案:

答案 0 :(得分:1)

您在模块A中只有register()函数的单一实现。
模块B中没有变量things,它[变量]仅属于模块A.

即使你在模块B中使用装饰器,它也是模块A中将被追加的变量things

要记住的另一个非常重要的一点是每次调用函数时都会附加变量things

如果您无法在每个模块中更改算法声明变量 things 并创建这样的装饰器:

(来自ryachza的代码)

def register(things=things):
    def _register(func):
        @functools.wraps(func)
        def inner(*args, **kwargs):
            things.append(func)
            return func

        return inner

    return _register

但是,这不是使用装饰器的方法。

您可以在每个模块中创建一个变量things,然后像这样添加它。您不必为此使用装饰器。

things = []


def foo():
    pass


things.append(foo)


def bar():
    pass


things.append(bar)

foo()
bar()

print(things)

答案 1 :(得分:1)

不完全相同但可能令人满意,您可以定义register,如:

def register(things=things):
  def _register(func):
    @functools.wraps(func)
    def inner(*args, **kwargs):
      things.append(func)
      return func
    return inner
  return _register

A中使用,如:

@register()
def foo():pass

@register()
def bar():pass

B之中:

@A.register(things)
def baz():pass

@A.register(things)
def quux():pass

如果需要,甚至可以这样:

@A.register(A.things)
def whatever():pass

答案 2 :(得分:0)

我可能需要对现有代码进行少量修改的其他答案的替代方法是更改​​模块B,如:

...
things = []
A.things = things

@A.register
def baz():pass
...

基本上你所引用的任何东西都是可变的(在这种情况下是A.things)。您当然可以保存对原始A.things的引用,并在需要时在单个模块之间进行交换。