标签归档:exception

django MultiValueDictKeyError错误,我该如何处理

问题:django MultiValueDictKeyError错误,我该如何处理

我正在尝试将对象保存到数据库中,但是它引发了MultiValueDictKeyError错误。

问题出在表格内,is_private用一个复选框表示。如果未选中该复选框,则显然不会传递任何内容。这是消除错误的地方。

我如何正确处理并捕获此异常?

该行是

is_private = request.POST['is_private']

I’m trying to save a object to my database, but it’s throwing a MultiValueDictKeyError error.

The problems lies within the form, the is_private is represented by a checkbox. If the check box is NOT selected, obviously nothing is passed. This is where the error gets chucked.

How do I properly deal with this exception, and catch it?

The line is

is_private = request.POST['is_private']

回答 0

使用MultiValueDict的get方法。这在标准字典中也存在,并且是一种在不存在默认值的情况下获取值的方法。

is_private = request.POST.get('is_private', False)

通常,

my_var = dict.get(<key>, <default>)

Use the MultiValueDict’s get method. This is also present on standard dicts and is a way to fetch a value while providing a default if it does not exist.

is_private = request.POST.get('is_private', False)

Generally,

my_var = dict.get(<key>, <default>)

回答 1

选择最适合您的:

1个

is_private = request.POST.get('is_private', False);

如果is_privatekey在request.POST中存在,则is_private变量等于它,如果不相等,则它等于False。

2

if 'is_private' in request.POST:
    is_private = request.POST['is_private']
else:
    is_private = False

3

from django.utils.datastructures import MultiValueDictKeyError
try:
    is_private = request.POST['is_private']
except MultiValueDictKeyError:
    is_private = False

Choose what is best for you:

1

is_private = request.POST.get('is_private', False);

If is_private key is present in request.POST the is_private variable will be equal to it, if not, then it will be equal to False.

2

if 'is_private' in request.POST:
    is_private = request.POST['is_private']
else:
    is_private = False

3

from django.utils.datastructures import MultiValueDictKeyError
try:
    is_private = request.POST['is_private']
except MultiValueDictKeyError:
    is_private = False

回答 2

之所以会这样,是因为您试图从不存在的字典中获取密钥。您需要先测试它是否在其中。

尝试:

is_private = 'is_private' in request.POST

要么

is_private = 'is_private' in request.POST and request.POST['is_private']

取决于您使用的值。

You get that because you’re trying to get a key from a dictionary when it’s not there. You need to test if it is in there first.

try:

is_private = 'is_private' in request.POST

or

is_private = 'is_private' in request.POST and request.POST['is_private']

depending on the values you’re using.


回答 3

您为什么不尝试is_private在模型中定义为default=False

class Foo(models.Models):
    is_private = models.BooleanField(default=False)

Why didn’t you try to define is_private in your models as default=False?

class Foo(models.Models):
    is_private = models.BooleanField(default=False)

回答 4

要记住的另一件事是request.POST['keyword']引用由指定的html name属性标识的元素keyword

因此,如果您的表格是:

<form action="/login/" method="POST">
  <input type="text" name="keyword" placeholder="Search query">
  <input type="number" name="results" placeholder="Number of results">
</form>

然后,request.POST['keyword']和分别request.POST['results']包含输入元素keyword和的值results

Another thing to remember is that request.POST['keyword'] refers to the element identified by the specified html name attribute keyword.

So, if your form is:

<form action="/login/" method="POST">
  <input type="text" name="keyword" placeholder="Search query">
  <input type="number" name="results" placeholder="Number of results">
</form>

then, request.POST['keyword'] and request.POST['results'] will contain the value of the input elements keyword and results, respectively.


回答 5

首先检查请求对象是否具有’is_private’键参数。多数情况下,此MultiValueDictKeyError发生是因为类字典的请求对象中缺少键。由于字典是无序键,因此值对为“关联存储器”或“关联数组”

换句话说。request.GET或request.POST是类似于字典的对象,包含所有请求参数。这是特定于Django的。

如果key在字典中,则方法get()返回给定key的值。如果key不可用,则返回默认值None。

您可以通过以下方式处理此错误:

is_private = request.POST.get('is_private', False);

First check if the request object have the ‘is_private’ key parameter. Most of the case’s this MultiValueDictKeyError occurred for missing key in the dictionary-like request object. Because dictionary is an unordered key, value pair “associative memories” or “associative arrays”

In another word. request.GET or request.POST is a dictionary-like object containing all request parameters. This is specific to Django.

The method get() returns a value for the given key if key is in the dictionary. If key is not available then returns default value None.

You can handle this error by putting :

is_private = request.POST.get('is_private', False);

回答 6

对我而言,由于以下原因,此错误在我的django项目中发生:

  1. 我在项目的模板文件夹中的home.html文件中插入了一个新的超链接,如下所示:

    <input type="button" value="About" onclick="location.href='{% url 'about' %}'">

  2. 在views.py中,我具有count和about的以下定义:

   def count(request):
           fulltext = request.GET['fulltext']
           wordlist = fulltext.split()
           worddict = {}
           for word in wordlist:
               if word in worddict:
                   worddict[word] += 1
               else:
                   worddict[word] = 1
                   worddict = sorted(worddict.items(), key = operator.itemgetter(1),reverse=True)
           return render(request,'count.html', 'fulltext':fulltext,'count':len(wordlist),'worddict'::worddict})

   def about(request): 
       return render(request,"about.html")
  1. 在urls.py中,我具有以下url模式:
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('',views.homepage,name="home"),
        path('eggs',views.eggs),
        path('count/',views.count,name="count"),
        path('about/',views.count,name="about"),
    ]

可以看出没有。上面的3,在最后一个url模式中,我错误地调用了views.count而我需要调用views.about。fulltext = request.GET['fulltext']views.py的count函数中的这一行(由于在urlpatterns中输入错误而被错误地调用)引发了multivaluedictkeyerror异常。

然后,我将urls.py中的最后一个URL模式更改为正确的模式,即path('about/',views.about,name="about"),一切正常。

显然,通常django中的新手程序员会犯这样的错误,即我错误地为URL调用了另一个视图函数,这可能是期望使用不同的参数集或在其render调用中传递不同的对象集,而不是预期的行为。

希望这可以帮助一些新手程序员使用django。

For me, this error occurred in my django project because of the following:

  1. I inserted a new hyperlink in my home.html present in templates folder of my project as below:

    <input type="button" value="About" onclick="location.href='{% url 'about' %}'">
  2. In views.py, I had the following definitions of count and about:

   def count(request):
           fulltext = request.GET['fulltext']
           wordlist = fulltext.split()
           worddict = {}
           for word in wordlist:
               if word in worddict:
                   worddict[word] += 1
               else:
                   worddict[word] = 1
                   worddict = sorted(worddict.items(), key = operator.itemgetter(1),reverse=True)
           return render(request,'count.html', 'fulltext':fulltext,'count':len(wordlist),'worddict'::worddict})

   def about(request): 
       return render(request,"about.html")
  1. In urls.py, I had the following url patterns:
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('',views.homepage,name="home"),
        path('eggs',views.eggs),
        path('count/',views.count,name="count"),
        path('about/',views.count,name="about"),
    ]

