2012-05-09 85 views
3

對於git alias problem,我希望能夠通過名稱從文件中選擇一個Python函數。例如:Bash腳本從文件中選擇一個Python函數

... 
    def notyet(): 
     wait for it 

    def ok_start(x): 
     stuff 
     stuff 
     def dontgettrickednow(): 
     keep going 
    #stuff 
     more stuff 

    def ok_stop_now(): 

在算法方面,以下就足夠了近:當你發現一個匹配/^(\s*)def $1[^a-zA-Z0-9]/

  • 保持匹配的行,直到找到一條線是

    1. 開始過濾^\s*#^/\1\s](即,可能是縮進的註釋,或比上一個更長的縮進)

    (我並不在乎是否拾取了以下函數之前的裝飾器。結果是爲人類閱讀。)

    我試圖用awk(我幾乎不知道)做到這一點,但它比我想象的有點困難。對於初學者,我需要一種方法來存儲原始def之前的縮進長度。

  • 回答

    3

    單向使用awk。代碼很好評論,所以我希望它很容易理解。

    內容infile

    含量 script.awk
    ... 
        def notyet(): 
         wait for it 
    
        def ok_start(x): 
         stuff 
         stuff 
         def dontgettrickednow(): 
         keep going 
        #stuff 
         more stuff 
    
        def ok_stop_now(): 
    

    BEGIN { 
         ## 'f' variable is the function to search, set a regexp with it. 
         f_regex = "^" f "[^a-zA-Z0-9]" 
    
         ## When set, print line. Otherwise omit line. 
         ## It is set when found the function searched. 
         ## It is unset when found any character different from '#' with less 
         ## spaces before it. 
         in_func = 0 
    } 
    
    ## Found function. 
    $1 == "def" && $2 ~ f_regex { 
    
         ## Get position of first 'd' in the line. 
         i = index($0, "d") 
    
         ## Sanity check. Never should success because the condition was 
         ## checked before. 
         if (i == 0) { 
           next 
         } 
    
         ## Get characters until matched index before, check that all of 
         ## them are spaces, and get its length. 
         indent = substr($0, 0, i - 1) 
         if (indent ~ /^[[:space:]]*$/) { 
           num_spaces = length(indent) 
         } 
    
         ## Set variable, print line and read next one. 
         in_func = 1 
         print 
         next 
    } 
    
    ## When we are inside the function, line doesn't begin with '#' and 
    ## it's not a blank line (only spaces). 
    in_func == 1 && $1 ~ /^[^#]/ && $0 ~ /[^[:space:]]/ { 
    
         ## Get how many characters there are until first non-space. The result 
         ## is the position of first non-blank, so substract one to get the number 
         ## of spaces. 
         spaces = match($0, /[^[:space:]]/) 
         spaces -= 1 
    
         ## If current indent is less or equal that the indent of function definition, then 
         ## end of function found, so end processing. 
         if (spaces <= num_spaces) { 
           in_func = 0 
         } 
    } 
    
    ## Self-explanatory. 
    in_func == 1 { 
         print 
    } 
    

    運行它喜歡:

    awk -f script.awk -v f="ok_start" infile 
    

    隨着下面的輸出:

    def ok_start(x): 
         stuff 
         stuff 
         def dontgettrickednow(): 
         keep going 
        #stuff 
         more stuff 
    
    +0

    哇,真棒:)我可以確認它適用於我的真實世界功能。一個有趣的方面是,如果有兩個具有相同名稱的函數(如果它們處於不同的類中,可能會發生),它會從頭到尾返回它們兩個。不確定這是否是有意的(或者確實是什麼正確的行爲應該是) - 看起來是一個好的結果。 –

    +0

    @SteveBennett:我只是在編輯修改該行爲。現在它應該只處理找到的第一個函數。 – Birei

    +0

    我有點像「選擇所有具有相同名稱的函數」版本 - 否則我不知道如何訪問具有相同名稱的第二個函數。 –

    3

    爲什麼不只是讓python做到這一點?我認爲inspection模塊可以打印出一個功能的來源,所以你可以導入模塊,選擇功能並檢查它。不掛斷。幫你解決方案...

    好的。原來,inspect.getsource功能交互方式定義的東西不起作用:

    >>> def test(f): 
    ...  print 'arg:', f 
    ... 
    >>> test(1) 
    arg: 1 
    >>> inspect.getsource(test) 
    Traceback (most recent call last): 
        File "<stdin>", line 1, in <module> 
        File "C:\Python27\lib\inspect.py", line 699, in getsource 
        lines, lnum = getsourcelines(object) 
        File "C:\Python27\lib\inspect.py", line 688, in getsourcelines 
        lines, lnum = findsource(object) 
        File "C:\Python27\lib\inspect.py", line 529, in findsource 
        raise IOError('source code not available') 
    IOError: source code not available 
    >>> 
    

    但對你的使用情況,它會工作:對於保存到磁盤模塊。就拿我test.py文件:

    def test(f): 
        print 'arg:', f 
    
    def other(f): 
        print 'other:', f 
    

    而且比較這個交互式會話:

    >>> import inspect 
    >>> import test 
    >>> inspect.getsource(test.test) 
    "def test(f):\n print 'arg:', f\n" 
    >>> inspect.getsource(test.other) 
    "def other(f):\n print 'other:', f\n" 
    >>> 
    

    所以......你需要寫一個接受Python源文件名的簡單的Python腳本和一個函數/對象名稱作爲參數。然後它應該導入模塊並檢查功能並將其打印到STDOUT。

    +0

    我喜歡你的想法,但它看起來像Python必須能夠解析整個項目 - 這意味着檢查一切,而不僅僅是一個文件。 (否則它不能導入,因爲依賴關係被破壞) –

    +0

    哦,親愛的。那麼,在這種情況下,還有python編譯器包可以幫助:http://docs.python.org/library/compiler.html - 但是這將會有更多的工作! –

    相關問題