12.异常

予早 2024-10-05 23:17:22
Categories: Tags:

抛出异常

# {}.sort()
# assert True is False
# [][0]
# {}['']
# 1 / 0
# open("")
# _
# hello world
# print(list(range(10000000000)))  # MemoryError

try:
    x = 1 / 0
except ZeroDivisionError as original_exception:
    print({}['error'])
    # 重新抛出该异常
    raise

try:
    x = 1 / 0
except ZeroDivisionError as original_exception:
    print({}['error'])
    # 将original_exception抛出
    raise original_exception


try:
    x = 1 / 0
except ZeroDivisionError as original_exception:
    # 引发一个新的异常,同时保留原始异常信息
    raise ValueError("An error occurred") from original_exception

try:
    x = 1 / 0
except ZeroDivisionError as original_exception:
    print({}['error'])
    raise ValueError("An error occurred") from original_exception

try-except[*]-else-finally

执行顺序与返回值

i的类型不同外,其余逻辑均相同,比较i作为整型和i作为列表的两种情况下的返回值,i为整型时,后两次返回值不一样,i为列表时,后两次返回值异常。此处利用不可变类型和可变类型的特点可反映出try-except时返回值如何处理的,执行return先记录返回值地址,然后走完后续try-except流程,返回这个地址中的对象。

i为整型,初始值为1,分别返回1、2、3

def return_int(x):
    try:
        i = 1
        if x == 1:
            return i
    except Exception as error:
        print(error)
    else:
        i += 1
        print("无异常执行else")
        if x == 2:
            return i
    finally:
        i += 1
        print("不管代码是否有问题均执行finally")
        if x == 3:
            return i


# 正常 try -> else -> finally
# 异常 try -> except -> finally


# try返回值 x == 1
print("→", return_int(1))
# 不管代码是否有问题均执行finally
# → 1

# else返回值 x == 2
print("→", return_int(2))
# 无异常执行else
# 不管代码是否有问题均执行finally
# → 2


# finally返回值 x == 3
print("→", return_int(3))
# 无异常执行else
# 不管代码是否有问题均执行finally
# → 3

i为列表,初始值为[1],分别返回[1, 3]、[1, 2, 3]、[1, 2, 3]

def return_int(x):
    try:
        i = [1]
        if x == 1:
            return i
    except Exception as error:
        print(error)
    else:
        i.append(2)
        print("无异常执行else")
        if x == 2:
            return i
    finally:
        i.append(3)
        print("不管代码是否有问题均执行finally")
        if x == 3:
            return i

# 正常 try -> else -> finally
# 异常 try -> except -> finally


# try返回值 x == 1
print("→", return_int(1))
# 不管代码是否有问题均执行finally
# → [1, 3]

# else返回值 x == 2
print("→", return_int(2))
# 无异常执行else
# 不管代码是否有问题均执行finally
# → [1, 2, 3]


# finally返回值 x == 3
print("→", return_int(3))
# 无异常执行else
# 不管代码是否有问题均执行finally
# → [1, 2, 3]

单异常处理

except处理异常组也只处理一次,异常组本质上也是一种异常

import builtins  # 手动导入也没问题


def division(a, b, c, d, f, g):
    try:
        type([1, 2, 3][a])
        if b:
            raise UserWarning('UserWarning')
        c / d
        if f:
            eval("hia hia hia")
        if g:
            raise ExceptionGroup("group", [KeyError(), ValueError(), ExceptionGroup("sub_group", [OSError()])])
    except IndexError:
        print("IndexError")
    except (Warning, ArithmeticError) as e:
        print(e, type(e))
    except ExceptionGroup as e:
        print(e, type(e))
    except Exception as e:
        print('exception兜底', e, type(e))  # 应当在所有异常之后,用于异常捕获兜底
    else:
        print("无异常执行else")
    finally:
        print("不管代码是否有问题均执行finally")


print(division(0, False, 1, 1, False, builtins.str()))
# 无异常执行else
# 不管代码是否有问题均执行finally
# None


print(division(520, False, 1, 1, 0, builtins.str()))
# IndexError
# 不管代码是否有问题均执行finally
# None


print(division(0, True, 1, 1, 0, builtins.str()))
# UserWarning <class 'UserWarning'>
# 不管代码是否有问题均执行finally
# None


