我正在编写自己的容器,需要通过属性调用来访问内部的字典.容器的典型用法如下:
dict_container = DictContainer()
dict_container['foo'] = bar
...
print dict_container.foo
Run Code Online (Sandbox Code Playgroud)
我知道写这样的东西可能是愚蠢的,但这是我需要提供的功能.我正在考虑以下列方式实现它:
def __getattribute__(self, item):
try:
return object.__getattribute__(item)
except AttributeError:
try:
return self.dict[item]
except KeyError:
print "The object doesn't have such attribute"
Run Code Online (Sandbox Code Playgroud)
我不确定嵌套的try/except块是否是一个好习惯,所以另一种方法是使用hasattr()
和has_key()
:
def __getattribute__(self, item):
if hasattr(self, item):
return object.__getattribute__(item)
else:
if self.dict.has_key(item):
return self.dict[item]
else:
raise AttributeError("some customised error")
Run Code Online (Sandbox Code Playgroud)
或者使用其中一个和一个尝试catch块,如下所示:
def __getattribute__(self, item):
if hasattr(self, item):
return object.__getattribute__(item)
else:
try:
return self.dict[item]
except KeyError:
raise AttributeError("some customised error")
Run Code Online (Sandbox Code Playgroud)
哪个选项最pythonic和优雅?
我在这段代码中有一条 pylint 消息(w0707)(来自https://www.django-rest-framework.org/tutorial/3-class-based-views/):
class SnippetDetail(APIView):
"""
Retrieve, update or delete a snippet instance.
"""
def get_object(self, pk):
try:
return Snippet.objects.get(pk=pk)
except Snippet.DoesNotExist:
raise Http404
Run Code Online (Sandbox Code Playgroud)
信息是:
Consider explicitly re-raising using the 'from' keyword
我不太明白如何采取行动来纠正问题。
预先感谢您的帮助
这些是Python异常的属性,但是我无法绕过它们.Python的文档似乎相当安静.我看了一下文档,但我很困惑.那么,两者之间有什么区别?它们是如何使用的?
编辑:就此而言__traceback__
,如果有的话,它们是如何相关的?
编辑3:我想我只是不明白__cause__
.我终于明白了__traceback__
和__context__
.为什么不attribute_error.__cause__
参考AttributeError()
?
try:
raise NameError() from OSError
except NameError as name_error:
print('name_error.__cause__: %s' % repr(name_error.__cause__))
print('name_error.__context__: %s' % repr(name_error.__context__))
print('name_error.__traceback__: %s' % repr(name_error.__traceback__))
try:
raise AttributeError()
except AttributeError as attribute_error:
print('attribute_error.__cause__: %s' % repr(attribute_error.__cause__))
print('attribute_error.__context__: %s' % repr(attribute_error.__context__))
print('attribute_error.__traceback__: %s' % repr(attribute_error.__traceback__))
raise attribute_error from IndexError
Run Code Online (Sandbox Code Playgroud)
这输出
name_error.__cause__: OSError()
name_error.__context__: None
name_error.__traceback__: <traceback object at 0x000000000346CAC8>
attribute_error.__cause__: None
attribute_error.__context__: NameError()
attribute_error.__traceback__: <traceback object at 0x000000000346CA88> …
Run Code Online (Sandbox Code Playgroud) 我写我需要从外部调用一个包pytest
从内pytest
通过运行subprocess
。很明显,从子进程捕获的输出正是我想要显示的错误,因为它具有 pytest 提供的所有漂亮的格式和信息。不幸的是,目前主要的 pytest 调用只显示我的包装器的内部代码,而不是漂亮的子进程输出,在我打印它之后,只显示在 pytest 的捕获标准输出部分。我想格式化失败和错误的输出,就好像直接调用代码一样,并隐藏进行了子进程调用。因此,我基本上想用不同的字符串完全替换一个测试函数的输出。这可能吗?
让我们看一个简单包装函数的 MWE(没有做任何有用的事情,但是我能想到的最短的 MWE):
import functools
from subprocess import Popen, PIPE
import sys
def call_something(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# for the sake of simplicity, a dummy call
p = Popen([sys.executable, '-c', 'import numby'], stderr=PIPE, stdout=PIPE)
# let's imagine this is the perfect string output we want
# to print instead of the actual output generated from...
error = p.communicate()[1].decode("utf-8")
if p.returncode != 0:
# ... …
Run Code Online (Sandbox Code Playgroud) 我已经开始使用pytest-vcr
which 是一个pytest
插件包装VCR.py
,我在这篇关于 Advanced Python Testing 的博客文章中记录了它。
它cassettes/*.yml
在第一次测试运行时将所有 HTTP 流量记录到文件中以保存快照。类似于Web 组件的Jest快照测试。
在后续的测试运行中,如果请求格式错误,它将找不到匹配项并抛出异常,表示禁止记录新请求并且未找到现有记录。
VCR.py
引发 aCannotOverwriteExistingCassetteException
并没有特别说明为什么它不匹配。
我如何利用 pytest
pytest_exception_interact
钩子将这个异常替换为一个利用夹具信息的信息更丰富的异常?
我一头扎进我的site-packages
地方VCR.py
是pip installed
并重新编写我希望如何处理异常。我只需要知道如何让这个pytest_exception_interact
钩子正常工作,以从该测试节点访问设备(在它被清理之前)并引发不同的异常。
让我们获取依赖项。
$ pip install pytest pytest-vcr requests
Run Code Online (Sandbox Code Playgroud)
test_example.py:
import pytest
import requests
@pytest.mark.vcr
def test_example():
r = requests.get("https://www.stackoverflow.com")
assert r.status_code == 200
Run Code Online (Sandbox Code Playgroud)
$ pytest test_example.py --vcr-record=once
...
test_example.py::test_example PASSED
...
$ …
Run Code Online (Sandbox Code Playgroud) 我正在尝试创建一个 try- except 块,该块重新引发任意异常,但仅包含回溯堆栈中的最后一个块。
像这样的东西:
import traceback
def my_func(shorten_tracebacks=True):
try:
# Do stuff here
except Exception as e:
if shorten_tracebacks:
raise TheSameTypeOfError, e, traceback.print_exc(limit=1)
else:
raise(e)
Run Code Online (Sandbox Code Playgroud)
有没有更好的方法来做到这一点?
如果重要的话,我这样做是为了方便调试 jupyter 笔记本中经常使用的某些 API——它们往往会生成非常长的堆栈跟踪,其中只有最后一个块提供信息。这迫使用户频繁滚动。如果你不想缩短回溯,你可以随时设置shorten_tracebacks=False
我正在阅读一些包含类似于以下功能的源代码:
def dummy_function():
try:
g = 1/0
except Exception as e:
raise Exception("There is an error: {}".format(e))
Run Code Online (Sandbox Code Playgroud)
据我所知,所有异常都是从Exception类派生的,所以这应该捕获所有错误.在https://docs.python.org/3/tutorial/errors.html之后,那么这不等同于
def dummy_function():
try:
g = 1/0
except:
print "There is an error:"
raise
Run Code Online (Sandbox Code Playgroud)
我注意到在任何一种情况下打印输出的排列都略有不同,但在我看来,第二种方法基本相同且不那么冗长.或者我错过了什么?
考虑在python中编写一个小型库,它有一个x
接受参数的简单方法并ac
返回计算值10/ac
.现在抓住这里是ac
不可能的0
.所以我如何在我的方法中处理这种情况.我想到了这些方法.
注意:我已经研究了python异常处理,但它只是展示了如何使用try except
不是我要求的具体问题.
方法1
def x(ac):
try:
return (10/ac)
except ZeroDivisionError:
raise ZeroDivisionError("ac cannot be zero")
Run Code Online (Sandbox Code Playgroud)
上面的代码只是使用一个普通的try除了块来捕获特定的异常并引发调用代码的异常.所以调用代码看起来像这样:
# some script...
try:
x(0)
except ZeroDivisionError as e:
log(e)
Run Code Online (Sandbox Code Playgroud)
但在这种情况下,我必须事先知道方法x
可能引发的所有可能的异常.
方法2:
def x(ac):
if ac == 0:
raise ValueError("ac cannot be zero") # or ZeroDivisionError??
else:
return (10/ac)
Run Code Online (Sandbox Code Playgroud)
我猜这在语义上与前一个相同,只是为了检查一些条件(我们知道可能会发生)使用if's
和基于此提高异常.它也遇到了事先知道方法可能抛出的异常的相同问题.
方法3
最后一个方法是不处理库方法中的任何异常,而是将其留给客户端代码,但这显然没有意义,因为客户端永远无法知道为什么在诉诸类似的事情时可能会发生错误.
def x(ac):
return (10/ac)
try:
x(20)
except Exception as e:
log(e)
Run Code Online (Sandbox Code Playgroud)
现在这个方法只是一个操作的简单方法,但如果方法本身正在做一些复杂的事情,如连接到数据库然后获取一些结果.就像是 :
def …
Run Code Online (Sandbox Code Playgroud)