代码之家  ›  专栏  ›  技术社区  ›  Thomas Ahle

简单的python异步。Precompiler?

  •  2
  • Thomas Ahle  · 技术社区  · 15 年前

    假设您有这样一个IO重函数:

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

    我想我可以在执行之前编写一个“编译器”来更改代码,但它不像最佳解决方案那样无缝。

    你对如何做上述事情有什么想法吗?

    3 回复  |  直到 15 年前
        1
  •  0
  •   Denis Otkidach    15 年前

    当然,您可以从decorator访问函数代码(已经编译过),分解并破解它。您甚至可以访问它在中定义的模块的源并重新编译它。但我认为这是不必要的。下面是一个使用装饰生成器的示例,其中 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
    
        2
  •  2
  •   Michael Sparks    15 年前

    您可以使用导入挂钩来实现此目标…

    …但我个人认为这有点讨厌。

    如果你想沿着这条路走,基本上你要做的是:

    • 为扩展名添加导入挂钩(例如“.thpy”)。
    • 然后,这个导入钩子负责(本质上)作为导入的结果传递一些有效的代码。
    • 有效的代码被赋予与您要导入的文件有效相关的参数。
    • 这意味着您的预编译程序可以在进入时执行任何您喜欢的到源代码的转换。

    不利方面:

    • 虽然以这种方式使用导入钩子是可行的,但它会让任何维护人员或代码的生命感到惊讶。(坏主意IMO)
    • 你这样做的方式取决于 imputil -它已经在python 3.0中被删除,这意味着用这种方式编写的代码的生命周期是有限的。

    亲自 我不会去的,但如果你去的话,有一个问题是 Python Magazine 做这类事情的地方会有一些详细的介绍,我建议把这方面的背景资料读一下。(由Paul McGuire撰写,2009年4月发行,可能以PDF格式提供)。

    特别是使用 亚胺基 和pyparsing的例子一样,但原理是相同的。

        3
  •  1
  •   interjay    15 年前

    像这样的怎么样:

    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有点难看,但它很简单,可能比使用预编译技巧更易读。