print(division(0, False, 1, 0, 0, builtins.str()))
# division by zero <class 'ZeroDivisionError'>
# 不管代码是否有问题均执行finally
# None
# 基于父类捕获异常 ArithmeticError是的父类ZeroDivisionError


print(division(0, False, 1, 1, 1, builtins.str()))
# exception兜底 invalid syntax (<string>, line 1) <class 'SyntaxError'>
# 不管代码是否有问题均执行finally
# None
# 通常使用Exception兜底,Exception为异常体系中大多数异常的父类

print(division(0, False, 1, 1, 0, builtins.str("-")))
# group (3 sub-exceptions) <class 'ExceptionGroup'>
# 不管代码是否有问题均执行finally
# 三个子异常

异常组处理

Python3.11.4及以后引入异常组及except*语句,except*处理异常组会对异常组中每一个异常匹配一次

def division(a, b=1):
    try:
        match a / b:
            case 1:
                raise ZeroDivisionError()
            case 2:
                raise ExceptionGroup('error', [ValueError('value error'), TypeError('type error')])
            case 3:
                raise ExceptionGroup('error',
                                     [ZeroDivisionError(), ExceptionGroup('param error', [ValueError('value error'),
                                                                                          TypeError('type error')])])
            case 4:
                raise ExceptionGroup('error', [ZeroDivisionError()])
            case 5:
                raise ZeroDivisionError
            case 6:
                raise ExceptionGroup('error', [ZeroDivisionError])
            case 7:
                raise ExceptionGroup('error',
                                     [ZeroDivisionError, ExceptionGroup('param error', [ValueError('value error')])])
            case 8:
                raise ExceptionGroup('error', [ZeroDivisionError, KeyError(), ValueError])
    except* ArithmeticError as e:  # ZeroDivisionError的父类
        print(1, e, type(e))
    except* ValueError as e:
        print(2, e, type(e))
    except* KeyError as e:
        print(3, e, type(e))
    except* Exception as e:
        print(4, e, type(e))
    finally:
        print("""↑↑↑""")


# except和except*不兼容
# SyntaxError: cannot have both 'except' and 'except*' on the same 'try'
division(1)
#  1  (1 sub-exception) <class 'ExceptionGroup'>
# 单个异常会被以异常组的方式捕获

division(2)
# 2 error (1 sub-exception) <class 'ExceptionGroup'>
# 4 error (1 sub-exception) <class 'ExceptionGroup'>
# 异常组中每个单个异常会被捕获一次

division(3)
# 1 error (1 sub-exception) <class 'ExceptionGroup'>
# 2 error (1 sub-exception) <class 'ExceptionGroup'>
# 4 error (1 sub-exception) <class 'ExceptionGroup'>
# 异常组可以嵌套为树状

division(4)
# 1 error (1 sub-exception) <class 'ExceptionGroup'>

division(5)
# 1  (1 sub-exception) <class 'ExceptionGroup'>
# ZeroDivisionError不带()可以被捕获

division(6)
# 2  (1 sub-exception) <class 'ExceptionGroup'>
# 但在异常组中不带()会报异常 ValueError: Item 0 of second argument (exceptions) is not an exception
# 没有匹配到 ArithmeticError


division(7)
# 2  (1 sub-exception) <class 'ExceptionGroup'>
# # 但在异常组中不带()会报异常

division(8)
# 2  (1 sub-exception) <class 'ExceptionGroup'>
# # 但在异常组中不带()会报异常

返回值机制

def division(x):
    try:

        i = 1
        if x == 1:
            return i
        if x == 3:
            raise ZeroDivisionError()
    except Exception as error:
        print(error)
        i = 0
        return i
    else:
        i = 2
        print("无异常执行else")
        return i
    finally:
        i = 3
        print("不管代码是否有问题均执行finally")
        if x == 4:
            return i


# 正常执行
print("→", division(1))
# 不管代码是否有问题均执行finally
# → 1

print("→", division(2))
# 无异常执行else
# 不管代码是否有问题均执行finally
# → 2
# 重点看这个i的变化和输出值

print("→", division(3))
#
# 不管代码是否有问题均执行finally
# → 0

print("→", division(4))
# 无异常执行else
# 不管代码是否有问题均执行finally
# → 3

注:

  1. try-except各个子块下变量在同一个命名空间

    # 报错
    i = 0
    def func():
        i += 2
        print(i)
    func()
    
    # 不报错
    try:
        i = 0
    except Exception():
        ...
    else:
        i += 1
    finally:
        i += 1
    print(i)
    

