【问题标题】:Easy Python ASync. Precompiler?简单的 Python 异步。预编译器?
【发布时间】:2010-12-14 08:19:43
【问题描述】:

想象一下你有一个像这样的 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 部分)

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

你有什么想法,关于如何做上面的事情吗?

【问题讨论】:

    标签: python compiler-construction syntax asynchronous


    【解决方案1】:

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

    ...但我个人认为它有点讨厌。

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

    • 您为扩展添加了一个导入钩子(例如“.thpy”)
    • 该导入挂钩随后负责(本质上)作为导入的结果传递一些有效代码。
    • 为有效代码提供与您要导入的文件有效相关的参数。
    • 这意味着您的预编译器可以在输入的过程中对源代码执行任何您喜欢的转换。

    不利的一面:

    • 虽然以这种方式使用导入挂钩会起作用,但它会令任何维护者或您的代码的生命感到惊讶。 (国际海事组织的坏主意)
    • 您执行此操作的方式依赖于imputil - 它已在 python 3.0 中删除,这意味着您以这种方式编写的代码的生命周期有限。

    就个人而言我不会去那里,但如果你去那里,Python Magazine 有一个问题,其中详细介绍了做这种事情,我建议你找一个回过头来阅读它。 (由 Paul McGuire 撰写,2009 年 4 月号,可能以 PDF 格式提供)。

    具体以imputil和pyparsing为例,但原理是一样的。

    【讨论】:

      【解决方案2】:

      这样的事情怎么样:

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

      【讨论】:

      • 问题是'...'被扩展的情况,即你得到答案后想要做多行。如果 Python 有多行内联函数,那可能会这样做,尽管如果你在同一个块中有两个 $ 调用,即使这样也会变得非常混乱。
      【解决方案3】:

      当然你可以从装饰器访问函数代码(已经编译),反汇编和破解它。您甚至可以访问它定义的模块的源代码并重新编译它。但我认为这是没有必要的。下面是一个使用修饰生成器的示例,其中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
      

      【讨论】:

      • 使用生成器的好主意!我制作了一个可以随时打开和关闭主线程的版本:code.activestate.com/recipes/576952 由于某种原因,如果我使用 glib,它会在随机位置死锁。我可能不得不问他们这个:)
      猜你喜欢
      • 2016-05-12
      • 1970-01-01
      • 2018-12-25
      • 2021-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多