我在面试时遇到了这个问题。这个问题看起来很有趣。所以,我把它发布在这里。
考虑会产生语义错误的运算,例如除以零。默认情况下,python 编译器会给出“无效操作”之类的输出。我们可以控制Python编译器给出的输出,比如打印一些其他错误消息,跳过除零操作,并继续执行其余指令吗?
另外,我如何评估运行时语义检查的成本?
这里有很多Python专家。我希望有人能对此有所启发。
我们可以控制Python编译器给出的输出,比如打印一些其他错误消息,跳过除零操作,并继续执行其余指令吗?
不,你不能。您可以使用
try...except
块手动包装每个危险命令,但我假设您正在谈论自动恢复到 try...except
块中的特定行,甚至完全自动恢复。当错误消失以致调用
sys.excepthook
时,或者任何外部作用域(如果您尽早捕获它),内部作用域都消失了。您可以在 CPython 中使用
sys.settrace
更改行号,尽管这只是一个实现细节,但由于外部作用域已经消失,因此没有可靠的恢复机制。 如果您尝试使用幽默的
goto
愚人节模块(使用我刚才描述的方法)来跳转块
甚至在文件中:
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
所以我很确定这是不可能的。
我不知道那是什么,但您可能正在寻找
:
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
因此,在这种情况下,“运行时语义检查”将占用运行时间的 36.4%
foo
。
如果您想手动对大于您使用
timeit
的特定块进行计时,但小于您想要的探查器所需的时间,我建议不要使用两个
time.time()
调用(这是一种非常不准确的方法) Steven D'Aprano 的秒表上下文管理器。
f(a,b)
:
def f(a: int, b: int):
"""
@param a:
@param b:
"""
try:
c = a / b
print(c)
except ZeroDivisionError:
print("You idiot, you can't do that ! :P")
if __name__ == '__main__':
f(1, 0)
>>> from cheese import f
>>> f(0, 0)
You idiot, you can't do that ! :P
>>> f(0, 1)
0.0
>>> f(1, 0)
You idiot, you can't do that ! :P
>>> f(1, 1)
1.0
这是一个如何通过使用
ZeroDivisionError
制作异常情况来捕获零除法的示例。
我不会讨论任何用于制作记录器的特定工具,但您确实可以理解与这种检查相关的成本。您可以在函数的开头放置
start = time.time()
,在函数末尾放置
end = time.time()
。如果取差值,您将得到以秒为单位的执行时间。希望有帮助。