内置异常层次结构

exception-hierarchy,内置异常即builtins中的异常

BaseException                              异常基类
 ├── BaseExceptionGroup                    异常组基类
 ├── GeneratorExit                         生成器退出
 ├── KeyboardInterrupt                     键盘中断(通常是输入^C)
 ├── SystemExit                            解释器退出
 └── Exception                             一般异常基类
      ├── ArithmeticError                  计算错误基类
      │    ├── FloatingPointError          浮点错误
      │    ├── OverflowError               溢出错误,数值计算超出表示范围
      │    └── ZeroDivisionError           除零错误
      ├── AssertionError                   断言错误,断言语句断言失败
      ├── AttributeError                   属性错误,访问对象没有的属性
      ├── BufferError                      缓冲区错误
      ├── EOFError                         EOF错误
      ├── ExceptionGroup [BaseExceptionGroup]
      ├── ImportError                      导入错误
      │    └── ModuleNotFoundError         模块找不到错误
      ├── LookupError                      查找错误,没访问到数据
      │    ├── IndexError                  索引错误,序列中没有该index
      │    └── KeyError                    键错误,字典中没有该key
      ├── MemoryError                      内存错误,内存溢出
      ├── NameError                        名称错误,标识符未声明
      │    └── UnboundLocalError           未绑定的本地变量
      ├── OSError                          操作系统错误
      │    ├── BlockingIOError             阻塞IO错误
      │    ├── ChildProcessError           子进程错误
      │    ├── ConnectionError             连接错误
      │    │    ├── BrokenPipeError        
      │    │    ├── ConnectionAbortedError 连接中止错误
      │    │    ├── ConnectionRefusedError 连接拒绝错误
      │    │    └── ConnectionResetError   连接重置错误
      │    ├── FileExistsError             文件已存在错误
      │    ├── FileNotFoundError           文件找不到错误
      │    ├── InterruptedError            中断错误
      │    ├── IsADirectoryError           是一个文件夹错误
      │    ├── NotADirectoryError          不是一个文件夹错误
      │    ├── PermissionError             权限错误
      │    ├── ProcessLookupError          进程查找错误
      │    └── TimeoutError                超时错误
      ├── ReferenceError                   引用错误,弱引用访问已经被GC的对象
      ├── RuntimeError                     运行时错误
      │    ├── NotImplementedError         未实现错误,方法未实现
      │    └── RecursionError              递归错误
      ├── StopAsyncIteration               停止异步迭代
      ├── StopIteration                    停止迭代
      ├── SyntaxError                      语法错误
      │    └── IndentationError            缩进错误
      │         └── TabError               Tab错误,与space混用
      ├── SystemError                      系统错误
      ├── TypeError                        类型错误
      ├── ValueError                       值错误
      │    └── UnicodeError                Unicode错误
      │         ├── UnicodeDecodeError     Unicode解码错误
      │         ├── UnicodeEncodeError     Unicode编码错误
      │         └── UnicodeTranslateError  Unicode转换错误
      └── Warning                          警告基类
           ├── BytesWarning	               bytes和bytearray相关警告的基类
           ├── DeprecationWarning          弃用警告
           ├── EncodingWarning             编码警告
           ├── FutureWarning               未来警告,未来版本中可能会发生变化
           ├── ImportWarning               导入警告
           ├── PendingDeprecationWarning   即将弃用警告
           ├── ResourceWarning             资源警告
           ├── RuntimeWarning              运行时警告
           ├── SyntaxWarning               语法警告
           ├── UnicodeWarning              Unicode警告
           └── UserWarning                 用户警告

BaseException 为异常基类,通常情况下在自定义异常或希望捕获全部异常的情况下是使用一般异常基类Exception而非BaseException。在设计上,Exception作为一般异常基类,其同级异常都有专门用途,异常组基类BaseExceptionGroup用于构建异常组,生成器退出GeneratorExit用于在生成器退出时抛出,解释器本身捕获并处理该异常以使得生成器功能完整,键盘中断KeyboardInterrupt和解释器退出SystemExit都用于退出解释器,被捕获后若不二次抛出就无法退出解释器,与其原本目的不符。

