如何根据调用者为警告分配堆栈级别?

时间:2019-01-28 10:00:40

标签: python python-3.x constructor warnings

我有一个Python类,它在__init__()内发出警告。它还提供了用于打开和读取文件的工厂类方法:

from warnings import warn

class MyWarning(Warning):
    """Warning issued when an invalid name is found."""
    pass

class MyClass:
    def __init__(self, names):
        # Simplified; actual code is longer
        if is_invalid(names):
            names = fix_names(names)
            warn(f'{names!r} contains invalid element(s)',
                MyWarning, stacklevel=2)
        self._names = names

    @classmethod
    def from_file(cls, filename):
        with open(filename) as file:
            names = extract_names(file)
        return cls(names)

stacklevel=2使警告指向对MyClass()的调用,而不是warn()语句本身。当用户代码直接实例化MyClass时,此方法有效。但是,当MyClass.from_file()发出警告时,MyWarning指向return cls(names),而不是用户代码调用from_file()

如何确保工厂方法也发出指向调用方的警告?我考虑过的一些选择:

  1. _stacklevel添加一个“隐藏” __init__()参数,并在_stacklevel=2内使用from_file()实例化MyClass。
    • 这很丑陋,并且向API公开了内部行为。
  2. 添加一个“隐藏的” _stacklevel类属性,并在__init__()内部访问它。然后在from_file()中临时修改此属性
    • 也很丑。
  3. 添加一个_set_names()方法来检查/修复名称并在需要时发出警告。然后在构造函数中调用此方法。对于from_file(),首先用空参数实例化MyClass,然后直接调用_set_names()以确保MyWarning指向调用者。
    • 仍然很hacky,并且在调用_set_names()时有效地两次调用from_file()
  4. 捕获并重新引发警告,类似于异常链接。
    • 听起来不错,但我不知道该怎么做。

我阅读了warning module docs,但是它在安全地捕获和重新抛出警告方面没有什么帮助。使用warnings.simplefilter()将警告转换为异常会中断MyClass()并迫使我再次调用它。

0 个答案:

没有答案