Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to catch Python exceptions dynamically

2025-03-30 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

How to dynamically catch Python exceptions, many novices are not very clear about this, in order to help you solve this problem, the following editor will explain for you in detail, people with this need can come to learn, I hope you can gain something.

What surprises me when talking about dynamic catching exceptions is that it allows me to find hidden Bug and fun.

Problematic code

The following code comes from an abstract code that looks good in a product-slightly (!). This is a function that calls some statistics and then processes them. The first is to use a socket connection to get a value, a socket error may have occurred. Since statistics are not critical in the system, we just write down log errors and move on.

(please note that I tested this article with doctest-this means the code can run!)

> def get_stats (): Pass... > > def do_something_with_stats (stats):... Pass... > > try:... Stats = get_stats ()... Except socket.error:... Logging.warning ("Can't get statistics")... Else:... Do_something_with_stats (stats)

Find

We didn't find anything wrong with the test, but in fact we noticed that the static analysis report showed a problem:

$flake8 filename.py filename.py:351:1: F821 undefined name 'socket' filename.py:352:1: F821 undefined name' logging'

Obviously we didn't test, the problem is that we didn't refer to socket and logging modules in the code. To my surprise, this didn't throw a NameError error in advance. I thought it would look for some nouns in these exception statements. If it needs to catch these exceptions, what does it need to know?

It turns out that this is not the case. the search for exception statements is delayed and an exception is thrown during evaluation. Not only the name delay lookup, but also the custom display declaration exception as a 'parameter (argument)'.

This can be a good thing, a bad thing, or disgusting.

A good thing (mentioned in the previous paragraph)

Exception parameters can be passed numerically in any form. This allows abnormal dynamic parameters to be captured.

> def do_something (): Blob. > > def attempt (action, ignore_spec):... Try:... Action ()... Except ignore_spec:... Pass... > > attempt (do_something, ignore_spec= (NameError, TypeError)) > attempt (do_something, ignore_spec=TypeError) Traceback (most recent call last):. NameError: global name 'blob' is not defined

Bad things (mentioned in the previous paragraph)

The obvious drawback is that errors in exception parameters are usually noticed only after the exception is triggered, but it is too late. When using exceptions to catch unusual events (for example, failure to open a file by writing), unless you make a specific test case, you will only know when an exception (or any exception) is triggered, log it and see if there is a matching exception, and throw its own error exception-this is what NameError usually does.

> def do_something (): Return 1, 2... > > try:... A, b = do_something (). Except ValuError: # oops-someone can't type... Print ("Oops")... Else:... Print ("OK!") # we are 'ok' until do_something returns a triple... OK!

Obnoxious (mentioned in the previous paragraph)

Try:... TypeError = ZeroDivisionError # now why would we do is. Steps!. 1 / 0. Except TypeError:... Print ("Caught!")... Else:... Print ("ok")... Caught!

It's not just exception parameters that are looked up by name,-other expressions work this way:

> try:... 1 / 0... Except eval ('.join (' Zero Division Error'.split ():... Print ("Caught!")... Else:... Print ("ok")... Caught!

Exception parameters can not only be determined at run time, but can even use exception information during the life cycle. Here is a more elusive way to catch thrown exceptions-but that's it:

> import sys > def current_exc_type ():... Return sys.exc_info () [0]... > try:... Blob... Except current_exc_type ():... Print ("Got you!")... Got you!

Obviously, this is what we're really looking for, and when we write exception handlers, the first thing we should think of is this.

(byte) code

To confirm how it occurs in exception handling, I run dis.dis () in an exception example. Note that the decomposition here is under Python2.7-different bytecodes are generated under Python 3.3, but this is basically similar:

> import dis > def x ():... Try:... Pass... Except Blobbity:... Print ("bad")... Else:... Print ("good")... > dis.dis (x) # doctest: + NORMALIZE_WHITESPACE 20 SETUP_EXCEPT 4 (to 7) 3 3 POP_BLOCK 4 JUMP_FORWARD 22 (to 29) 4 > > 7 DUP_TOP 8 LOAD_GLOBAL 0 (Blobbity) 11 COMPARE_OP 10 (exception match) 14 POP_JUMP_IF_FALSE 28 17 POP_TOP 18 POP_TOP 19 POP_TOP 5 20 LOAD_CONST 1 ('bad') 23 PRINT_ITEM 24 PRINT_NEWLINE 25 JUMP_FORWARD 6 (to 34) > 28 END_FINALLY 7 > > 29 LOAD_CONST 2 ('good') 32 PRINT_ITEM 33 PRINT_NEWLINE > > 34 LOAD_CONST 0 (None) 37 RETURN_VALUE

This shows the problem I had expected (issue). Exception handling "seems" to operate entirely according to the internal mechanism of Python. There is no need to know about subsequent exception "catch" statements at this step, and if no exceptions are thrown, they will be completely ignored. Setup _ EXCEPT doesn't care about what happened, just that if an exception occurs, * handlers should be evaluated, and then a second, and so on.

Each handler consists of two parts: get an exception rule and compare it with the exception you just threw. Everything is delayed, and everything seems to be as expected for your line-by-line code, from the perspective of the interpreter. Nothing smart happened, just suddenly made it look very smart.

Summary

Although I was surprised by this dynamic abnormal parameter, it included many interesting applications. Of course, it may be a bad idea to realize many of them, hehe.

Sometimes it is not always intuitive to confirm how many Python features are supported-for example, expressions and declarations are explicitly accepted in class scope (rather than functions, methods, global scopes), but not all are so flexible. Although (I think) that would be wonderful, expressions are prohibited from being applied to decorators-here are Python syntax errors:

@ (lambda fn: fn) def x (): pass

This is an example of trying to pass dynamic exception parameters to * exceptions of a given type, quietly tolerating repeated exceptions:

Class Pushover (object):... Exc_spec = set (). Def attempt (self, action):... Try:... Return action ()... Except tuple (self.exc_spec):... Pass... Except BaseException ase:... Self.exc_spec.add (e.birthday classrooms _). Raise. > > pushover = Pushover () > for _ in range (4):. Try:... Pushover.attempt (lambda: 1 / 0). Except:... Print ("Boo")... Else:... Print ("Yay!") Boo Yay! Yay! Yay! Is it helpful for you to read the above content? If you want to know more about the relevant knowledge or read more related articles, please follow the industry information channel, thank you for your support.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report