想象你有一个像这样重要的功能:
def getMd5Sum(path):
with open(path) as f:
return md5(f.read()).hexdigest()
你认为Python足够灵活,允许这样的代码(注意$):
def someGuiCallback(filebutton):
...
path = filebutton.getPath()
md5sum = $getMd5Sum()
showNotification("Md5Sum of file: %s" % md5sum)
...
要执行这样的事情:
def someGuiCallback_1(filebutton):
...
path = filebutton.getPath()
Thread(target=someGuiCallback_2, args=(path,)).start()
def someGuiCallback_2(path):
md5sum = getMd5Sum(path)
glib.idle_add(someGuiCallback_3, md5sum)
def someGuiCallback_3(md5sum):
showNotification("Md5Sum of file: %s" % md5sum)
...
(glib.idle_add只是将一个函数推送到主线程的队列中)
我考虑过使用装饰器,但他们不允许我在调用后访问函数的“内容”。 (showNotification部分)
我想我可以编写一个'编译器'来在执行前更改代码,但它并不像最佳解决方案那样。
关于如何做上述事情,你有什么想法吗?
答案 0 :(得分:2)
您可以使用导入挂钩来实现此目标......
...但我个人认为它有点讨厌。
如果你想沿着这条路走下去,基本上你要做的就是:
缺点:
个人我不会去那里,但是如果你这样做,那么Python Magazine会出现一个问题,其中有一些细节,我会建议得到一个后面的问题来阅读它。 (由Paul McGuire撰写,2009年4月号,可能以PDF格式提供)。
特别是使用imputil和pyparsing作为例子,但原理是相同的。
答案 1 :(得分:1)
这样的事情怎么样:
def performAsync(asyncFunc, notifyFunc):
def threadProc():
retValue = asyncFunc()
glib.idle_add(notifyFunc, retValue)
Thread(target=threadProc).start()
def someGuiCallback(filebutton):
path = filebutton.getPath()
performAsync(
lambda: getMd5Sum(path),
lambda md5sum: showNotification("Md5Sum of file: %s" % md5sum)
)
使用lambdas有点难看,但它比使用预编译器技巧更简单,可能更具可读性。
答案 2 :(得分:0)
当然,您可以从装饰器访问功能代码(已编译),反汇编和破解它。您甚至可以访问其定义的模块源并重新编译它。但我认为这不是必要的。下面是使用装饰生成器的示例,其中yield
语句用作同步和异步部分之间的分隔符:
from threading import Thread
import hashlib
def async(gen):
def func(*args, **kwargs):
it = gen(*args, **kwargs)
result = it.next()
Thread(target=lambda: list(it)).start()
return result
return func
@async
def test(text):
# synchronous part (empty in this example)
yield # Use "yield value" if you need to return meaningful value
# asynchronous part[s]
digest = hashlib.md5(text).hexdigest()
print digest