刷新装饰

ast*_*rog 1 python algorithm decorator

我正在尝试编写一个在被调用后"刷新"的装饰器,但是在最后一个函数退出后只刷新一次.这是一个例子:

@auto_refresh
def a():
    print "In a"

@auto_refresh
def b():
    print "In b"
    a()
Run Code Online (Sandbox Code Playgroud)

如果a()被调用,我希望退出后运行刷新功能a().如果b()被调用,我希望刷新函数在退出b()后运行,而不是在a()调用之后运行b().以下是执行此操作的类的示例:

class auto_refresh(object):

def __init__(self, f):

    print "Initializing decorator"
    self.f = f

def __call__(self, *args, **kwargs):

    print "Before function"
    if 'refresh' in kwargs:
        refresh = kwargs.pop('refresh')
    else:
        refresh = False

    self.f(*args, **kwargs)

    print "After function"

    if refresh:
        print "Refreshing"
Run Code Online (Sandbox Code Playgroud)

有了这个装饰,如果我跑

b()
print '---'
b(refresh=True)
print '---'
b(refresh=False)
Run Code Online (Sandbox Code Playgroud)

我得到以下输出:

Initializing decorator
Initializing decorator
Before function
In b
Before function
In a
After function
After function
---
Before function
In b
Before function
In a
After function
After function
Refreshing
---
Before function
In b
Before function
In a
After function
After function
Run Code Online (Sandbox Code Playgroud)

因此,当以这种方式编写时,不指定refresh参数意味着刷新默认为False.任何人都可以想办法来改变这种做法,refreshTrue没有指定什么时候?改变了

refresh = False
Run Code Online (Sandbox Code Playgroud)

refresh = True
Run Code Online (Sandbox Code Playgroud)

在装饰并没有工作:

Initializing decorator
Initializing decorator
Before function
In b
Before function
In a
After function
Refreshing
After function
Refreshing
---
Before function
In b
Before function
In a
After function
Refreshing
After function
Refreshing
---
Before function
In b
Before function
In a
After function
Refreshing
After function
Run Code Online (Sandbox Code Playgroud)

因为刷新然后在第一种和第二种情况下被多次调用,而在最后一种情况下被调用一次(当它在第一种和第二种情况下应该是一次,而不是在最后一种情况下).

Ale*_*lli 5

以线程安全的方式计算"嵌套"的数量是使用线程本地存储的一个很好的例子:

import threading
mydata = threading.local()
mydata.nesting = 0

class auto_refresh(object):

  def __init__(self, f):
    self.f = f

  def __call__(self, *args, **kwargs):
    mydata.nesting += 1
    try: return self.f(*args, **kwargs)
    finally:
      mydata.nesting -= 1
      if mydata.nesting == 0:
        print 'refreshing'
Run Code Online (Sandbox Code Playgroud)

如果您不关心线程,只要您的Python安装在编译时启用了线程(现在几乎所有这些都是),这仍然可以正常工作.如果您担心没有线程的特殊Python安装,请将import语句更改为

try:
    import threading
except ImportError:
    import dummy_threading as threading
Run Code Online (Sandbox Code Playgroud)

大致按照文档中的建议(除了文档使用一个特殊的"私人"名称作为导入的结果,并没有真正的原因,所以我使用一个简单的名称;-).