2009-11-08 60 views
2

想象你有一个IO重函数是这样的:Easy Python ASync。预编译器?

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

当然,你可以从装饰者访问功能代码(已编译),反汇编和破解它。你甚至可以访问它定义的模块的源并重新编译它。但我认为这不是必要的。下面是一个使用装饰发生器,其中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 
+0

使用发电机的好主意! 我制作了一个版本,可以开启和关闭主线程任何次数:code.activestate.com/recipes/576952由于某种原因,如果我使用glib,它会在随机地方出现死锁。我可能不得不问他们有关:) – 2009-11-10 19:07:54

2

可以使用导入挂钩来实现这一目标?

...但我个人认为这是一个有点讨厌。

如果你想,虽然走这条路线,基本上就是你会做的是:

  • 您添加的进口吊钩延期(如“.thpy”)
  • 那进口作为导入的结果,钩子负责(基本上)传递一些有效的代码。
  • 为有效代码提供与您正在导入的文件有效关联的参数。
  • 这意味着您的预编译器可以执行你喜欢上的方式源的任何转换

不利的一面:

  • 虽然以这种方式使用进口挂钩将工作,这将带来惊喜任何维护者或代码的生命。 (坏主意IMO)
  • 你这样做的方式依赖于imputil - 它已被删除在Python 3.0,这意味着你这样写的代码有一个有限的生命周期。

个人我不会去那里,但如果这样做,还有的地方做这样的事情是覆盖在一些细节Python Magazine的问题,我建议获得的是背部问题阅读它。 (由Paul McGuire撰写,2009年4月号,可能以PDF格式提供)。

具体说就是用imputil和pyparsing作为例子,但原理是一样的。

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) 
    ) 

有点丑与lambda表达式,但其实很简单,可能比使用预编译的招数更具可读性。

+0

问题出在哪里的情况下“...”被扩大,这是你想要做的不止一个在你得到答案后 如果Python有多行内联函数,那么可能会这样做,尽管如果在同一个块中有两个$调用,那么即使这样也会变得非常混乱。 – 2009-11-10 17:44:36