关于生成器 GeneratorExit,发生在如下情况:

  1. 显式关闭:当调用生成器的 close() 方法时。
  2. 迭代结束:当生成器的所有值都被迭代完毕后,迭代器的 __next__() 方法会抛出 StopIteration 异常,这会触发生成器的 close() 方法,间接导致 GeneratorExit 被抛出。
  3. 异常传播:如果生成器在执行过程中遇到了异常,并且这个异常没有在生成器内部被捕获处理,那么异常会向上传播,最终可能触发生成器的 close() 方法。

BaseException

class BaseException(object):
    """ Common base class for all exceptions """

    def add_note(self, note):  # real signature unknown; restored from __doc__
        """
        Exception.add_note(note) --
            add a note to the exception
        """
        pass

    def with_traceback(self, tb):  # real signature unknown; restored from __doc__
        """
        Exception.with_traceback(tb) --
            set self.__traceback__ to tb and return self.
        """
        pass

    def __delattr__(self, *args, **kwargs):  # real signature unknown
        """ Implement delattr(self, name). """
        pass

    def __getattribute__(self, *args, **kwargs):  # real signature unknown
        """ Return getattr(self, name). """
        pass

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass

    def __reduce__(self, *args, **kwargs):  # real signature unknown
        pass

    def __repr__(self, *args, **kwargs):  # real signature unknown
        """ Return repr(self). """
        pass

    def __setattr__(self, *args, **kwargs):  # real signature unknown
        """ Implement setattr(self, name, value). """
        pass

    def __setstate__(self, *args, **kwargs):  # real signature unknown
        pass

    def __str__(self, *args, **kwargs):  # real signature unknown
        """ Return str(self). """
        pass

    args = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

    __cause__ = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception cause"""

    __context__ = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception context"""

    __suppress_context__ = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

    __traceback__ = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

    __dict__ = None  # (!) real value is "mappingproxy({'__new__': <built-in method __new__ of type object at 0x00007FF9479126B0>, '__repr__': <slot wrapper '__repr__' of 'BaseException' objects>, '__str__': <slot wrapper '__str__' of 'BaseException' objects>, '__getattribute__': <slot wrapper '__getattribute__' of 'BaseException' objects>, '__setattr__': <slot wrapper '__setattr__' of 'BaseException' objects>, '__delattr__': <slot wrapper '__delattr__' of 'BaseException' objects>, '__init__': <slot wrapper '__init__' of 'BaseException' objects>, '__reduce__': <method '__reduce__' of 'BaseException' objects>, '__setstate__': <method '__setstate__' of 'BaseException' objects>, 'with_traceback': <method 'with_traceback' of 'BaseException' objects>, 'add_note': <method 'add_note' of 'BaseException' objects>, '__suppress_context__': <member '__suppress_context__' of 'BaseException' objects>, '__dict__': <attribute '__dict__' of 'BaseException' objects>, 'args': <attribute 'args' of 'BaseException' objects>, '__traceback__': <attribute '__traceback__' of 'BaseException' objects>, '__context__': <attribute '__context__' of 'BaseException' objects>, '__cause__': <attribute '__cause__' of 'BaseException' objects>, '__doc__': 'Common base class for all exceptions'})"
class Exception(BaseException):
    """ Common base class for all non-exit exceptions. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class BaseExceptionGroup(BaseException):
    """ A combination of multiple unrelated exceptions. """

    def derive(self, *args, **kwargs):  # real signature unknown
        pass

    def split(self, *args, **kwargs):  # real signature unknown
        pass

    def subgroup(self, *args, **kwargs):  # real signature unknown
        pass

    def __class_getitem__(self, *args, **kwargs):  # real signature unknown
        """ See PEP 585 """
        pass

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass

    def __str__(self, *args, **kwargs):  # real signature unknown
        """ Return str(self). """
        pass

    exceptions = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """nested exceptions"""

    message = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception message"""



class GeneratorExit(BaseException):
    """ Request that a generator exit. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass



class KeyboardInterrupt(BaseException):
    """ Program interrupted by user. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass



class ExceptionGroup(BaseExceptionGroup, Exception):
    # no doc
    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    __weakref__ = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """list of weak references to the object (if defined)"""