As can be seen in no. 3 above,in the last url pattern, I was incorrectly calling views.count whereas I needed to call views.about. This line fulltext = request.GET['fulltext'] in count function (which was mistakenly called because of wrong entry in urlpatterns) of views.py threw the multivaluedictkeyerror exception.

Then I changed the last url pattern in urls.py to the correct one i.e. path('about/',views.about,name="about"), and everything worked fine.

Apparently, in general a newbie programmer in django can make the mistake I made of wrongly calling another view function for a url, which might be expecting different set of parameters or passing different set of objects in its render call, rather than the intended behavior.

Hope this helps some newbie programmer to django.


如何捕获像异常一样的numpy警告(不仅用于测试)?

问题:如何捕获像异常一样的numpy警告(不仅用于测试)?

我必须在Python中为正在执行的项目制作Lagrange多项式。我正在做一个重心样式,以避免使用显式的for循环,而不是牛顿的分差样式。我的问题是我需要用零除,但是Python(或者也许是numpy)只是将其警告而不是正常异常。

因此,我需要知道的是如何捕获此警告,就像它是一个exceptions一样。我在本网站上发现的与此相关的问题并未按照我需要的方式回答。这是我的代码:

import numpy as np
import matplotlib.pyplot as plt
import warnings

class Lagrange:
    def __init__(self, xPts, yPts):
        self.xPts = np.array(xPts)
        self.yPts = np.array(yPts)
        self.degree = len(xPts)-1 
        self.weights = np.array([np.product([x_j - x_i for x_j in xPts if x_j != x_i]) for x_i in xPts])

    def __call__(self, x):
        warnings.filterwarnings("error")
        try:
            bigNumerator = np.product(x - self.xPts)
            numerators = np.array([bigNumerator/(x - x_j) for x_j in self.xPts])
            return sum(numerators/self.weights*self.yPts) 
        except Exception, e: # Catch division by 0. Only possible in 'numerators' array
            return yPts[np.where(xPts == x)[0][0]]

L = Lagrange([-1,0,1],[1,0,1]) # Creates quadratic poly L(x) = x^2

L(1) # This should catch an error, then return 1. 

执行此代码后,我得到的输出是:

Warning: divide by zero encountered in int_scalars

那是我要抓住的警告。它应该出现在列表理解中。

I have to make a Lagrange polynomial in Python for a project I’m doing. I’m doing a barycentric style one to avoid using an explicit for-loop as opposed to a Newton’s divided difference style one. The problem I have is that I need to catch a division by zero, but Python (or maybe numpy) just makes it a warning instead of a normal exception.

So, what I need to know how to do is to catch this warning as if it were an exception. The related questions to this I found on this site were answered not in the way I needed. Here’s my code:

import numpy as np
import matplotlib.pyplot as plt
import warnings

class Lagrange:
    def __init__(self, xPts, yPts):
        self.xPts = np.array(xPts)
        self.yPts = np.array(yPts)
        self.degree = len(xPts)-1 
        self.weights = np.array([np.product([x_j - x_i for x_j in xPts if x_j != x_i]) for x_i in xPts])

    def __call__(self, x):
        warnings.filterwarnings("error")
        try:
            bigNumerator = np.product(x - self.xPts)
            numerators = np.array([bigNumerator/(x - x_j) for x_j in self.xPts])
            return sum(numerators/self.weights*self.yPts) 
        except Exception, e: # Catch division by 0. Only possible in 'numerators' array
            return yPts[np.where(xPts == x)[0][0]]

L = Lagrange([-1,0,1],[1,0,1]) # Creates quadratic poly L(x) = x^2

L(1) # This should catch an error, then return 1. 

When this code is executed, the output I get is:

Warning: divide by zero encountered in int_scalars

That’s the warning I want to catch. It should occur inside the list comprehension.


回答 0

看来您的配置正在使用print选项numpy.seterr

>>> import numpy as np
>>> np.array([1])/0   #'warn' mode
__main__:1: RuntimeWarning: divide by zero encountered in divide
array([0])
>>> np.seterr(all='print')
{'over': 'warn', 'divide': 'warn', 'invalid': 'warn', 'under': 'ignore'}
>>> np.array([1])/0   #'print' mode
Warning: divide by zero encountered in divide
array([0])

这意味着您看到的警告不是真正的警告,而只是打印了一些字符stdout(请参阅文档以获取信息seterr)。如果您想抓住它,可以:

  1. 使用numpy.seterr(all='raise')它将直接引发异常。但是,这会更改所有操作的行为,因此,这是行为上的很大变化。
  2. 使用numpy.seterr(all='warn'),可以将打印的警告转换为真实的警告,您将可以使用上述解决方案来本地化此行为更改。

实际warnings收到警告后,您可以使用该模块来控制警告的处理方式:

>>> import warnings
>>> 
>>> warnings.filterwarnings('error')
>>> 
>>> try:
...     warnings.warn(Warning())
... except Warning:
...     print 'Warning was raised as an exception!'
... 
Warning was raised as an exception!

请仔细阅读文档,filterwarnings因为它可以使您仅过滤所需的警告并具有其他选项。我还要考虑看看catch_warnings哪个是上下文管理器,它会自动重置原始filterwarnings功能:

>>> import warnings
>>> with warnings.catch_warnings():
...     warnings.filterwarnings('error')
...     try:
...         warnings.warn(Warning())
...     except Warning: print 'Raised!'
... 
Raised!
>>> try:
...     warnings.warn(Warning())
... except Warning: print 'Not raised!'
... 
__main__:2: Warning: 

It seems that your configuration is using the print option for numpy.seterr:

>>> import numpy as np
>>> np.array([1])/0   #'warn' mode
__main__:1: RuntimeWarning: divide by zero encountered in divide
array([0])
>>> np.seterr(all='print')
{'over': 'warn', 'divide': 'warn', 'invalid': 'warn', 'under': 'ignore'}
>>> np.array([1])/0   #'print' mode
Warning: divide by zero encountered in divide
array([0])

This means that the warning you see is not a real warning, but it’s just some characters printed to stdout(see the documentation for seterr). If you want to catch it you can:

  1. Use numpy.seterr(all='raise') which will directly raise the exception. This however changes the behaviour of all the operations, so it’s a pretty big change in behaviour.
  2. Use numpy.seterr(all='warn'), which will transform the printed warning in a real warning and you’ll be able to use the above solution to localize this change in behaviour.

Once you actually have a warning, you can use the warnings module to control how the warnings should be treated:

>>> import warnings
>>> 
>>> warnings.filterwarnings('error')
>>> 
>>> try:
...     warnings.warn(Warning())
... except Warning:
...     print 'Warning was raised as an exception!'
... 
Warning was raised as an exception!

Read carefully the documentation for filterwarnings since it allows you to filter only the warning you want and has other options. I’d also consider looking at catch_warnings which is a context manager which automatically resets the original filterwarnings function:

>>> import warnings
>>> with warnings.catch_warnings():
...     warnings.filterwarnings('error')
...     try:
...         warnings.warn(Warning())
...     except Warning: print 'Raised!'
... 
Raised!
>>> try:
...     warnings.warn(Warning())
... except Warning: print 'Not raised!'
... 
__main__:2: Warning: 

回答 1

