- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
简短版:
Is there way to achieve in Python the same effect achieved by Perl's
<a href="http://perldoc.perl.org/Carp.html" rel="noreferrer noopener nofollow">Carp::carp</a>
utility?
长版(对于那些不熟悉 Carp::carp
的人):
假设我们正在实现一些库 API 函数(即,它旨在被其他程序员在他们的代码中使用),比如 spam
,并假设 spam
包含一些代码来检查传递给它的参数的有效性。当然,如果检测到这些参数有任何问题,这段代码应该会引发异常。假设我们想让关联的错误消息和回溯对调试某些客户端代码的人尽可能有帮助。
理想情况下,由此引发的异常产生的回溯的最后一行应该查明“有问题的代码”,即客户端代码中的行 spam
使用无效参数调用。
不幸的是,至少在默认情况下,使用 Python 不会发生这种情况。相反,回溯的最后一行将引用库代码内部的某处,那里的异常实际上是 raise
。 'd,这对于这个特定追溯的目标受众来说是相当模糊的。
例子:
# spam.py (library code)
def spam(ham, eggs):
'''
Do something stupid with ham and eggs.
At least one of ham and eggs must be True.
'''
_validate_spam_args(ham, eggs)
return ham == eggs
def _validate_spam_args(ham, eggs):
if not (ham or eggs):
raise ValueError('if we had ham '
'we could have ham and eggs '
'(if we had eggs)')
# client.py (client code)
from spam import spam
x = spam(False, False)
当我们运行 client.py
,我们得到:
% python client.py
Traceback (most recent call last):
File "client.py", line 3, in <module>
x = spam(False, False)
File "/home/jones/spam.py", line 7, in spam
_validate_spam_args(ham, eggs)
File "/home/jones/spam.py", line 12, in _validate_spam_args
raise ValueError('if we had ham '
ValueError: if we had ham we could have ham and eggs (if we had eggs)
而我们想要的更接近于:
% python client.py
Traceback (most recent call last):
File "client.py", line 3, in <module>
x = spam(False, False)
ValueError: if we had ham we could have ham and eggs (if we had eggs)
...将违规代码 ( x = spam(False, False)
) 作为回溯的最后一行。
我们需要的是某种“从调用者的角度”报告错误的方法(这就是 Carp::carp
允许人们在 Perl 中做的事情)。
编辑:需要明确的是,这个问题不是关于 LBYL 与 EAFP,也不是关于先决条件或按契约(Contract)编程。如果我给了这个错误的印象,我很抱歉。这个问题是关于如何从调用堆栈的几层(一层、两层)开始产生回溯。
EDIT2:Python 的 traceback
模块显然是寻找 Perl 的 Carp::carp
的 Python 等价物的地方。 ,但在研究了一段时间后,我无法找到任何方法将它用于我想做的事情。 FWIW,Perl 的 Carp::carp
允许通过公开全局(因此动态范围)变量 $Carp::CarpLevel
来微调回溯的初始框架.可能 carp
的非 API 库函数-出,local
-ize 并在输入时增加此变量(例如 local $Carp::CarpLevel += 1;
)。我没有看到任何甚至远程像这个 Python 的 traceback
模块。所以,除非我遗漏了什么,否则任何使用 Python 的 traceback
的解决方案将不得不采取完全不同的策略......
最佳答案
这实际上只是一个约定问题,python 中的异常处理旨在大量使用(请求原谅而不是请求许可)。鉴于您在不同的语言空间中工作,您希望遵循这些约定——即/您确实想让开发人员知道异常站点在哪里。但是如果你真的需要这样做......
使用检查模块
inspect module将完成重建一个漂亮版本的 carp 所需的几乎所有工作,无需担心装饰器(见下文)。根据 comments in this answer ,可能这种方法会在 cpython 以外的 python 上中断
# revised carp.py
import sys
import inspect
def carp( msg ):
# grab the current call stack, and remove the stuff we don't want
stack = inspect.stack()
stack = stack[1:]
caller_func = stack[0][1]
caller_line = stack[0][2]
sys.stderr.write('%s at %s line %d\n' % (msg, caller_func, caller_line))
for idx, frame in enumerate(stack[1:]):
# The frame, one up from `frame`
upframe = stack[idx]
upframe_record = upframe[0]
upframe_func = upframe[3]
upframe_module = inspect.getmodule(upframe_record).__name__
# The stuff we need from the current frame
frame_file = frame[1]
frame_line = frame[2]
sys.stderr.write( '\t%s.%s ' % (upframe_module, upframe_func) )
sys.stderr.write( 'called at %s line %d\n' % (frame_file, frame_line) )
# Exit, circumventing (most) exception handling
sys.exit(1)
对于下面的例子:
1 import carp
2
3 def f():
4 carp.carp( 'carpmsg' )
5
6 def g():
7 f()
8
9 g()
产生输出:
msg at main.py line 4
__main__.f called at main.py line 7
__main__.g called at main.py line 9
使用回溯
这是最初提出的方法。
carp 的等价物也可以通过操作回溯对象用 python 编写,请参阅 traceback module 中的文档.这样做的主要挑战原来是注入(inject)异常和回溯打印代码。值得注意的是,本节中的代码非常脆弱。
# carp.py
import sys
import traceback
'''
carp.py - partial emulation of the concept of perls Carp::carp
'''
class CarpError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
def carpmain( fun ):
def impl():
try:
fun()
except CarpError as ex:
_, _, tb = sys.exc_info()
items = traceback.extract_tb(tb)[:-1]
filename, lineno, funcname, line = items[-1]
print '%s at %s line %d' % (ex.value, filename, lineno)
for item in items[1:]:
filename, lineno, funcname, line = item
print '\t%s called at %s line %d' % (funcname, filename, lineno)
return impl
def carp( value ):
raise CarpError( value )
可以使用以下基本过程调用:
import carp
def g():
carp.carp( 'pmsg' )
def f():
g()
@carp.carpmain
def main():
f()
main()
其输出为:
msg at foo.py line 4
main called at foo.py line 12
f called at foo.py line 7
g called at foo.py line 4
Perl 引用示例
为了完整起见,通过将结果与这个等效的 perl 示例进行比较来调试此答案中提出的两个解决方案:
1 use strict;
2 use warnings;
3 use Carp;
4
5 sub f {
6 Carp::carp("msg");
7 }
8
9 sub g {
10 f();
11 }
12
13 g();
输出结果:
msg at foo.pl line 6
main::f() called at foo.pl line 10
main::g() called at foo.pl line 13
关于python - 从调用者的角度发出警告(又名 Python 等同于 Perl 的鲤鱼)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8275745/
你好,我正在尝试在 opensuse 中创建一个 Shell 脚本来创建 MySqlUsers,但是当我尝试运行它时,我得到了这个错误: Warning: Could not start progra
我阅读了有关此错误的所有信息,但未能找到任何解决方案。 我有一个看起来像这样的简单页面: $xmlfile = "/var/www/marees.xml"; //Fichier dans lequel
运行 Websphere App 服务器 V8.5 Liberty Profile。我找不到任何可以解决这些警告的帮助。我在 eclipse 。 ************** He
我尝试在 GC AppEngine 上部署应用程序。部署过程中没有错误,但应用程序无法运行(仅显示加载页面)。日志中唯一一个奇怪的原始 OpenBLAS WARNING - could not det
我刚开始学习 RestKit。我正在尝试使用它来使用 Foursquare api 获取附近的 field 。但每次我尝试“objectLoader:(RKObjectLoader *)objectL
我对 Vuejs 比较陌生,每次按键时都会收到以下警告: [Vue warn]: $attrs is readonly. found in ---> at src\component
Warning: simplexml_load_file() [function.simplexml-load-file]: I/O warning : failed to load external
我在尝试修改某些表时不断收到此错误。这是我的代码: /** = 1){ //$this->mysqli->autocommit(FALSE); //insert th
当我尝试使用 PHP 的 ftp_put 函数上传文件时,早些时候出现错误: 警告:ftp_put() [function.ftp-put]:无数据连接 现在,我尝试开启被动模式: ftp_pasv(
我一直在努力让这段代码适用于现阶段的年龄。它旨在计算一个范围内的素数,我已经编写了一种方法来打印它们。不幸的是,代码将无法编译,引用警告: “警告:[未检查] 未检查调用 add(E) 作为原始类型
尝试使用带有架构组件和Kotlin的Android Studio 3 Canary 5构建示例会给出此警告。 谁能告诉我原因? 谢谢,Ove 编辑#1: 这是Dan Lew前段时间制作的样本 http
我正在编写一个 Shiny 的应用程序,它运行得非常好,突然我收到两条警告消息。我已经回到以前运行良好的副本,它们现在显示相同的错误消息,所以我真的很困惑。我的代码仍然运行并在我 Shiny 的仪表板
03-25 05:52:15.329 8029-8042/com.mgh.radio W/MediaPlayerNative: info/warning (703, 0) 03-25 05:52:15
我在构建时在我的 gradle 控制台中收到一条警告消息: 警告:[options] 引导类路径未与 -source 1.7 一起设置 1 条警告 我怎样才能解决这个问题? 任何帮助表示赞赏! 最佳答
我有下一个代码: 测试.c #include "a1.h" int main() { int a = 8; foo(a); return a; } a1.h void foo
我的程序中有一个 WORD 变量。 WORD hour; 但是当我比较它的时候 if(hour>=0 && hour=0 && hour=0 的比较,它始终适用于 hour 是 WORD 类型,它是一
安全研究人员警告称,一个最新的严重的Java错误,其本质与目前在全球范围内利用的臭名昭著的 Log4Shell 漏洞相同 。 CVE-2021-42392 尚未在国家漏洞数据库 (NVD) 中
安装SqlServer2005时“版本变更检查 (警告)"问题排查 今天同事在安装SqlServer2005时遇到“版本变更检查 (警告) ”问题导致安装失败,警告提示如下: - 版本
我的 UWP 项目中出现以下警告。我已经标记了解决方案的示例,但我更感兴趣的是为什么在同一平台上创建另一个空项目时不会出现此警告? APPX4001: Build property AppxBundl
我试图修复我的登录脚本,在我的本地主机上它可以工作,但上传到我的在线测试服务器时,注销被破坏,我得到这个错误: Warning: session_destroy() [function.session
我是一名优秀的程序员,十分优秀!