2013-07-08 70 views
0

我在Python交互式控制檯(不是空閒,不是ipython)中定義了一個函數,之後我需要再次查看很多屏幕。如何顯示Python函數的代碼?

例子:

>>> def myf(): 
... print 1 
... print 2 
... print 3 
... 
>>> 
>>> # a lot of scrolling 
>>> 

以下(而不是 「名 'print_function' 沒有定義」),以證明什麼,我想假輸出示例:

>>> print_function(myf) 
myf() 
    print 1 
    print 2 
    print 3 

有沒有像在Python print_function什麼?如果不是,你將如何實現它?

+1

你正在做的這一切在一個控制檯,而不是在一個文件中的任何原因? –

+1

不在控制檯中。在文件中,是的,但不是在控制檯中。 –

+0

可能重複的[可以Python打印一個函數定義?](http://stackoverflow.com/questions/1562759/can-python-print-a-function-definition) –

回答

3

您無法在常規控制檯中執行此操作。 iPython會保留一份源代碼的副本,以備日後再次查看,但標準Python控制檯不會。

只好從文件導入的功能,你也可以使用​​:

>>> import os.path 
>>> import inspect 
>>> print inspect.getsource(os.path.join) 
def join(a, *p): 
    """Join two or more pathname components, inserting '/' as needed. 
    If any component is an absolute path, all previous path components 
    will be discarded. An empty last part will result in a path that 
    ends with a separator.""" 
    path = a 
    for b in p: 
     if b.startswith('/'): 
      path = b 
     elif path == '' or path.endswith('/'): 
      path += b 
     else: 
      path += '/' + b 
    return path 

但是,僅僅是明確的,inspect.getsource()將無法​​在交互式控制檯中輸入功能:

>>> def foo(): pass 
... 
>>> print inspect.getsource(foo) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/Users/mj/Development/Libraries/buildout.python/parts/opt/lib/python2.7/inspect.py", line 701, in getsource 
    lines, lnum = getsourcelines(object) 
    File "/Users/mj/Development/Libraries/buildout.python/parts/opt/lib/python2.7/inspect.py", line 690, in getsourcelines 
    lines, lnum = findsource(object) 
    File "/Users/mj/Development/Libraries/buildout.python/parts/opt/lib/python2.7/inspect.py", line 538, in findsource 
    raise IOError('could not get source code') 
IOError: could not get source code 

,因爲解釋器中沒有任何內容保留輸入(除了readline庫,可能會保存輸入歷史記錄,只是不能以inspect.getsource()直接使用的格式)。

0

你想對此有多正式? 如果你的反應是東西的「不太」,那麼你可以只是一個函數的代碼複製到文檔字符串,然後使用DOC

例如打印文檔字符串的效果:

def foo(): 
""" Prints a sequence of numbers to the terminal: 
    print 1 
    print 2 
""" 
print 1 
print 2 

print foo() 
--> 1 
--> 2 

print foo.__doc__ 
--> Prints a sequence of numbers to the terminal: 
--> print 1 
--> print 2 
0

當我學會了這一點,但每個功能都有一個代碼的方法我很驚訝,所以你可以嘗試寫類似:

>>> def f(): 
print "hello world" 
>>> f.__code__ 
<code object f at 02C57188, file "<pyshell#5>", line 1> 

正如你看到的,它只是讓你存儲在備忘錄對象的引用ry,而不是函數的確切代碼。然而,你可以這樣做:

>>> def roman(): 
print "Oh no!" 
>>> roman.__code__ = f.__code__ 
>>> roman() 
hello world 
>>> 

我不知道這件事,但我認爲你也可以寫入文件,並從該文件稍後閱讀的代碼。你需要自己做一些研究,並修改它,希望這有助於某種程度。

+0

此代碼是功能的字節碼,幾乎不可讀取 –

+0

啊謝謝不知道,但也許你可以以某種方式恢復它? –

+0

有Python的反編譯器,但很多信息將會丟失(註釋,局部變量名,...)。因此,如果您編寫源代碼,只需保存它就好多了 –

0

IPython有這個可愛的歷史查詢。因此,如果您知道功能的名稱,則應該能夠輸入def myFunc(並按向上箭頭鍵。這將使IPython重新調用緩衝區並向您顯示最後輸入的與此匹配的匹配代碼。在你的情況下,它將是你的函數的定義,包括全功能體。所以這應該爲你做!

希望這有助於

+1

這與iPython無關。普通的Python解釋器也有這個功能,這要歸功於'readline'模塊。 – 2013-07-08 16:40:10

+0

有趣。我從來沒有能夠在常規解釋器上覆制這些功能。然而,自從我切換到IPython已經有相當長的一段時間了,所以也許我的信息太舊了 – inspectorG4dget

+0

下面是如何做到這一點:http://docs.python.org/2/library/readline.html#example – 2013-07-08 16:43:02

2

這是一個有點hackish但如果這是東西,你會做很多,你可以使用readline模塊和功能的裝飾。

class PrintableFunction(object): 
    """A class that contains a function and its start and end points 
    in the readline history""" 

    def __init__(self, func, start, end): 
     self.start = start 
     self.end = end 
     self.func = func 

    def __call__(self, *args): 
     self.func(*args) 

    def __str__(self): 
     """Just get all the readline history lines from start to end and 
     return them""" 

     lines = [] 
     for i in range(self.start, self.end + 1): 
      lines.append(readline.get_history_item(i)) 
     return "\n".join(lines) 


class SavedFunction(object): 
    """The actual function decorator. It takes one argument, the history 
    line that at which the function definition will begin.""" 

    def __init__(self, start): 
     """Take the starting line as an argument to the decorator. The end 
     line is grabbed from the current history after the function has 
     been entered""" 

     self.start = start 
     self.end = readline.get_current_history_length() 

    def __call__(self, func): 
     return PrintableFunction(func, self.start, self.end) 

您可以將這些類添加到您的PYTHONSTARTUP文件,這樣你每次加載一個解釋,你有他們提供。

>>> @SavedFunction(readline.get_current_history_length() + 1) 
... def foo(bar): 
...  print(bar) 
>>> foo(5) 
5 
>>> print(foo) 
def foo(bar): 
    print(bar) 

我創建了一個自定義的PS1爲自己(在我PYTHONSTARTUP文件也一樣),顯示當前的ReadLine歷史編號,這意味着我可以把它只是快速添加到@saved_function參數列表,這是不是更容易獲取它與上面的readline.get_current_history_length功能:

[508] @SavedFunction(509) 
(509) def foo(bar): 
(510)  print(bar) 
[511] print(foo) 
def foo(bar): 
    print(bar) 
0

雖然我很普遍認同inspect是一個很好的答案(如的Martijn Pieters的提到),我不同意,你不能得到源代碼在解釋器中定義的對象。如果使用dill中的dill.source.getsource,則可以獲取函數和lambda表達式的來源,即使它們是交互式定義的。 它也可以從curries中定義的綁定或未綁定的類方法和函數獲取代碼...但是,如果沒有包含對象的代碼,您可能無法編譯該代碼。

>>> from dill.source import getsource 
>>> 
>>> def add(x,y): 
... return x+y 
... 
>>> squared = lambda x:x**2 
>>> 
>>> print getsource(add) 
def add(x,y): 
    return x+y 

>>> print getsource(squared) 
squared = lambda x:x**2 

>>> 
>>> class Foo(object): 
... def bar(self, x): 
...  return x*x+x 
... 
>>> f = Foo() 
>>> 
>>> print getsource(f.bar) 
def bar(self, x): 
    return x*x+x 

>>> 
0

有很多方法可以做到這一點:

沒有任何進口:

print myf.func_code.co_code 

但你極有可能剛剛結束了字節碼。這可以解決: http://www.crazy-compilers.com/decompyle/

你也可以去檢查方式:

import inspect 
import mymodule 
print inspect.getsource(mymodule.myf) 

或者你可以用DIS:(明智安全)

import dis 

dis.dis(myf) 

最後,雖然不推薦有是這樣的:

funcstring = """def myf(): 
    print 1 
    print 2 
    print 3""" 
func = eval(funcstring) 

func.source = funcstring 

print func.source 
0

這就是我該怎麼做:

import inspect as i 
    import sys 
    sys.stdout.write(inspect.getsource(MyFunction)) 

打印出來很好...