class ArithmeticError(Exception):
    """ Base class for arithmetic errors. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class FloatingPointError(ArithmeticError):
    """ Floating point operation failed. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class OverflowError(ArithmeticError):
    """ Result too large to be represented. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class ZeroDivisionError(ArithmeticError):
    """ Second argument to a division or modulo operation was zero. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class AssertionError(Exception):
    """ Assertion failed. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class AttributeError(Exception):
    """ Attribute not found. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    def __str__(self, *args, **kwargs):  # real signature unknown
        """ Return str(self). """
        pass

    name = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """attribute name"""

    obj = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """object"""


class WindowsError(Exception):
    """ Base class for I/O related errors. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass

    def __reduce__(self, *args, **kwargs):  # real signature unknown
        pass

    def __str__(self, *args, **kwargs):  # real signature unknown
        """ Return str(self). """
        pass

    characters_written = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

    errno = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """POSIX exception code"""

    filename = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception filename"""

    filename2 = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """second exception filename"""

    strerror = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception strerror"""

    winerror = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """Win32 exception code"""


OSError = WindowsError
IOError = WindowsError
EnvironmentError = WindowsError


class BlockingIOError(OSError):
    """ I/O operation would block. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass


class ConnectionError(OSError):
    """ Connection error. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass


class BrokenPipeError(ConnectionError):
    """ Broken pipe. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass


class ChildProcessError(OSError):
    """ Child process error. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass


class ConnectionAbortedError(ConnectionError):
    """ Connection aborted. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass


class ConnectionRefusedError(ConnectionError):
    """ Connection refused. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass


class ConnectionResetError(ConnectionError):
    """ Connection reset. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass


class FileExistsError(OSError):
    """ File already exists. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass


class FileNotFoundError(OSError):
    """ File not found. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass


class InterruptedError(OSError):
    """ Interrupted by signal. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass


class IsADirectoryError(OSError):
    """ Operation doesn't work on directories. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass


class NotADirectoryError(OSError):
    """ Operation only works on directories. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass


class PermissionError(OSError):
    """ Not enough permissions. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass


class ProcessLookupError(OSError):
    """ Process not found. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass


class TimeoutError(OSError):
    """ Timeout expired. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass


class BufferError(Exception):
    """ Buffer error. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class Warning(Exception):
    """ Base class for warning categories. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class BytesWarning(Warning):
    """
    Base class for warnings about bytes and buffer related problems, mostly
    related to conversion from str or comparing to str.
    """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class DeprecationWarning(Warning):
    """ Base class for warnings about deprecated features. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class EncodingWarning(Warning):
    """ Base class for warnings about encodings. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class FutureWarning(Warning):
    """
    Base class for warnings about constructs that will change semantically
    in the future.
    """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class ImportWarning(Warning):
    """ Base class for warnings about probable mistakes in module imports """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class PendingDeprecationWarning(Warning):
    """
    Base class for warnings about features which will be deprecated
    in the future.
    """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class ResourceWarning(Warning):
    """ Base class for warnings about resource usage. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class RuntimeWarning(Warning):
    """ Base class for warnings about dubious runtime behavior. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class SyntaxWarning(Warning):
    """ Base class for warnings about dubious syntax. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class UnicodeWarning(Warning):
    """
    Base class for warnings about Unicode related problems, mostly
    related to conversion problems.
    """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class UserWarning(Warning):
    """ Base class for warnings generated by user code. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class EOFError(Exception):
    """ Read beyond end of file. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class ImportError(Exception):
    """ Import can't find module, or can't find name in module. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    def __reduce__(self, *args, **kwargs):  # real signature unknown
        pass

    def __str__(self, *args, **kwargs):  # real signature unknown
        """ Return str(self). """
        pass

    msg = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception message"""

    name = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """module name"""

    path = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """module path"""


class ModuleNotFoundError(ImportError):
    """ Module not found. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass


class SyntaxError(Exception):
    """ Invalid syntax. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    def __str__(self, *args, **kwargs):  # real signature unknown
        """ Return str(self). """
        pass

    end_lineno = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception end lineno"""

    end_offset = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception end offset"""

    filename = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception filename"""

    lineno = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception lineno"""

    msg = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception msg"""

    offset = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception offset"""

    print_file_and_line = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception print_file_and_line"""

    text = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception text"""


class IndentationError(SyntaxError):
    """ Improper indentation. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass


