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
.任何人都可以想办法来改变这种做法,refresh
是True
没有指定什么时候?改变了
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)
因为刷新然后在第一种和第二种情况下被多次调用,而在最后一种情况下被调用一次(当它在第一种和第二种情况下应该是一次,而不是在最后一种情况下).
以线程安全的方式计算"嵌套"的数量是使用线程本地存储的一个很好的例子:
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)
大致按照文档中的建议(除了文档使用一个特殊的"私人"名称作为导入的结果,并没有真正的原因,所以我使用一个简单的名称;-).