<p>或者,在没有任何附加模块(但有一些Python内部构件)的情况下:</p>
<pre><code>>>> def thing():
... a = 5
... b = a + 4
... return a + b * 2
...
>>> thing.__code__.co_firstlineno # self-explanatory
1
>>> list(thing.__code__.co_lnotab)
[0, 1, 4, 1, 8, 1]
>>> thing.__code__.co_firstlineno + sum(line_increment for i, line_increment in enumerate(thing.__code__.co_lnotab) if i % 2)
4
</code></pre>
<p>这样就有了:函数从第1行(<code>thing.__code__.co_firstlineno</code>)到第4行。你知道吗</p>
<p><code>dis</code>模块证明了这一点(第一列中的数字是行号):</p>
<pre><code>>>> import dis
>>> dis.dis(thing)
2 0 LOAD_CONST 1 (5)
2 STORE_FAST 0 (a)
3 4 LOAD_FAST 0 (a)
6 LOAD_CONST 2 (4)
8 BINARY_ADD
10 STORE_FAST 1 (b)
4 12 LOAD_FAST 0 (a)
14 LOAD_FAST 1 (b)
16 LOAD_CONST 3 (2)
18 BINARY_MULTIPLY
20 BINARY_ADD
22 RETURN_VALUE
</code></pre>
<p>注意最后一个数字是4,这是函数最后一行的数字。你知道吗</p>
<p>更多关于<code>co_lnotab</code>结构的信息可以在<a href="https://github.com/python/cpython/blob/3.8/Objects/lnotab_notes.txt" rel="nofollow noreferrer">here</a>和<a href="https://late.am/post/2012/03/26/exploring-python-code-objects.html" rel="nofollow noreferrer">here</a>中找到。你知道吗</p>
<hr/>
<h2>测试程序</h2>
<pre><code>def span_of_function(func):
start = func.__code__.co_firstlineno
end = start + sum(line_increment for i, line_increment in enumerate(func.__code__.co_lnotab) if i % 2)
return start, end
def hello(name):
print(f'Hello, {name}!')
return 5
print(span_of_function(span_of_function))
print(span_of_function(hello))
</code></pre>
<p>输出:</p>
<pre><code>$ python3 test.py
(1, 5)
(7, 9)
</code></pre>