我是作为面试问题遇到的。这个问题似乎很有趣。所以,我把它张贴在这里。
考虑给出语义错误的操作,例如被零除。默认情况下,python 编译器会给出类似“无效操作”之类的输出。我们能否控制 Python 编译器给出的输出,比如打印一些其他错误消息,跳过除零操作,并继续执行其余指令?
而且,我如何评估运行时语义检查的成本? 这里有很多 python 专家。我希望有人能对此有所启发。提前致谢。
请您参考如下方法:
Can we control the output that is given out by Python compiler, like print some other error message, skip that division by zero operation, and carry on with rest of the instructions?
不,你不能。您可以用 try...except block 手动包装每个危险命令,但我假设您是在谈论自动恢复到特定行 within try...except 阻止,甚至完全自动。
当错误发生时 sys.excepthook 被调用,或者如果您及早发现它的任何外部范围,内部范围就会消失。您可以使用 sys.settrace 更改行号在 CPython 中,尽管那只是一个实现细节,但由于外部作用域已不存在,因此没有可靠的恢复机制。
如果您尝试使用幽默的 goto 愚人节模块(使用我刚刚描述的方法)来跳转 block 甚至在文件中:
from goto import goto, label
try:
1 / 0
label .foo
print("recovered")
except:
goto .foo
你得到一个错误:
Traceback (most recent call last):
File "rcv.py", line 9, in <module>
goto .foo
File "rcv.py", line 9, in <module>
goto .foo
File "/home/joshua/src/goto-1.0/goto.py", line 272, in _trace
frame.f_lineno = targetLine
ValueError: can't jump into the middle of a block
所以我很确定这是不可能的。
And also, how can i evaluate the cost of run-time semantic checks?
我不知道那是什么,但您可能正在寻找 line_profiler :
import random
from line_profiler import LineProfiler
profiler = LineProfiler()
def profile(function):
profiler.add_function(function)
return function
@profile
def foo(a, b, c):
if not isinstance(a, int):
raise TypeError("Is this what you mean by a 'run-time semantic check'?")
d = b * c
d /= a
return d**a
profiler.enable()
for _ in range(10000):
try:
foo(random.choice([2, 4, 2, 5, 2, 3, "dsd"]), 4, 2)
except TypeError:
pass
profiler.print_stats()
输出:
Timer unit: 1e-06 s
File: rcv.py
Function: foo at line 11
Total time: 0.095197 s
Line # Hits Time Per Hit % Time Line Contents
==============================================================
11 @profile
12 def foo(a, b, c):
13 10000 29767 3.0 31.3 if not isinstance(a, int):
14 1361 4891 3.6 5.1 raise TypeError("Is this what you mean by a 'run-time semantic check'?")
15
16 8639 20192 2.3 21.2 d = b * c
17 8639 20351 2.4 21.4 d /= a
18
19 8639 19996 2.3 21.0 return d**a
所以“运行时语义检查”,在这种情况下将占用运行 foo 的 36.4% 的时间。
如果你想手动为特定的 block 计时,这些 block 大于你使用 timeit on 但小于你想要的分析器,而不是使用两个 time.time( ) 调用(这是一个非常不准确的方法)我建议 Steven D'Aprano's Stopwatch context manager .
