3

git alias problemの場合、ファイルから単一の Python 関数を名前で選択できるようにしたいと考えています。例えば:

  ...
  def notyet():
      wait for it

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

  def ok_stop_now():

アルゴリズム的に言えば、以下は十分に近いものです。

  1. 一致する行が見つかったら、フィルタリングを開始します/^(\s*)def $1[^a-zA-Z0-9]/
  2. orではない 行(つまり、インデントされている可能性のあるコメント、または前のものよりも長いインデント)が見つかるまで、一致を続けます。^\s*#^/\1\s]

(次の関数の前のデコレータが取り上げられても、あまり気にしません。結果は、人間が読むためのものです。)

私はこれをAwk(ほとんど知らない)でやろうとしていましたが、思ったより少し難しいです。手始めに、元の の前にインデントの長さを保存する方法が必要defです。

4

2 に答える 2

4

を使用した片道awk。コードはよくコメントされているので、理解しやすいと思います。

の内容infile:

  ...
  def notyet():
      wait for it

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

  def ok_stop_now():

の内容script.awk:

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
于 2012-05-09T09:56:06.157 に答える
4

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 に出力する必要があります。

于 2012-05-09T08:39:43.550 に答える