class TabError(IndentationError):
    """ Improper mixture of spaces and tabs. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass


class LookupError(Exception):
    """ Base class for lookup errors. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class IndexError(LookupError):
    """ Sequence index out of range. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class KeyError(LookupError):
    """ Mapping key not found. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    def __str__(self, *args, **kwargs):  # real signature unknown
        """ Return str(self). """
        pass


class MemoryError(Exception):
    """ Out of memory. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class NameError(Exception):
    """ Name not found globally. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    def __str__(self, *args, **kwargs):  # real signature unknown
        """ Return str(self). """
        pass

    name = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """name"""


class UnboundLocalError(NameError):
    """ Local name referenced but not bound to a value. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass


class RuntimeError(Exception):
    """ Unspecified run-time error. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class NotImplementedError(RuntimeError):
    """ Method or function hasn't been implemented yet. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class RecursionError(RuntimeError):
    """ Recursion limit exceeded. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class ReferenceError(Exception):
    """ Weak ref proxy used after referent went away. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class StopAsyncIteration(Exception):
    """ Signal the end from iterator.__anext__(). """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class StopIteration(Exception):
    """ Signal the end from iterator.__next__(). """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    value = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """generator return value"""


class SystemError(Exception):
    """
    Internal error in the Python interpreter.

    Please report this to the Python maintainer, along with the traceback,
    the Python version, and the hardware/OS platform and version.
    """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class TypeError(Exception):
    """ Inappropriate argument type. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class ValueError(Exception):
    """ Inappropriate argument value (of correct type). """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class UnicodeError(ValueError):
    """ Unicode related error. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass


class UnicodeDecodeError(UnicodeError):
    """ Unicode decoding error. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass

    def __str__(self, *args, **kwargs):  # real signature unknown
        """ Return str(self). """
        pass

    encoding = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception encoding"""

    end = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception end"""

    object = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception object"""

    reason = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception reason"""

    start = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception start"""


class UnicodeEncodeError(UnicodeError):
    """ Unicode encoding error. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass

    def __str__(self, *args, **kwargs):  # real signature unknown
        """ Return str(self). """
        pass

    encoding = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception encoding"""

    end = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception end"""

    object = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception object"""

    reason = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception reason"""

    start = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception start"""


class UnicodeTranslateError(UnicodeError):
    """ Unicode translation error. """

    def __init__(self, *args, **kwargs):  # real signature unknown
        pass

    @staticmethod  # known case of __new__
    def __new__(*args, **kwargs):  # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass

    def __str__(self, *args, **kwargs):  # real signature unknown
        """ Return str(self). """
        pass

    encoding = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception encoding"""

    end = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception end"""

    object = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception object"""

    reason = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception reason"""

    start = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception start"""

异常栈

获取异常的traceback

print(Exception("xxx").__traceback__)

异常traceback

class MyException(Exception):
    pass


def func6():
    return 1 / 0


def func5():
    func6()


def func4():
    func5()


def func3():
    try:
        func4()
    except Exception as exception:
        ...
        raise exception


def func2():
    func3()


def func1():
    func2()


func1()

# Traceback (most recent call last):
#   File "E:\python\pyBaseCode\demo.py", line 33, in <module>
#     func1()
#   File "E:\python\pyBaseCode\demo.py", line 30, in func1
#     func2()
#   File "E:\python\pyBaseCode\demo.py", line 26, in func2
#     func3()
#   File "E:\python\pyBaseCode\demo.py", line 22, in func3
#     raise exception
#   File "E:\python\pyBaseCode\demo.py", line 19, in func3
#     func4()
#   File "E:\python\pyBaseCode\demo.py", line 14, in func4
#     func5()
#   File "E:\python\pyBaseCode\demo.py", line 10, in func5
#     func6()
#   File "E:\python\pyBaseCode\demo.py", line 6, in func6
#     return 1 / 0
#            ~~^~~
# ZeroDivisionError: division by zero

https://docs.python.org/3/library/traceback.html

import sys
import traceback

try:
    1 / 0
