Python3 错误和异常

语法错误与异常、try/except/else/finally、抛出异常、自定义异常与清理行为。

Beginner
Key Points语法错误在编译期暴露,异常在运行期抛出;捕获要具体、不要裸 except;finally 无论是否异常都会执行。

语法错误

Syntax errors are the most common kind: the source does not conform to Python grammar, so the interpreter refuses to compile it and reports the line plus a ^ pointing near the problem.

Python
try:
    compile('while True print("hi")', '<demo>', 'exec')
except SyntaxError as e:
    print("SyntaxError:", e.msg)
    print("line:", e.lineno)
    print("offset:", e.offset)

try:
    compile('def f(:\n    pass', '<demo>', 'exec')
except SyntaxError as e:
    print("SyntaxError:", e.msg)
Output
SyntaxError: invalid syntax
line: 1
offset: 12
SyntaxError: invalid syntax

异常

Even valid syntax can fail at runtime: division by zero, index out of range, missing key, type mismatch. These are exceptions — they abort the current flow and print a traceback; read it bottom-up to find the failing line.

Python
cases = [
    lambda: 1 / 0,
    lambda: [1, 2][5],
    lambda: {'a': 1}['b'],
    lambda: 'a' + 1,
]

for fn in cases:
    try:
        fn()
    except Exception as e:
        print(type(e).__name__, '->', e)
Output
ZeroDivisionError -> division by zero
IndexError -> list index out of range
KeyError -> 'b'
TypeError -> can only concatenate str (not "int") to str

异常处理

Put risky code in try, catch by type in except, run else when nothing raised, and finally always. Handlers match top-down, so list subclasses before their base classes.

Python
def safe_div(a, b):
    try:
        result = a / b
    except ZeroDivisionError:
        print("cannot divide by zero")
        return None
    except TypeError as e:
        print("bad operand:", e)
        return None
    else:
        print("ok")
        return result
    finally:
        print("-- finally --")

print(safe_div(6, 3))
print(safe_div(1, 0))
print(safe_div('a', 2))
Output
ok
-- finally --
2.0
cannot divide by zero
-- finally --
None
bad operand: unsupported operand type(s) for /: 'str' and 'int'
-- finally --
None
Never write a bare except: or except Exception: pass — it swallows KeyboardInterrupt and real bugs alike. Catch only the specific types you can actually handle.

抛出异常

raise throws deliberately — a class or an instance. raise ... from ... keeps the original cause visible, and a bare raise inside except re-raises unchanged.

Python
def set_age(age):
    if not isinstance(age, int):
        raise TypeError("age must be int, got %s" % type(age).__name__)
    if age < 0:
        raise ValueError("age must be >= 0, got %d" % age)
    return age

for v in (18, -1, 'x'):
    try:
        print("age:", set_age(v))
    except (TypeError, ValueError) as e:
        print(type(e).__name__, '->', e)

try:
    try:
        1 / 0
    except ZeroDivisionError as e:
        raise RuntimeError("compute failed") from e
except RuntimeError as e:
    print("cause:", type(e.__cause__).__name__)
Output
age: 18
ValueError -> age must be >= 0, got -1
TypeError -> age must be int, got str
cause: ZeroDivisionError

用户自定义异常

Custom exceptions subclass Exception (or a descendant) and are named ...Error. Adding attributes lets callers read extra context inside except.

Python
class ValidationError(Exception):
    def __init__(self, field, message):
        super().__init__("%s: %s" % (field, message))
        self.field = field
        self.message = message

def validate(user):
    if not user.get('email'):
        raise ValidationError('email', 'is required')
    return True

try:
    validate({'name': 'Tom'})
except ValidationError as e:
    print("field:", e.field)
    print("message:", e.message)
    print("str:", e)
    print("is Exception:", isinstance(e, Exception))
Output
field: email
message: is required
str: email: is required
is Exception: True

定义清理行为

The finally clause runs whether or not an exception occurred — even across return — so it is the place to release resources. Beware: a return inside finally overrides the value from try.

Python
def f():
    try:
        print("try")
        return "from try"
    finally:
        print("finally")

print(f())

def g():
    try:
        raise ValueError("boom")
    finally:
        print("cleanup runs even on error")

try:
    g()
except ValueError as e:
    print("caught:", e)
Output
try
finally
from try
cleanup runs even on error
caught: boom

预定义的清理行为

Some objects clean up after themselves and with triggers it: closing files, releasing locks, returning connections. This is the context-manager protocol __enter__ / __exit__, where __exit__ plays the role of finally.

Python
class Resource:
    def __enter__(self):
        print("acquire")
        return self
    def __exit__(self, exc_type, exc, tb):
        print("release")
        return False

with Resource() as r:
    print("working")

try:
    with Resource() as r:
        raise ValueError("boom")
except ValueError as e:
    print("caught:", e)

with open('out.txt', 'w', encoding='utf-8') as f:
    f.write("hi")
print("file closed:", f.closed)
Output
acquire
working
release
acquire
release
caught: boom
file closed: True

Friends & Partners