我在Python交互式控制台中定义了一个函数(不是空闲的,而不是ipython),我需要稍后再次看到它。
示例:
>>> def myf():
... print 1
... print 2
... print 3
...
>>>
>>> # a lot of scrolling
>>>
下面的假示例输出(而不是“name'print_function'未定义”)来演示我想要的内容:
>>> print_function(myf)
myf()
print 1
print 2
print 3
Python中有什么类似print_function的东西吗?如果没有,你会如何实现它?
答案 0 :(得分:3)
您无法在常规控制台中执行此操作。 iPython会保留源代码的副本,以备日后再次查看时使用,但标准的Python控制台不会。
如果从文件导入了该函数,则可以使用inspect.getsource()
:
>>> 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()
可直接使用的格式)。
答案 1 :(得分: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)
答案 2 :(得分:0)
你想要对此有多正式? 如果您的回答是“非常”的结果,那么您可以将函数的代码复制到docstring中,然后使用 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
答案 3 :(得分:0)
当我学会了这个但每个函数都有一个代码方法时,我感到很惊讶,所以你可以尝试编写类似的东西:
>>> def f():
print "hello world"
>>> f.__code__
<code object f at 02C57188, file "<pyshell#5>", line 1>
如您所见,它只是为您提供存储在内存中的对象的引用,而不是该函数的确切代码。但是你可以这样做:
>>> def roman():
print "Oh no!"
>>> roman.__code__ = f.__code__
>>> roman()
hello world
>>>
我不确定,但我认为您也可以将代码写入文件并稍后从此文件中读取。你需要自己做一些研究并修补它,希望这会有所帮助。
答案 4 :(得分:0)
IPython有这个可爱的历史查找。因此,如果您知道函数的名称,则应该能够键入def myFunc(
并按向上箭头键。这将使IPython调用缓冲区并向您显示与此开始匹配的最后输入的代码。在您的情况下,它将是您的函数的定义,包括完整的函数体。所以这应该为你做到!
希望这有帮助
答案 5 :(得分:0)
虽然我普遍认为inspect
是一个很好的答案(如 Martijn Pieters 提到的那样),但我不同意你不能得到解释器中定义的对象的源代码。如果您使用dill
中的dill.source.getsource
,则可以获得函数和lambdas的来源,即使它们是以交互方式定义的。
它还可以从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
>>>
答案 6 :(得分: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
答案 7 :(得分:0)
我就是这样做的:
import inspect as i
import sys
sys.stdout.write(i.getsource(MyFunction))
很好地打印出来......