except Exception as e:
    exc_type, exc_value, exc_traceback = sys.exc_info()
    print(f"{exc_type=} {exc_value=} {exc_traceback=}")

    traceback.print_exc()
    # traceback封装了sys.exc_info()

    traceback.print_tb(exc_traceback)
    # traceback.print_tb(tb, limit=None, file=None)
    # tb traceback object,可以由sys.exc_info获取到
    # limit traceback层级限制,None为不限制返回所有层级
    # file    if file is None:
    #           file = sys.stderr
    #         for item in StackSummary.from_list(extracted_list).format():
    #           print(item, file=file, end="")
    
    traceback.print_exception(exc_type, exc_value, exc_traceback, limit=None, file=sys.stdout)
    # print_exception(exc, /, value=_sentinel, tb=_sentinel, limit=None, file=None, chain=True)
    # 前三个参数正好是sys.exc_info()返回的三个值

    traceback.format_exc()

上下文管理器处理异常

对上下文管理器本身出现问题不会处理,只处理包裹代码部分

 class Context:
     def __init__(self):
         ...
 
     def __enter__(self):
         1 / 0
         ...
 
     def __exit__(self, exc_type, exc_val, exc_tb):
         # 1 / 0
         return True
 
 
 with Context():
     ...
 # Process finished with exit code 1

对返回值进行逻辑判断,真则表示无需将可能有的异常抛出,假则表示需要将可能有的异常抛出

 class Context:
     def __init__(self):
         ...
 
     def __enter__(self):
         ...
 
     def __exit__(self, exc_type, exc_val, exc_tb):
         # Process finished with exit code 0
         # 0 False [] ......
         # "0" 1 True
         return "0"
 
 
 with Context():
     1 / 0

ExitStack

嵌套多层上下文管理器

import abc
import os
import random
import sys
import _collections_abc
from collections import deque
from functools import wraps
from types import MethodType, GenericAlias


class AbstractContextManager(abc.ABC):
    """
    上下文管理器的一个抽象基类
    """

    __class_getitem__ = classmethod(GenericAlias)

    def __enter__(self):
        return self

    @abc.abstractmethod
    def __exit__(self, exc_type, exc_value, traceback):
        return None

    @classmethod
    def __subclasshook__(cls, C):
        if cls is AbstractContextManager:
            return _collections_abc._check_methods(C, "__enter__", "__exit__")
        return NotImplemented


class _BaseExitStack:
    """A base class for ExitStack and AsyncExitStack."""

    @staticmethod
    def _create_exit_wrapper(cm, cm_exit):
        """
        使用 MethodType 函数来将 cm_exit 方法绑定到 cm 对象上
        MethodType 是一个内置函数,它接收两个参数:一个方法和一个对象,然后返回一个绑定到该对象的方法。这意味着返回的方法在被调用时,self 参数将指向 cm 对象

        cm_exit 是要绑定的cm的__exit__方法,其中 __exit__ 的参数为 self 和 各种异常信息
        cm 是要绑定的对象,即上下文管理器对象本身
        """
        return MethodType(cm_exit, cm)

    @staticmethod
    def _create_cb_wrapper(callback, /, *args, **kwds):
        def _exit_wrapper(exc_type, exc, tb):
            callback(*args, **kwds)
        return _exit_wrapper

    def __init__(self):
        """
        deque 保存 经过包装后的 __exit__ 方法
        """
        self._exit_callbacks = deque()

    def pop_all(self):
        """Preserve the context stack by transferring it to a new instance."""
        new_stack = type(self)()
        new_stack._exit_callbacks = self._exit_callbacks
        self._exit_callbacks = deque()
        return new_stack

    def push(self, exit):
        """
        使用标准的__exit__方法签名注册回调。
        可以像__exit__方法一样抑制异常。还接受具有__exit__方法的任何对象(注册对该方法的调用,而不是对象本身)。
        """
        # We use an unbound method rather than a bound method to follow
        # the standard lookup behaviour for special methods.
        _cb_type = type(exit)

        try:
            exit_method = _cb_type.__exit__
        except AttributeError:
            # Not a context manager, so assume it's a callable.
            self._push_exit_callback(exit)
        else:
            self._push_cm_exit(exit, exit_method)
        return exit  # Allow use as a decorator.

    def enter_context(self, cm):
        """
        1. 获取给定上下文管理器的  __enter__ 和 __exit__ 方法
        2. 调用 __enter__ 并返回结果
        3. 将 __exit__ 作为 callback 方法 push 入队列
        """
        cls = type(cm)
        try:
            _enter = cls.__enter__
            _exit = cls.__exit__
        except AttributeError:
            raise TypeError(f"'{cls.__module__}.{cls.__qualname__}' object does "
                            f"not support the context manager protocol") from None
        result = _enter(cm)
        self._push_cm_exit(cm, _exit)
        return result

    def callback(self, callback, /, *args, **kwds):
        """
        注册支持任意参数的回调方法,不能像 __exit__ 方法一样压制异常
        """
        _exit_wrapper = self._create_cb_wrapper(callback, *args, **kwds)

        # We changed the signature, so using @wraps is not appropriate, but
        # setting __wrapped__ may still help with introspection.
        _exit_wrapper.__wrapped__ = callback
        self._push_exit_callback(_exit_wrapper)
        return callback  # Allow use as a decorator

    def _push_cm_exit(self, cm, cm_exit):
        """
        1. 包装 __exit__ 方法
        2. 入队列
        """
        _exit_wrapper = self._create_exit_wrapper(cm, cm_exit)
        self._push_exit_callback(_exit_wrapper, True)

    def _push_exit_callback(self, callback, is_sync=True):
        """
        包装后的方法入队列
        """
        self._exit_callbacks.append((is_sync, callback))