在@Bakuriu的答案中添加一些内容:

如果您已经知道警告可能在何处发生,那么使用numpy.errstate上下文管理器通常会更干净一些,而不是 numpy.seterr将所有相同类型的后续警告视为相同,而不管它们在代码中的位置如何:

import numpy as np

a = np.r_[1.]
with np.errstate(divide='raise'):
    try:
        a / 0   # this gets caught and handled as an exception
    except FloatingPointError:
        print('oh no!')
a / 0           # this prints a RuntimeWarning as usual

编辑:

在我最初的示例中,我有a = np.r_[0],但是显然numpy的行为发生了变化,使得在分子为全零的情况下对零除的处理方式有所不同。例如,在numpy 1.16.4中:

all_zeros = np.array([0., 0.])
not_all_zeros = np.array([1., 0.])

with np.errstate(divide='raise'):
    not_all_zeros / 0.  # Raises FloatingPointError

with np.errstate(divide='raise'):
    all_zeros / 0.  # No exception raised

with np.errstate(invalid='raise'):
    all_zeros / 0.  # Raises FloatingPointError

相应的警告消息也不同:1. / 0.记录为RuntimeWarning: divide by zero encountered in true_divide,而0. / 0.记录为RuntimeWarning: invalid value encountered in true_divide。我不确定为什么要进行此更改,但是我怀疑这与以下事实有关:0. / 0.是不能表示为数字(numpy的回报为NaN在这种情况下),而1. / 0.-1. / 0.分别返回+ Inf文件和-Inf ,符合IEE 754标准。

如果您想捕获两种类型的错误,则可以始终通过np.errstate(divide='raise', invalid='raise'),或者all='raise'如果您想对任何类型的浮点错误引发异常。

To add a little to @Bakuriu’s answer:

If you already know where the warning is likely to occur then it’s often cleaner to use the numpy.errstate context manager, rather than numpy.seterr which treats all subsequent warnings of the same type the same regardless of where they occur within your code:

import numpy as np

a = np.r_[1.]
with np.errstate(divide='raise'):
    try:
        a / 0   # this gets caught and handled as an exception
    except FloatingPointError:
        print('oh no!')
a / 0           # this prints a RuntimeWarning as usual

Edit:

In my original example I had a = np.r_[0], but apparently there was a change in numpy’s behaviour such that division-by-zero is handled differently in cases where the numerator is all-zeros. For example, in numpy 1.16.4:

all_zeros = np.array([0., 0.])
not_all_zeros = np.array([1., 0.])

with np.errstate(divide='raise'):
    not_all_zeros / 0.  # Raises FloatingPointError

with np.errstate(divide='raise'):
    all_zeros / 0.  # No exception raised

with np.errstate(invalid='raise'):
    all_zeros / 0.  # Raises FloatingPointError

The corresponding warning messages are also different: 1. / 0. is logged as RuntimeWarning: divide by zero encountered in true_divide, whereas 0. / 0. is logged as RuntimeWarning: invalid value encountered in true_divide. I’m not sure why exactly this change was made, but I suspect it has to do with the fact that the result of 0. / 0. is not representable as a number (numpy returns a NaN in this case) whereas 1. / 0. and -1. / 0. return +Inf and -Inf respectively, per the IEE 754 standard.

If you want to catch both types of error you can always pass np.errstate(divide='raise', invalid='raise'), or all='raise' if you want to raise an exception on any kind of floating point error.


回答 2

为了详细说明上述@Bakuriu的答案,我发现这使我能够以类似于捕获错误警告的方式捕获运行时警告,从而很好地打印警告:

import warnings

with warnings.catch_warnings():
    warnings.filterwarnings('error')
    try:
        answer = 1 / 0
    except Warning as e:
        print('error found:', e)

您可能可以尝试放置warnings.catch_warnings()的位置,具体取决于您要用这种方式捕获错误的伞的大小。

To elaborate on @Bakuriu’s answer above, I’ve found that this enables me to catch a runtime warning in a similar fashion to how I would catch an error warning, printing out the warning nicely:

import warnings

with warnings.catch_warnings():
    warnings.filterwarnings('error')
    try:
        answer = 1 / 0
    except Warning as e:
        print('error found:', e)

You will probably be able to play around with placing of the warnings.catch_warnings() placement depending on how big of an umbrella you want to cast with catching errors this way.


回答 3

删除warnings.filterwarnings并添加:

numpy.seterr(all='raise')

Remove warnings.filterwarnings and add:

numpy.seterr(all='raise')

Python:在__init__中引发异常是否不好?

问题:Python:在__init__中引发异常是否不好?

在其中引发异常是否被认为是不好的形式__init__?如果是这样,那么当某些类变量初始化为None错误类型或类型错误时,可以接受的引发错误的方法是什么?

Is it considered bad form to raise exceptions within __init__? If so, then what is the accepted method of throwing an error when certain class variables are initialized as None or of an incorrect type?


回答 0

在内部引发异常__init__()是绝对可以的。在构造函数中没有其他好的方法来指示错误情况,并且标准库中有数百个示例,在这些示例中构建对象会引发异常。

当然,要提出的错误类别由您决定。ValueError如果向构造函数传递了无效的参数,则最好。

Raising exceptions within __init__() is absolutely fine. There’s no other good way to indicate an error condition within a constructor, and there are many hundreds of examples in the standard library where building an object can raise an exception.

The error class to raise, of course, is up to you. ValueError is best if the constructor was passed an invalid parameter.


回答 1

确实,在构造函数中指示错误的唯一正确方法是引发异常。这就是为什么在C ++和其他考虑到异常安全性设计的面向对象的语言中,如果在对象的构造函数中抛出异常(表示对象的初始化不完整),则不会调用析构函数。在脚本语言(例如Python)中通常不是这种情况。例如,如果socket.connect()失败,以下代码将引发AttributeError:

class NetworkInterface:
    def __init__(self, address)
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.connect(address)
        self.stream = self.socket.makefile()

    def __del__(self)
        self.stream.close()
        self.socket.close()

原因是在连接尝试失败之后,流属性初始化之前,调用了不完整对象的析构函数。您不应该避免从构造函数中引发异常,我只是说很难在Python中编写完全安全的异常代码。一些Python开发人员完全避免使用析构函数,但这是另一个参数的问题。

It’s true that the only proper way to indicate an error in a constructor is raising an exception. That is why in C++ and in other object-oriented languages that have been designed with exception safety in mind, the destructor is not called if an exception is thrown in the constructor of an object (meaning that the initialization of the object is incomplete). This is often not the case in scripting languages, such as Python. For example, the following code throws an AttributeError if socket.connect() fails:

class NetworkInterface:
    def __init__(self, address)
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.connect(address)
        self.stream = self.socket.makefile()

    def __del__(self)
        self.stream.close()
        self.socket.close()

The reason is that the destructor of the incomplete object is called after the connection attempt has failed, before the stream attribute has been initialized. You shouldn’t avoid throwing exceptions from constructors, I’m just saying that it’s difficult to write fully exception safe code in Python. Some Python developers avoid using destructors altogether, but that’s a matter of another debate.


回答 2

我看不出任何形式的错误。

