I defined a function in a Python interactive console (not idle, not ipython) and I needed to see it again many screenfuls later.
Example:
>>> def myf():
... print 1
... print 2
... print 3
...
>>>
>>> # a lot of scrolling
>>>
Fake example output below (instead of "name 'print_function' is not defined") to demonstrate what I want:
>>> print_function(myf)
myf()
print 1
print 2
print 3
Is there anything like print_function in Python? If not, how would you implement it?
You cannot do this in the regular console. iPython keeps a copy of the source in case you want to see it again later on, but the standard Python console does not.
Had you imported the function from a file, you could have used 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
but, just to be explicit, inspect.getsource() will fail for functions entered in the interactive console:
>>> 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
because nothing in the interpreter retains the input (other than the readline library, which might save input history, just not in a format directly usable by inspect.getsource()).
It's a bit hackish but if this is something that you will be doing a lot, you can use the readline module and a function decorator.
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)
You can add these classes to your PYTHONSTARTUP file, so that every time you load an interpreter, you have them available.
>>> @SavedFunction(readline.get_current_history_length() + 1)
... def foo(bar):
... print(bar)
>>> foo(5)
5
>>> print(foo)
def foo(bar):
print(bar)
I've created a custom PS1 for myself (in my PYTHONSTARTUP file as well) that shows the current readline history number, meaning I can just quickly add it to the @saved_function argument list, which is easier than fetching it with the readline.get_current_history_length function as above:
[508] @SavedFunction(509)
(509) def foo(bar):
(510) print(bar)
[511] print(foo)
def foo(bar):
print(bar)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With