# Inspired by discussions on http://bugs.python.org/issue13585
class ExitStack(_BaseExitStack, AbstractContextManager):
    """
    用于动态管理退出回调堆栈的上下文管理器
    """

    """
    For example:
        with ExitStack() as stack:
            files = [stack.enter_context(open(fname)) for fname in filenames]
            # All opened files will automatically be closed at the end of
            # the with statement, even if attempts to open files later
            # in the list raise an exception.
    """

    def __enter__(self):
        return self

    def __exit__(self, *exc_details):
        received_exc = exc_details[0] is not None

        # We manipulate the exception state so it behaves as though
        # we were actually nesting multiple with statements
        frame_exc = sys.exc_info()[1]
        def _fix_exception_context(new_exc, old_exc):
            # Context may not be correct, so find the end of the chain
            while 1:
                exc_context = new_exc.__context__
                if exc_context is None or exc_context is old_exc:
                    # Context is already set correctly (see issue 20317)
                    return
                if exc_context is frame_exc:
                    break
                new_exc = exc_context
            # Change the end of the chain to point to the exception
            # we expect it to reference
            new_exc.__context__ = old_exc


        # 回调函数以先进后出顺序调用,模拟嵌套上下文管理器
        suppressed_exc = False
        pending_raise = False
        while self._exit_callbacks:
            # 弹出一个上下文管理器
            is_sync, cb = self._exit_callbacks.pop()
            assert is_sync
            try:
                # 执行回调,若该回调返回值为真,则压制异常不抛出
                if cb(*exc_details):
                    suppressed_exc = True
                    pending_raise = False
                    exc_details = (None, None, None)
            except:
                # 执行回调时异常,pending_raise = True 准备抛出
                new_exc_details = sys.exc_info()
                # simulate the stack of exceptions by setting the context
                _fix_exception_context(new_exc_details[1], exc_details[1])
                pending_raise = True
                exc_details = new_exc_details
        if pending_raise:
            try:
                # bare "raise exc_details[1]" replaces our carefully
                # set-up context
                fixed_ctx = exc_details[1].__context__
                raise exc_details[1]
            except BaseException:
                exc_details[1].__context__ = fixed_ctx
                raise
        return received_exc and suppressed_exc

    def close(self):
        """Immediately unwind the context stack."""
        self.__exit__(None, None, None)

if __name__ == '__main__':
    with ExitStack() as exit_stack:
        exit_stack.enter_context(open(str(random.Random().random()), "w+"))
        raise Exception("123")
f = (open("123", "w+"), open("456", "w+"), open("789", "w+"))

with f:
    ...
from contextlib import ExitStack

with ExitStack() as stack:
    for i in f:
        stack.enter_context(i)

deprecated

import warnings
import functools


def deprecated(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        warnings.warn(f"{func.__name__} is deprecated. Use the new function instead.", DeprecationWarning, stacklevel=2)
        return func(*args, **kwargs)

    return wrapper


# 使用装饰器标记已弃用的函数
@deprecated
def old_function():
    # 旧的功能实现
    return "Old function"


def new_function():
    # 新的功能实现
    return "New function"


# 调用已弃用的函数
result_old = old_function()

# 调用新的函数
result_new = new_function()

print(result_old)  # 输出警告信息并执行旧函数
print(result_new)  # 执行新函数