相反,与返回错误代码相反,已知异常处理得很好的原因之一是,构造函数通常无法返回错误代码。因此,至少在像C ++这样的语言中,引发异常是发出错误的唯一途径。

I don’t see any reason that it should be bad form.

On the contrary, one of the things exceptions are known for doing well, as opposed to returning error codes, is that error codes usually can’t be returned by constructors. So at least in languages like C++, raising exceptions is the only way to signal errors.


回答 3

标准库说:

>>> f = file("notexisting.txt")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory: 'notexisting.txt'

我也没有真正看到任何理由将其视为错误的形式。

The standard library says:

>>> f = file("notexisting.txt")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory: 'notexisting.txt'

Also I don’t really see any reason why it should be considered bad form.


回答 4

我应该认为这是内置ValueError异常的完美案例。

I should think it is the perfect case for the built-in ValueError exception.


回答 5

我同意以上所有观点。

除了引发异常外,实际上没有其他方法可以表明对象的初始化出错。

在大多数程序类中,类的状态完全取决于该类的输入,我们可能期望引发某种ValueError或TypeError。

如果(例如)网络设备不可用或无法写入画布对象,则具有副作用的类(例如,进行网络或图形处理的类)可能会在初始化中引发错误。这对我来说听起来很合理,因为您通常希望尽快了解故障情况。

I concur with all of the above.

There’s really no other way to signal that something went wrong in the initialisation of an object other than raising an exception.

In most programs classes where the state of a class is wholly dependant on the inputs to that class we might expect some kind of ValueError or TypeError to be raised.

Classes with side-effects (e.g. one which does networking or graphics) might raise an error in init if (for example) the network device is unavailable or the canvas object cannot be written to. This sounds sensible to me because often you want to know about failure conditions as soon as possible.


回答 6

在某些情况下,不可避免地要从init引发错误,但是init太多的工作是不好的风格。您应该考虑建立工厂或伪工厂-一种简单的类方法,该方法返回设置的对象。

Raising errors from init is unavoidable in some cases, but doing too much work in init is a bad style. You should consider making a factory or a pseudo-factory – a simple classmethod that returns setted up object.


如何获取在Python中捕获的异常的名称?

问题:如何获取在Python中捕获的异常的名称?

如何获得在Python中引发的异常的名称?

例如,

try:
    foo = bar
except Exception as exception:
    name_of_exception = ???
    assert name_of_exception == 'NameError'
    print "Failed with exception [%s]" % name_of_exception

例如,我捕获了多个(或所有)异常,并想在错误消息中打印异常的名称。

How can I get the name of an exception that was raised in Python?

e.g.,

try:
    foo = bar
except Exception as exception:
    name_of_exception = ???
    assert name_of_exception == 'NameError'
    print "Failed with exception [%s]" % name_of_exception

For example, I am catching multiple (or all) exceptions, and want to print the name of the exception in an error message.


回答 0

以下是获取异常类名称的几种不同方法:

  1. type(exception).__name__
  2. exception.__class__.__name__
  3. exception.__class__.__qualname__

例如,

try:
    foo = bar
except Exception as exception:
    assert type(exception).__name__ == 'NameError'
    assert exception.__class__.__name__ == 'NameError'
    assert exception.__class__.__qualname__ == 'NameError'

Here are a few different ways to get the name of the class of the exception:

  1. type(exception).__name__
  2. exception.__class__.__name__
  3. exception.__class__.__qualname__

e.g.,

try:
    foo = bar
except Exception as exception:
    assert type(exception).__name__ == 'NameError'
    assert exception.__class__.__name__ == 'NameError'
    assert exception.__class__.__qualname__ == 'NameError'

回答 1

这行得通,但似乎必须有一种更简单,更直接的方法?

try:
    foo = bar
except Exception as exception:
    assert repr(exception) == '''NameError("name 'bar' is not defined",)'''
    name = repr(exception).split('(')[0]
    assert name == 'NameError'

This works, but it seems like there must be an easier, more direct way?

try:
    foo = bar
except Exception as exception:
    assert repr(exception) == '''NameError("name 'bar' is not defined",)'''
    name = repr(exception).split('(')[0]
    assert name == 'NameError'

回答 2

您也可以使用sys.exc_info()exc_info()返回3个值:类型,值,回溯。关于文档:https : //docs.python.org/3/library/sys.html#sys.exc_info

import sys

try:
    foo = bar
except Exception:
    exc_type, value, traceback = sys.exc_info()
    assert exc_type.__name__ == 'NameError'
    print "Failed with exception [%s]" % exc_type.__name__

You can also use sys.exc_info(). exc_info() returns 3 values: type, value, traceback. On documentation: https://docs.python.org/3/library/sys.html#sys.exc_info

import sys

try:
    foo = bar
except Exception:
    exc_type, value, traceback = sys.exc_info()
    assert exc_type.__name__ == 'NameError'
    print "Failed with exception [%s]" % exc_type.__name__

回答 3

如果您想要完全限定的类名(例如,sqlalchemy.exc.IntegrityError而不是仅使用IntegrityError),则可以使用下面的函数,该函数是我从MB对另一个问题的出色回答(我只是重命名了一些变量以适合自己的口味)而来:

def get_full_class_name(obj):
    module = obj.__class__.__module__
    if module is None or module == str.__class__.__module__:
        return obj.__class__.__name__
    return module + '.' + obj.__class__.__name__

例:

try:
    # <do something with sqlalchemy that angers the database>
except sqlalchemy.exc.SQLAlchemyError as e:
    print(get_full_class_name(e))

# sqlalchemy.exc.IntegrityError

If you want the fully qualified class name (e.g. sqlalchemy.exc.IntegrityError instead of just IntegrityError), you can use the function below, which I took from MB’s awesome answer to another question (I just renamed some variables to suit my tastes):

def get_full_class_name(obj):
    module = obj.__class__.__module__
    if module is None or module == str.__class__.__module__:
        return obj.__class__.__name__
    return module + '.' + obj.__class__.__name__

Example:

try:
    # <do something with sqlalchemy that angers the database>
except sqlalchemy.exc.SQLAlchemyError as e:
    print(get_full_class_name(e))

# sqlalchemy.exc.IntegrityError

回答 4

此处的其他答案非常适合用于探索目的,但是如果主要目标是记录异常(包括异常的名称),则可以考虑使用logging.exception而不是print?

The other answers here are great for exploration purposes, but if the primary goal is to log the exception (including the name of the exception), perhaps consider using logging.exception instead of print?


如何处理列表推导中的异常?

问题:如何处理列表推导中的异常?

我在Python中有一些列表理解,其中每次迭代都可能引发异常。

例如,如果我有:

eggs = (1,3,0,3,2)

[1/egg for egg in eggs]

我将ZeroDivisionError在第3个元素中得到一个exceptions。

如何处理此异常并继续执行列表理解?

我能想到的唯一方法是使用辅助函数:

def spam(egg):
    try:
        return 1/egg
    except ZeroDivisionError:
        # handle division by zero error
        # leave empty for now
        pass

但这对我来说有点麻烦。

有没有更好的方法在Python中执行此操作?

注意: 这是我做的一个简单示例(请参阅上面的“ 例如 ”),因为我的实际示例需要一些上下文。我对避免除以零错误不感兴趣,但对处理列表理解中的异常不感兴趣。

