从 Python 解释器检查 lambda 代码

Inspect lambda code from Python interpreter

这个简单的 python 程序是从更复杂的代码库中提取出来的:

#insp.py
import inspect
L = lambda x: x+1
print("L(10)=" + str(L(10)))
code = inspect.getsource(L)
print(code)

如果我从命令行 运行 工作:

$ python insp.py

如果我在 python 解释器中复制并粘贴每一行,它会失败:

d:\>python
Python 3.5.1 (v3.5.1:37a07cee5969, Dec  6 2015, 01:38:48) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import inspect
>>> L = lambda x: x+1
>>> print("L(10)=" + str(L(10)))
L(10)=11
>>> code = inspect.getsource(L)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "d:\Users\Cimino\AppData\Local\Programs\Python\Python35-32\Lib\inspect.py", line 944, in getsource
    lines, lnum = getsourcelines(object)
  File "d:\Users\Cimino\AppData\Local\Programs\Python\Python35-32\Lib\inspect.py", line 931, in getsourcelines
    lines, lnum = findsource(object)
  File "d:\Users\Cimino\AppData\Local\Programs\Python\Python35-32\Lib\inspect.py", line 762, in findsource
    raise OSError('could not get source code')
OSError: could not get source code

请注意,使用 IPython 而不是普通的 Python 解释器,它可以工作!

有人知道为什么吗?

我在Windows7下使用Python3.5 32位。

它在 IPython 中工作,因为它缓存了您使用 linecache 模块输入的每个命令。

例如:

$ ipy  ## Equivalent to ipython --classic
Python 2.7.10 (default, Jul 30 2016, 18:31:42)
Type "copyright", "credits" or "license" for more information.

IPython 3.0.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.
>>> print a
Traceback (most recent call last):
  File "<ipython-input-1-9d7b17ad5387>", line 1, in <module>
    print a
NameError: name 'a' is not defined

注意这里的 <ipython-input-1-9d7b17ad5387> 部分,这是 IPython 特有的部分。在正常 Python shell 你会看到 <stdin>:

$ python
Python 2.7.10 (default, Jul 30 2016, 18:31:42)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> print a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined

现在让我们运行你的代码:

>>> import inspect
>>> L = lambda x: x+1
>>> code = inspect.getsource(L)

是时候找出与 L 相关的文件名了:

>>> L.func_code.co_filename
'<ipython-input-2-0c0d6f325784>'

现在让我们看看 linecache.cache 中是否有此文件的源代码:

>>> import linecache
>>> linecache.cache[L.func_code.co_filename]
(18, 1481047125.479239, [u'L = lambda x: x+1\n'], '<ipython-input-2-0c0d6f325784>')

因此,使用此信息 IPython 能够找到所需的来源,但 Python shell 不能,因为它没有存储任何信息。


关于inspect如何获取源码的相关细节可以在源码中的getsourcefile and findsource函数中找到。