草庐IT

python - 引发似乎来自调用者的异常

coder 2023-08-24 原文

我有同样的问题 here但错误地关闭了 作为 another related question 的副本:

Python 库如何以其自身的方式引发异常 它没有在回溯中公开的代码?动机是做它 清楚库函数被错误调用:有问题的 来电者的线路似乎应该承担责任,而不是 库中的行(故意且正确地)引发了 异常。

正如 Ian 在对已关闭问题的评论中所指出的,这不是 与询问如何调整调用者中的代码以更改相同 回溯出现的方式。

我失败的尝试如下。 在标记为 QUESTION 的行中,我尝试修改的属性 tb,例如tb.tb_frame = tb.tb_frame.f_back 但这会导致 AttributeError:只读属性。我也试图创建一个 具有与 tb 相同属性的鸭子类型对象,但在期间失败 reraise(),带有 TypeError: __traceback__ must be a traceback or None。 (我试图通过子类化 traceback 来解决这个问题,但遇到了 TypeError: type 'traceback' is not an acceptable base type)。

调整 traceback 对象本身在任何情况下都可能是此 X 的错误 Y - 也许还有其他策略?

假设 Alice 编写了以下库:

import sys

# home-made six-esque Python {2,3}-compatible reraise() definition
def reraise( cls, instance, tb=None ): # Python 3 definition
    raise ( cls() if instance is None else instance ).with_traceback( tb )
try: 
    Exception().with_traceback
except: # fall back to Python 2 definition
    exec( 'def reraise( cls, instance, tb=None ): raise cls, instance, tb' )
    # has to be wrapped in exec because this would be a syntax error in Python 3.0

def LibraryFunction( a ):
    if isinstance( a, (int, float) ):
        return a + 1
    else:
        err = TypeError( "expected int or float, got %r" % a )
        RaiseFromAbove( err )   # the traceback should NOT show this line
                                # because this function knows that it is operating
                                # correctly and that the caller is at fault

def RaiseFromAbove( exception, levels=1 ):
    # start by raising and immediately catching the exception
    # so that we can get a traceback from sys.exc_info()
    try:
        raise( exception )
    except:  
        cls, instance, tb = sys.exc_info()
        for i in range( levels + 1 ):
            pass # QUESTION: how can we manipulate tb here, to remove its deepest levels?
        reraise( cls, instance, tb )

现在,假设 Alice 发布了库,Bob 下载了它。 Bob 编写了调用它的代码,如下所示:

from AlicesLibrary import LibraryFunction

def Foo():
    LibraryFunction( 'invalid input' )  # traceback should reach this line but go no deeper

Foo()

重点是,如果没有有效的 RaiseFromAbove,回溯将显示异常源自 Alice 库的第 17 行。因此,Bob(或 Bob 的重要子群体)将向 Alice 发送电子邮件说“嘿,你的代码在第 17 行被破坏了。”但事实上,LibraryFunction() 确切地知道它在发出异常时做了什么。 Alice 可以尽最大努力改写异常,尽可能清楚地表明库被错误地调用,但是回溯将注意力从这个事实上移开。真正出错的地方是Bob代码的第4行。此外,Alice 的代码知道这一点,因此允许 Alice 的代码将责任归咎于它所属的地方并不是权力的错位。因此,为了尽可能提高透明度并减少支持流量,回溯不应深入到 Bob 代码的第 4 行,Bob 不必自己编写此行为。

mattbornski 提供了一个“你不应该想要这样做”的答案 here我认为这忽略了重要的一点。当然,如果你说“这不是我的错”并推卸责任,你并不知道你一定是在推卸责任。但是您确实知道您 (LibraryFunction) 已经努力对您收到的输入参数进行显式类型检查,并且此检查已成功(在检查本身没有引发异常的感觉),结果是否定的。当然,从某种意义上说,Bob 的代码可能没有“错误”,也许它没有生成无效输入——也许 Bob 只是从其他地方传递了那个论点。但不同的是,他没有检查就把它传了过去。如果 Bob 进行了检查,并且检查代码本身没有引发异常,那么 Bob 也应该随时RaiseFromAbove,从而帮助他的代码的用户。

最佳答案

这个问题一直没有好的/直接的/权威的答案。我在“需要权威引用”类别下发布了赏金,最接近的是 Martijn 的评论,即:

  1. 明确地做到这一点的方法是改变回溯对象或生成一个新对象;
  2. 不能在纯 Python 中完成,但必须通过处理不受支持的 API 基础架构来完成;
  3. 这不值得。