I have some a list comprehension in Python in which each iteration can throw an exception.

For instance, if I have:

eggs = (1,3,0,3,2)

[1/egg for egg in eggs]

I’ll get a ZeroDivisionError exception in the 3rd element.

How can I handle this exception and continue execution of the list comprehension?

The only way I can think of is to use a helper function:

def spam(egg):
    try:
        return 1/egg
    except ZeroDivisionError:
        # handle division by zero error
        # leave empty for now
        pass

But this looks a bit cumbersome to me.

Is there a better way to do this in Python?

Note: This is a simple example (see “for instance” above) that I contrived because my real example requires some context. I’m not interested in avoiding divide by zero errors but in handling exceptions in a list comprehension.


回答 0

Python中没有内置表达式可让您忽略异常(或在异常的情况下返回替代值&c),因此从字面上来讲,“处理列表推导中的异常”是不可能的,因为列表推导是一个表达式包含其他表达式,仅此而已(即,没有语句,只有语句可以捕获/忽略/处理异常)。

函数调用是表达式,函数主体可以包含您想要的所有语句,因此,如您所注意到的,将易于发生异常的子表达式的评估委托给函数是一种可行的解决方法(其他可行时,检查可能引发异常的值,如其他答案中所建议)。

对“如何处理列表理解中的异常”这一问题的正确回答都表达了所有这些事实的一部分:1)从字面上,即从词法上讲,在理解本身中,你不能做到;2)实际上,在可行的情况下,您将作业委派给某个函数或检查易于出错的值。您一再声称这不是一个答案是没有根据的。

There is no built-in expression in Python that lets you ignore an exception (or return alternate values &c in case of exceptions), so it’s impossible, literally speaking, to “handle exceptions in a list comprehension” because a list comprehension is an expression containing other expression, nothing more (i.e., no statements, and only statements can catch/ignore/handle exceptions).

Function calls are expression, and the function bodies can include all the statements you want, so delegating the evaluation of the exception-prone sub-expression to a function, as you’ve noticed, is one feasible workaround (others, when feasible, are checks on values that might provoke exceptions, as also suggested in other answers).

The correct responses to the question “how to handle exceptions in a list comprehension” are all expressing part of all of this truth: 1) literally, i.e. lexically IN the comprehension itself, you can’t; 2) practically, you delegate the job to a function or check for error prone values when that’s feasible. Your repeated claim that this is not an answer is thus unfounded.


回答 1

我意识到这个问题已经很老了,但是您也可以创建一个通用函数来简化这种事情:

def catch(func, handle=lambda e : e, *args, **kwargs):
    try:
        return func(*args, **kwargs)
    except Exception as e:
        return handle(e)

然后,在您的理解中:

eggs = (1,3,0,3,2)
[catch(lambda : 1/egg) for egg in eggs]
[1, 0, ('integer division or modulo by zero'), 0, 0]

当然,您可以随意设置默认的句柄函数(例如,您宁愿默认返回“ None”)。

希望这对您或该问题的将来的读者有帮助!

注意:在python 3中,我只将’handle’参数作为关键字,并将其放在参数列表的末尾。这将使实际传递的论点变得更加自然。

I realize this question is quite old, but you can also create a general function to make this kind of thing easier:

def catch(func, handle=lambda e : e, *args, **kwargs):
    try:
        return func(*args, **kwargs)
    except Exception as e:
        return handle(e)

Then, in your comprehension:

eggs = (1,3,0,3,2)
[catch(lambda : 1/egg) for egg in eggs]
[1, 0, ('integer division or modulo by zero'), 0, 0]

You can of course make the default handle function whatever you want (say you’d rather return ‘None’ by default).

Hope this helps you or any future viewers of this question!

Note: in python 3, I would make the ‘handle’ argument keyword only, and put it at the end of the argument list. This would make actually passing arguments and such through catch much more natural.


回答 2

您可以使用

[1/egg for egg in eggs if egg != 0]

这只会跳过零元素。

You can use

[1/egg for egg in eggs if egg != 0]

this will simply skip elements that are zero.


回答 3

没有,没有更好的方法。在很多情况下,您可以像Peter一样使用回避

您的另一选择是不使用理解

eggs = (1,3,0,3,2)

result=[]
for egg in eggs:
    try:
        result.append(egg/0)
    except ZeroDivisionError:
        # handle division by zero error
        # leave empty for now
        pass

由您决定是否比较麻烦

No there’s not a better way. In a lot of cases you can use avoidance like Peter does

Your other option is to not use comprehensions

eggs = (1,3,0,3,2)

result=[]
for egg in eggs:
    try:
        result.append(egg/0)
    except ZeroDivisionError:
        # handle division by zero error
        # leave empty for now
        pass

Up to you to decide whether that is more cumbersome or not


回答 4

我认为,正如提出最初问题的人和布莱恩·海德(Bryan Head)所建议的那样,辅助功能很好,一点也不麻烦。单行执行所有工作的魔术代码总是不可能的,因此,如果要避免for循环,辅助函数是一个完美的解决方案。但是我将其修改为此:

# A modified version of the helper function by the Question starter 
def spam(egg):
    try:
        return 1/egg, None
    except ZeroDivisionError as err:
        # handle division by zero error        
        return None, err

输出将是this [(1/1, None), (1/3, None), (None, ZeroDivisionError), (1/3, None), (1/2, None)]。有了这个答案,您完全可以控制以任何您想要的方式继续。

I think a helper function, as suggested by the one who asks the initial question and Bryan Head as well, is good and not cumbersome at all. A single line of magic code which does all the work is just not always possible so a helper function is a perfect solution if one wants to avoid for loops. However I would modify it to this one:

# A modified version of the helper function by the Question starter 
def spam(egg):
    try:
        return 1/egg, None
    except ZeroDivisionError as err:
        # handle division by zero error        
        return None, err

The output will be this [(1/1, None), (1/3, None), (None, ZeroDivisionError), (1/3, None), (1/2, None)]. With this answer you are in full control to continue in any way you want.

Alternative:

def spam2(egg):
    try:
        return 1/egg 
    except ZeroDivisionError:
        # handle division by zero error        
        return ZeroDivisionError

Yes, the error is returned, not raised.


回答 5

我没有任何答案提及此事。但是此示例将是一种防止在已知失败案例中引发异常的方法。

eggs = (1,3,0,3,2)
[1/egg if egg > 0 else None for egg in eggs]


Output: [1, 0, None, 0, 0]

I didn’t see any answer mention this. But this example would be one way of preventing an exception from being raised for known failing cases.

eggs = (1,3,0,3,2)
[1/egg if egg > 0 else None for egg in eggs]


Output: [1, 0, None, 0, 0]

Python中异常处理程序的成本

问题:Python中异常处理程序的成本

另一个问题中,可接受的答案建议用try / except块替换Python代码中的(非常便宜)if语句,以提高性能。

除了编码样式问题外,并假设永远不会触发异常,拥有一个异常处理程序与没有一个异常处理程序,与拥有与零比较的if语句相比,在性能方面有何不同?

In another question, the accepted answer suggested replacing a (very cheap) if statement in Python code with a try/except block to improve performance.

