return语句获取行号

问题描述 投票:-1回答:2

有没有办法让一个Python函数返回编程语句的行号?让我们看看下面的例子:

def foo(i: int) -> str:
    if i == 1:
        return 'he'
    elif i == 2:
        return 'ha'
    return 'he'

如果输入1或3,该函数将返回'he'。不过,我不知道这return 'he'被实际执行,除非我可以通过代码。

我的应用程序允许用户在Python GUI输入的业务规则,并让他们测试规则本身。由于我的应用程序不能遍历代码(执行的任务,它委托给一个独立Python引擎,预计字符串或异常)。我想找到一种方法来获取返回的行号,这样我可以突出在GUI上编辑器中相应的行。

这样做的一个肮脏的方式将有函数返回的行数和字符串的元组,但最好我想从这样的痛苦空余的用户。

python python-3.x return
2个回答
1
投票

bdb模块,您可以检查每个帧权在返回之前,所以你应该能够检索的Foo的在这一点最终回报f_lineno。例:

from bdb import Bdb
class ReturnWatcher(Bdb):
    def __init__(self):
        self.last_encountered_return_line = None
        super().__init__()
    def user_return(self, frame, return_value):
        self.last_encountered_return_line = frame.f_lineno

def foo(i):
    if(i==1):
        return 'he'
    elif(i==2):
        return 'ha'
    return 'he'

x = ReturnWatcher()
x.runcall(foo, 1)
print("Last return statement executed on line", x.last_encountered_return_line)
x.runcall(foo, 2)
print("Last return statement executed on line", x.last_encountered_return_line)
x.runcall(foo, 3)
print("Last return statement executed on line", x.last_encountered_return_line)

结果:

Last return statement executed on line 11
Last return statement executed on line 13
Last return statement executed on line 14

1
投票

你可以问Python来通知你使用任何sys.settrace()收益;这是一个钩子函数,当某些事件发生Python会打电话来,是典型的调试器和分析器是如何勾成Python。

你有sys.settrace()注册功能将被调用仅呼叫事件,每当Python的进入一个新的本地范围(函数调用,类机构,以及内涵和发电机表达式)。然后,您可以返回None(不跟踪这个局部范围),或将被用于线路,异常或范围之内返回事件跟踪功能。在Python 3.7,你可以设置框对象选择,在资料的详细程度你的每一丝范围函数被调用进一步控制;您可以禁用每行活动,甚至使每个操作码的事件。

你可以用它来记录事件的回报,像这样;我用两个调用和返回事件的一个跟踪方法:

import inspect
import sys

class ReturnLines:
    def __init__(self):
        self.returns = []
        self._old_trace = None

    def start(self):
        self._old_trace = sys.gettrace()
        sys.settrace(self.trace)

    def stop(self):
        sys.settrace(self._old_trace)

    def __enter__(self):
        self.start()
        return self.returns

    def __exit__(self, *exc):
        self.stop()

    def trace(self, frame, event, arg):
        filename = None
        if frame is not None:
            filename = inspect.getsourcefile(frame)
        if event == 'call':
            if filename == __file__:
                # skip ourselves
                return
            try:
                # Python 3.7+: only trace exceptions and returns for this call
                frame.f_trace_lines = False
            except AttributeError:
                pass
            return self.trace
        elif event == 'return':
            self.returns.append((filename, frame.f_lineno, arg))

它放入一个单独的模块,并使用像一个上下文管理对象:

from return_recorder import ReturnLines

with ReturnLines() as return_lines:
    # run the code you want to trace
    # ...

上下文管理器,您可以访问它增加了回报(如(filename, linenumber, returned_object)元组),让你为你的上下文管理器中执行代码可以访问返回的信息列表对象:

>>> from return_recorder import ReturnLines
>>> def foo(i: int) -> str:
...     if i == 1:
...         return 'he'
...     elif i == 2:
...         return 'ha'
...     return 'he'
...
>>> with ReturnLines() as return_lines:
...     for i in range(3):
...         foo(i)
...         print(f'<-- i={i}, returned at line {return_lines[-1][1]}')
...
'he'
<-- i=0, returned at line 6
'he'
<-- i=1, returned at line 3
'ha'
<-- i=2, returned at line 5
>>> for filename, lineno, returned in return_lines:
...     print(f'{filename}:{lineno}:{returned!r}')
...
None:6:'he'
None:3:'he'
None:5:'ha'

对于交互式解释,文件名是None

bdb模块,托换凯文的回答,建立在sys.set_trace()but的顶部不会禁用行Python的跟踪3.7+。而作为一个通用的调试器框架,它增加了每个跟踪事件更高的开销。这相当于你插装代码的执行速度较慢。

© www.soinside.com 2019 - 2024. All rights reserved.