我遇到了这个作为一个面试问题。这个问题似乎很有趣。所以,我把它贴在这里。
考虑产生语义错误的操作,例如除以零。默认情况下,python 编译器会给出“无效操作”之类的输出。我们可以控制 Python 编译器给出的输出,比如打印一些其他错误消息,跳过除零运算,然后继续执行其余指令吗?
而且,我如何评估运行时语义检查的成本?这里有很多python专家。我希望有人会对此有所了解。提前致谢。
我遇到了这个作为一个面试问题。这个问题似乎很有趣。所以,我把它贴在这里。
考虑产生语义错误的操作,例如除以零。默认情况下,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
所以我很确定这是不可能的。
而且,我如何评估运行时语义检查的成本?
我不知道那是什么,但您可能正在寻找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
因此,“运行时语义检查”在这种情况下将占用运行时间的 36.4% foo
。
如果您想手动计时比您使用的更大timeit
但小于分析器所需的特定块,而不是使用两个time.time()
调用(这是一种非常不准确的方法),我建议Steven D'Aprano 的秒表上下文管理器.
我只想使用一个例外,这个例子使用的是 python 3。对于 Python 2,只需删除函数参数后的注释。所以你的函数签名看起来像这样 -> 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
.
我不会介绍任何用于制作记录器的特定工具,但您确实可以了解与这种检查相关的成本。您可以将 astart = time.time()
放在函数的开头和end = time.time()
结尾。如果您取差价,您将获得以秒为单位的执行时间。
我希望这会有所帮助。