Coding style issues aside, and assuming that the exception is never triggered, how much difference does it make (performance-wise) to have an exception handler, versus not having one, versus having a compare-to-zero if-statement?


回答 0

为什么不使用timeit模块进行测量?这样,您可以查看它是否与您的应用程序相关。

好,所以我已经尝试了以下方法:

import timeit

statements=["""\
try:
    b = 10/a
except ZeroDivisionError:
    pass""",
"""\
if a:
    b = 10/a""",
"b = 10/a"]

for a in (1,0):
    for s in statements:
        t = timeit.Timer(stmt=s, setup='a={}'.format(a))
        print("a = {}\n{}".format(a,s))
        print("%.2f usec/pass\n" % (1000000 * t.timeit(number=100000)/100000))

结果:

a = 1
try:
    b = 10/a
except ZeroDivisionError:
    pass
0.25 usec/pass

a = 1
if a:
    b = 10/a
0.29 usec/pass

a = 1
b = 10/a
0.22 usec/pass

a = 0
try:
    b = 10/a
except ZeroDivisionError:
    pass
0.57 usec/pass

a = 0
if a:
    b = 10/a
0.04 usec/pass

a = 0
b = 10/a
ZeroDivisionError: int division or modulo by zero

因此,正如预期的那样,没有任何异常处理程序会稍快一些(但在发生异常时会炸毁您的脸),并且只要不满足条件,它try/except就会比显式的要快if

但这一切都在同一数量级内,并且无论哪种方式都不太重要。仅当实际满足条件时,if版本才会明显更快。

Why don’t you measure it using the timeit module? That way you can see whether it’s relevant to your application.

OK, so I’ve just tried the following:

import timeit

statements=["""\
try:
    b = 10/a
except ZeroDivisionError:
    pass""",
"""\
if a:
    b = 10/a""",
"b = 10/a"]

for a in (1,0):
    for s in statements:
        t = timeit.Timer(stmt=s, setup='a={}'.format(a))
        print("a = {}\n{}".format(a,s))
        print("%.2f usec/pass\n" % (1000000 * t.timeit(number=100000)/100000))

Result:

a = 1
try:
    b = 10/a
except ZeroDivisionError:
    pass
0.25 usec/pass

a = 1
if a:
    b = 10/a
0.29 usec/pass

a = 1
b = 10/a
0.22 usec/pass

a = 0
try:
    b = 10/a
except ZeroDivisionError:
    pass
0.57 usec/pass

a = 0
if a:
    b = 10/a
0.04 usec/pass

a = 0
b = 10/a
ZeroDivisionError: int division or modulo by zero

So, as expected, not having any exception handler is slightly faster (but blows up in your face when the exception happens), and try/except is faster than an explicit if as long as the condition is not met.

But it’s all within the same order of magnitude and unlikely to matter either way. Only if the condition is actually met, then the if version is significantly faster.


回答 1

设计和历史常见问题解答中实际上回答了这个问题

如果没有引发异常,则try / except块非常有效。实际上捕获异常是昂贵的。

This question is actually answered in the Design and History FAQ:

A try/except block is extremely efficient if no exceptions are raised. Actually catching an exception is expensive.


回答 2

这个问题是误导的。如果您假设从未触发该异常,那么这两个都不是最佳代码。

如果您假设异常是作为错误条件的一部分而触发的,那么您已经超出了想要最佳代码的范围(而且您可能始终无法像这样细粒度地对其进行处理)。

如果您将异常用作标准控制流程的一部分(这是Pythonic的“询问宽恕,而不是允许”的方式),那么异常将被触发,代价取决于异常的种类,如果,以及您估计发生异常的时间百分比。

This question is misleading. If you assume the exception is never triggered, neither one is optimal code.

If you assume the exception is triggered as part of an error condition, you are already outside the realm of wanting optimal code (and you probably aren’t handling it at a fine-grained level like that anyway).

If you are using the exception as part of the standard control flow – which is the Pythonic “ask forgiveness, not permission” way – then the exception is going to be triggered, and the cost depends on the kind of exception, the kind of if, and what percentage of time you estimate the exception happens.


如何在嵌套的try / except块中重新引发异常?

问题:如何在嵌套的try / except块中重新引发异常?

我知道如果我想重新引发异常,我会raise在相应的except块中简单地使用不带参数的形式。但是给定一个嵌套的表达式

try:
    something()
except SomeError as e:
    try:
        plan_B()
    except AlsoFailsError:
        raise e  # I'd like to raise the SomeError as if plan_B()
                 # didn't raise the AlsoFailsError

我如何在SomeError不破坏堆栈跟踪的情况下重新筹集?raise在这种情况下,仅此一项便会重新提高AlsoFailsError。或者我该如何重构我的代码来避免此问题?

I know that if I want to re-raise an exception, I simple use raise without arguments in the respective except block. But given a nested expression like

try:
    something()
except SomeError as e:
    try:
        plan_B()
    except AlsoFailsError:
        raise e  # I'd like to raise the SomeError as if plan_B()
                 # didn't raise the AlsoFailsError

how can I re-raise the SomeError without breaking the stack trace? raise alone would in this case re-raise the more recent AlsoFailsError. Or how could I refactor my code to avoid this issue?


回答 0

从Python 3开始,回溯存储在异常中,因此raise e(大多数)正确的事情很简单:

try:
    something()
except SomeError as e:
    try:
        plan_B()
    except AlsoFailsError:
        raise e  # or raise e from None - see below

产生的追溯将包括SomeError在处理过程中发生的其他通知AlsoFailsError(由于位于raise e内部except AlsoFailsError)。这具有误导性,因为实际发生的是相反的情况-我们AlsoFailsError在尝试从恢复时遇到并处理了它SomeError。要获取不包含的回溯AlsoFailsError,请替换raise eraise e from None

在Python 2中,您将异常类型,值和回溯存储在局部变量中,并使用以下三个参数的形式raise

try:
    something()
except SomeError:
    t, v, tb = sys.exc_info()
    try:
        plan_B()
    except AlsoFailsError:
        raise t, v, tb

As of Python 3 the traceback is stored in the exception, so a simple raise e will do the (mostly) right thing:

try:
    something()
except SomeError as e:
    try:
        plan_B()
    except AlsoFailsError:
        raise e  # or raise e from None - see below

The traceback produced will include an additional notice that SomeError occurred while handling AlsoFailsError (because of raise e being inside except AlsoFailsError). This is misleading because what actually happened is the other way around – we encountered AlsoFailsError, and handled it, while trying to recover from SomeError. To obtain a traceback that doesn’t include AlsoFailsError, replace raise e with raise e from None.

In Python 2 you’d store the exception type, value, and traceback in local variables and use the three-argument form of raise:

try:
    something()
except SomeError:
    t, v, tb = sys.exc_info()
    try:
        plan_B()
    except AlsoFailsError:
        raise t, v, tb

回答 1

即使接受的解决方案正确,也最好使用指向具有Python 2 + 3解决方案的Sixsix.reraise

六。重新提高exc_typeexc_valueexc_traceback = None)

重新引发异常,可能使用不同的回溯。[…]

因此,您可以编写:

import six


try:
    something()
except SomeError:
    t, v, tb = sys.exc_info()
    try:
        plan_B()
    except AlsoFailsError:
        six.reraise(t, v, tb)