我也是这么怀疑的。因此,除非/直到任何人实际上可以提供权威引用来说明这种方法的不可能性,否则我会将其作为“已接受”答案发布在这里。

但我不认为它不是 Python 的一个有值(value)的愿望 list 项目。这个问题产生了相当多的“你不应该想要这样做”的情绪,我仍然不同意:

  • 当然,Bob 应该学会正确阅读回溯,但是让他更容易这样做有什么错 - 帮助 Alice 帮助他指导他的注意正确的地方? Bob 天真到联系 Alice 并报告她代码中的错误的场景是一个夸大(尽管可能)的例子来说明这一点。更有可能的是,他只会有一个不必要的 2 秒停顿,因为他认为“第 17 行的问题......哦等等,不,调用者才是问题所在”。但为什么不饶过他,让编程用户体验更流畅呢?在我看来,Python 的理念似乎就是围绕消除这种摩擦展开的。

  • 当然,任何假定的 RaiseFromAbove 都可能 被 Alice 不加区别地使用,或者以其他方式滥用,因此可能会让 Bob 更加困惑而不是更少。对我来说,这是一个虚假的论点,因为它同样适用于 Alice 可能做出的任何其他不明智的编码决定,实际上也适用于 Python 和其他语言中已经存在的许多强大功能。应根据说明和安全警告正确使用来判断锋利工具的值(value)。

无论如何,赏金截止日期临近,如果我什么都不做,我相信一半的赏金将用于投票最高的答案。目前这是 Tore 的,但对我来说,只加 1 并让 Bob 做侦探工作的想法与我的目的相反:这让它看起来像 Alice 的代码中有问题.通过追查问题的智力练习,Bob 可能会成为更好的程序员,但他可能很着急,而且无论如何按照这种逻辑,我们都将在裸机上编程。因此,我会将赏金奖励给 yinnonsanders 的回答,不是因为它是一个完整且令人满意的解决方案,而是因为它至少符合问题的精神并且可能在某些情况下有效。

关于python - 引发似乎来自调用者的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46250124/

有关python - 引发似乎来自调用者的异常的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. ruby-on-rails - Rails - 乐观锁定总是触发 StaleObjectError 异常 - 2

    我正在学习Rails,并阅读了关于乐观锁的内容。我已将类型为integer的lock_version列添加到我的articles表中。但现在每当我第一次尝试更新记录时,我都会收到StaleObjectError异常。这是我的迁移:classAddLockVersionToArticle当我尝试通过Rails控制台更新文章时:article=Article.first=>#我这样做:article.title="newtitle"article.save我明白了:(0.3ms)begintransaction(0.3ms)UPDATE"articles"SET"title"='dwdwd

  3. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  4. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

    在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

  5. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  6. ruby - 在 Ruby 中重新分配常量时抛出异常? - 2

    我早就知道Ruby中的“常量”(即大写的变量名)不是真正常量。与其他编程语言一样,对对象的引用是唯一存储在变量/常量中的东西。(侧边栏:Ruby确实具有“卡住”引用对象不被修改的功能,据我所知,许多其他语言都没有提供这种功能。)所以这是我的问题:当您将一个值重新分配给常量时,您会收到如下警告:>>FOO='bar'=>"bar">>FOO='baz'(irb):2:warning:alreadyinitializedconstantFOO=>"baz"有没有办法强制Ruby抛出异常而不是打印警告?很难弄清楚为什么有时会发生重新分配。 最佳答案

  7. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  8. ruby - 调用其他方法的 TDD 方法的正确方法 - 2

    我需要一些关于TDD概念的帮助。假设我有以下代码defexecute(command)casecommandwhen"c"create_new_characterwhen"i"display_inventoryendenddefcreate_new_character#dostufftocreatenewcharacterenddefdisplay_inventory#dostufftodisplayinventoryend现在我不确定要为什么编写单元测试。如果我为execute方法编写单元测试,那不是几乎涵盖了我对create_new_character和display_invent

  9. ruby-on-rails - Capybara-webkit 引发 Capybara::Driver::Webkit::WebkitInvalidResponseError - 2

    我在rspec中收到来自webkit驱动程序的以下消息:Capybara::Driver::Webkit::WebkitInvalidResponseError:UnabletoloadURL:http://127.0.0.1:44923/posts几天前它成功了。问题出在save_page方法上。有什么问题吗? 最佳答案 当我的页面出现错误时,我收到过类似的错误消息。您应该通过在测试模式下启动服务器(railss-etest)并自行访问页面来手动检查情况是否如此。 关于ruby-on-

  10. Python 相当于 Perl/Ruby ||= - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。

随机推荐