2009-11-08 73 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