Even if the accepted solution is right, it’s good to point to the Six library which has a Python 2+3 solution, using six.reraise.

six.reraise(exc_type, exc_value, exc_traceback=None)

Reraise an exception, possibly with a different traceback. […]

So, you can write:

import six


try:
    something()
except SomeError:
    t, v, tb = sys.exc_info()
    try:
        plan_B()
    except AlsoFailsError:
        six.reraise(t, v, tb)

回答 2

根据Drew McGowen的建议,但考虑到一般情况(存在返回值s),这是user4815162342的替代方法:

try:
    s = something()
except SomeError as e:
    def wrapped_plan_B():
        try:
            return False, plan_B()
        except:
            return True, None
    failed, s = wrapped_plan_B()
    if failed:
        raise

As per Drew McGowen’s suggestion, but taking care of a general case (where a return value s is present), here’s an alternative to user4815162342’s answer:

try:
    s = something()
except SomeError as e:
    def wrapped_plan_B():
        try:
            return False, plan_B()
        except:
            return True, None
    failed, s = wrapped_plan_B()
    if failed:
        raise

回答 3

Python 3.5+始终将追溯信息附加到错误,因此不再需要单独保存它。

>>> def f():
...   try:
...     raise SyntaxError
...   except Exception as e:
...     err = e
...     try:
...       raise AttributeError
...     except Exception as e1:
...       raise err from None
>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 9, in f
  File "<stdin>", line 3, in f
SyntaxError: None
>>> 

Python 3.5+ attaches the traceback information to the error anyway, so it’s no longer necessary to save it separately.

>>> def f():
...   try:
...     raise SyntaxError
...   except Exception as e:
...     err = e
...     try:
...       raise AttributeError
...     except Exception as e1:
...       raise err from None
>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 9, in f
  File "<stdin>", line 3, in f
SyntaxError: None
>>> 

如何在Python中正确获取异常消息

问题:如何在Python中正确获取异常消息

从Python标准库的组件中获取异常消息的最佳方法是什么?

我注意到在某些情况下,您可以通过如下message字段获取它:

try:
  pass
except Exception as ex:
  print(ex.message)

但在某些情况下(例如在套接字错误的情况下),您必须执行以下操作:

try:
  pass
except socket.error as ex:
  print(ex)

我想知道是否有标准方法可以涵盖大多数情况?

What is the best way to get exceptions’ messages from components of standard library in Python?

I noticed that in some cases you can get it via message field like this:

try:
  pass
except Exception as ex:
  print(ex.message)

but in some cases (for example, in case of socket errors) you have to do something like this:

try:
  pass
except socket.error as ex:
  print(ex)

I wondered is there any standard way to cover most of these situations?


回答 0

如果您查看有关内置错误文档,则会看到大多数Exception类将其第一个参数分配为message属性。并非所有人都这样做。

值得注意的是,EnvironmentError(与子类IOErrorOSError)具有的第一自变量errno,第二的strerror。没有messagestrerror大致类似于通常的message

更一般而言,的子类Exception可以执行他们想要的任何操作。它们可能具有也可能没有message属性。将来的内置Exception可能没有message属性。Exception从第三方库或用户代码导入的任何子类都可能没有message属性。

我认为处理此问题的正确方法是,确定Exception要捕获的特定子类,然后仅捕获那些子类,而不是所有带有的except Exception子类,然后利用特定子类定义的任何属性(如果需要)。

如果您必须执行print某些操作,则我认为打印捕获到的内容Exception本身很可能会执行您想要的操作,无论它是否具有message属性。

您也可以像这样检查消息属性,但是我不会真正建议它,因为它看起来很混乱:

try:
    pass
except Exception as e:
    # Just print(e) is cleaner and more likely what you want,
    # but if you insist on printing message specifically whenever possible...
    if hasattr(e, 'message'):
        print(e.message)
    else:
        print(e)

If you look at the documentation for the built-in errors, you’ll see that most Exception classes assign their first argument as a message attribute. Not all of them do though.

Notably,EnvironmentError (with subclasses IOError and OSError) has a first argument of errno, second of strerror. There is no messagestrerror is roughly analogous to what would normally be a message.

More generally, subclasses of Exception can do whatever they want. They may or may not have a message attribute. Future built-in Exceptions may not have a message attribute. Any Exception subclass imported from third-party libraries or user code may not have a message attribute.

I think the proper way of handling this is to identify the specific Exception subclasses you want to catch, and then catch only those instead of everything with an except Exception, then utilize whatever attributes that specific subclass defines however you want.

If you must print something, I think that printing the caught Exception itself is most likely to do what you want, whether it has a message attribute or not.

You could also check for the message attribute if you wanted, like this, but I wouldn’t really suggest it as it just seems messy:

try:
    pass
except Exception as e:
    # Just print(e) is cleaner and more likely what you want,
    # but if you insist on printing message specifically whenever possible...
    if hasattr(e, 'message'):
        print(e.message)
    else:
        print(e)

回答 1

为了改善@artofwarfare提供的答案,这是我考虑的一种更整洁的方法来检查message属性并打印它或将Exception对象打印为后备。

try:
    pass 
except Exception as e:
    print getattr(e, 'message', repr(e))

调用repr是可选的,但我发现在某些用例中有必要。


更新#1:

@MadPhysicist发表评论之后,这证明了为什么repr可能需要调用。尝试在解释器中运行以下代码:

try:
    raise Exception 
except Exception as e:
    print(getattr(e, 'message', repr(e)))
    print(getattr(e, 'message', str(e)))

更新#2:

这是一个具有Python 2.7和3.5细节的演示:https : //gist.github.com/takwas/3b7a6edddef783f2abddffda1439f533

To improve on the answer provided by @artofwarfare, here is what I consider a neater way to check for the message attribute and print it or print the Exception object as a fallback.

try:
    pass 
except Exception as e:
    print getattr(e, 'message', repr(e))

The call to repr is optional, but I find it necessary in some use cases.


Update #1:

Following the comment by @MadPhysicist, here’s a proof of why the call to repr might be necessary. Try running the following code in your interpreter:

try:
    raise Exception 
except Exception as e:
    print(getattr(e, 'message', repr(e)))
    print(getattr(e, 'message', str(e)))

Update #2:

Here is a demo with specifics for Python 2.7 and 3.5: https://gist.github.com/takwas/3b7a6edddef783f2abddffda1439f533


回答 2

我有同样的问题。我认为最好的解决方案是使用log.exception,它将自动打印出堆栈跟踪和错误消息,例如:

try:
    pass
    log.info('Success')
except:
    log.exception('Failed')

I had the same problem. I think the best solution is to use log.exception, which will automatically print out stack trace and error message, such as:

try:
    pass
    log.info('Success')
except:
    log.exception('Failed')

回答 3

我也有同样的问题。对此进行深入研究,我发现Exception类具有一个args属性,该属性捕获了用于创建异常的参数。如果将except的异常范围缩小到一个子集,则应该能够确定它们的构造方式,从而确定哪个参数包含消息。

try:
   # do something that may raise an AuthException
except AuthException as ex:
   if ex.args[0] == "Authentication Timeout.":
      # handle timeout
   else:
      # generic handling

I too had the same problem. Digging into this I found that the Exception class has an args attribute, which captures the arguments that were used to create the exception. If you narrow the exceptions that except will catch to a subset, you should be able to determine how they were constructed, and thus which argument contains the message.

try:
   # do something that may raise an AuthException
except AuthException as ex:
   if ex.args[0] == "Authentication Timeout.":
      # handle timeout
   else:
      # generic handling

在Python中,如何将警告视为异常?

问题:在Python中,如何将警告视为异常?

我在python代码中使用的第三方库(用C编写)正在发出警告。我希望能够使用try except语法正确处理这些警告。有没有办法做到这一点?

A third-party library (written in C) that I use in my python code is issuing warnings. I want to be able to use the try except syntax to properly handle these warnings. Is there a way to do this?


回答 0

引用python手册(27.6.4。Testing Warnings):

import warnings

def fxn():
    warnings.warn("deprecated", DeprecationWarning)

with warnings.catch_warnings(record=True) as w:
    # Cause all warnings to always be triggered.
    warnings.simplefilter("always")
    # Trigger a warning.
    fxn()
    # Verify some things
    assert len(w) == 1
    assert issubclass(w[-1].category, DeprecationWarning)
    assert "deprecated" in str(w[-1].message)

To quote from the python handbook (27.6.4. Testing Warnings):

import warnings

def fxn():
    warnings.warn("deprecated", DeprecationWarning)

with warnings.catch_warnings(record=True) as w:
    # Cause all warnings to always be triggered.
    warnings.simplefilter("always")
    # Trigger a warning.
    fxn()
    # Verify some things
    assert len(w) == 1
    assert issubclass(w[-1].category, DeprecationWarning)
    assert "deprecated" in str(w[-1].message)

回答 1

要将警告作为错误处理,只需使用以下命令:

import warnings
warnings.filterwarnings("error")

之后,您将能够捕获与错误相同的警告,例如,它将起作用:

try:
    some_heavy_calculations()
except RuntimeWarning:
    import ipdb; ipdb.set_trace()

PS添加了此答案,因为注释中的最佳答案包含拼写错误:filterwarnigns而不是filterwarnings

To handle warnings as errors simply use this:

import warnings
warnings.filterwarnings("error")

After this you will be able to catch warnings same as errors, e.g. this will work:

try:
    some_heavy_calculations()
except RuntimeWarning:
    import ipdb; ipdb.set_trace()

P.S. Added this answer because the best answer in comments contains misspelling: filterwarnigns instead of filterwarnings.


回答 2

如果只希望脚本在警告上失败,则可以使用:

python -W error foobar.py

If you just want you script to fail on warnings you can invoke python with the -W argument:

python -W error foobar.py

回答 3

这是一个变体,可让您更清楚地了解如何仅使用自定义警告。

import warnings
with warnings.catch_warnings(record=True) as w:
    # Cause all warnings to always be triggered.
    warnings.simplefilter("always")

    # Call some code that triggers a custom warning.
    functionThatRaisesWarning()

    # ignore any non-custom warnings that may be in the list
    w = filter(lambda i: issubclass(i.category, UserWarning), w)

    if len(w):
        # do something with the first warning
        email_admins(w[0].message)

Here’s a variation that makes it clearer how to work with only your custom warnings.

import warnings
with warnings.catch_warnings(record=True) as w:
    # Cause all warnings to always be triggered.
    warnings.simplefilter("always")

    # Call some code that triggers a custom warning.
    functionThatRaisesWarning()

    # ignore any non-custom warnings that may be in the list
    w = filter(lambda i: issubclass(i.category, UserWarning), w)

    if len(w):
        # do something with the first warning
        email_admins(w[0].message)

回答 4

在某些情况下,您需要使用ctypes将警告变成错误。例如:

str(b'test')  # no error
import warnings
warnings.simplefilter('error', BytesWarning)
str(b'test')  # still no error
import ctypes
ctypes.c_int.in_dll(ctypes.pythonapi, 'Py_BytesWarningFlag').value = 2
str(b'test')  # this raises an error

In some cases, you need use ctypes to turn warnings into errors. For example:

str(b'test')  # no error
import warnings
warnings.simplefilter('error', BytesWarning)
str(b'test')  # still no error
import ctypes
ctypes.c_int.in_dll(ctypes.pythonapi, 'Py_BytesWarningFlag').value = 2
str(b'test')  # this raises an error

没有括号的“ raise exception()”和“ raise exception”之间有区别吗?

问题:没有括号的“ raise exception()”和“ raise exception”之间有区别吗?

定义无参数异常:

class MyException(Exception):
    pass

举起时,它们之间是否有任何区别:

raise MyException

raise MyException()

我找不到任何东西。它仅仅是一个重载的语法吗?

Defining a parameterless exception:

class MyException(Exception):
    pass

When raised, is there any difference between:

raise MyException

and

raise MyException()

I couldn’t find any; is it simply an overloaded syntax?


回答 0

简短的回答是,无论raise MyExceptionraise MyException()做同样的事情。第一种形式会自动实例化您的异常。

docs相关部分说:“ 抬高将第一个表达式评估为异常对象。它必须是BaseException的子类或实例。如果是类,则在需要时通过使用实例化该类来获取异常实例。没有参数。”

也就是说,即使语义相同,第一种形式在微观上也更快,而第二种形式则更灵活(因为如果需要,可以将其传递给参数)。

大多数人在Python中(即在标准库,流行的应用程序和许多书中)使用的通常样式是在raise MyException没有参数的情况下使用。人们仅在需要传递一些参数时才直接实例化异常。例如: raise KeyError(badkey)

The short answer is that both raise MyException and raise MyException() do the same thing. This first form auto instantiates your exception.

The relevant section from the docs says, “raise evaluates the first expression as the exception object. It must be either a subclass or an instance of BaseException. If it is a class, the exception instance will be obtained when needed by instantiating the class with no arguments.”

That said, even though the semantics are the same, the first form is microscopically faster, and the second form is more flexible (because you can pass it arguments if needed).

The usual style that most people use in Python (i.e. in the standard library, in popular applications, and in many books) is to use raise MyException when there are no arguments. People only instantiate the exception directly when there some arguments need to be passed. For example: raise KeyError(badkey).


回答 1

去看看raise声明的文档。它正在创建的实例MyException

Go look at the docs for the raise statement. It’s creating an instance of MyException.


回答 2

是的,ValueError和之间有区别ValueError()

ValueError是一个类,而ValueError()创建一个类的实例。这就是原因type(ValueError) is typetype(ValueError()) is ValueError

的唯一目的raise是引发异常,

当我们使用时ValueError,将调用class,该class依次运行构造函数 ValueError()

当我们使用时ValueError(),该方法ValueError()被直接调用。

注意: raise ValueError # shorthand for 'raise ValueError()'

Yep, there is a difference between ValueError and ValueError()

ValueError is a class whereas ValueError() creates an instance of a class. This is the reason the type(ValueError) is type and type(ValueError()) is ValueError

The sole purpose of raise is to raise the exception,

when we use ValueError, class will be called which in turn runs the constructor ValueError()

when we use ValueError(), the method ValueError() is directly called.

Note: raise ValueError # shorthand for 'raise ValueError()'