我有一个函数应该生成所有内置异常的元组(用于except (Exception1, Exception2, etc...) as error:
形式),当我正常运行时,它工作得很好。
def get_exceptions():
exceptionList = []
for item in dir(__builtins__):
if item.find('Error') != -1:
exec('exceptionList.append({})'.format(item))
return tuple(exceptionList)
if __name__ == '__main__':
print(get_exceptions())
并在运行时:
(<class 'ArithmeticError'>, <class 'AssertionError'>, <class 'AttributeError'>, <class 'BlockingIOError'>, <class 'BrokenPipeError'>, <class 'BufferError'>, <class 'ChildProcessError'>, <class 'ConnectionAbortedError'>, <class 'ConnectionError'>, <class 'ConnectionRefusedError'>, <class 'ConnectionResetError'>, <class 'EOFError'>, <class 'OSError'>, <class 'FileExistsError'>, <class 'FileNotFoundError'>, <class 'FloatingPointError'>, <class 'OSError'>, <class 'ImportError'>, <class 'IndentationError'>, <class 'IndexError'>, <class 'InterruptedError'>, <class 'IsADirectoryError'>, <class 'KeyError'>, <class 'LookupError'>, <class 'MemoryError'>, <class 'NameError'>, <class 'NotADirectoryError'>, <class 'NotImplementedError'>, <class 'OSError'>, <class 'OverflowError'>, <class 'PermissionError'>, <class 'ProcessLookupError'>, <class 'ReferenceError'>, <class 'RuntimeError'>, <class 'SyntaxError'>, <class 'SystemError'>, <class 'TabError'>, <class 'TimeoutError'>, <class 'TypeError'>, <class 'UnboundLocalError'>, <class 'UnicodeDecodeError'>, <class 'UnicodeEncodeError'>, <class 'UnicodeError'>, <class 'UnicodeTranslateError'>, <class 'ValueError'>, <class 'OSError'>, <class 'ZeroDivisionError'>)
这就是我想要的。但是,在下面,通过shell,
>>> import list_exceptions
>>> list_exceptions.get_exceptions()
()
什么都没发生。
即使在文件中:
import list_exceptions
print(list_exceptions.get_exceptions())
我得到:
()
这看起来很奇怪。任何帮助都会很棒!顺便说一下,我看着这些,它们与我的想法并没有太大关系。 import fails when running python as script, but not in iPython? http://python-notes.curiousefficiency.org/en/latest/python_concepts/import_traps.html
如果你有问题,就问吧 :)
你的方法的根本问题在于你依赖于两件你不应该依赖的东西。第一个是dir
,其行为不应该依赖,因为它主要用于帮助交互式shell中的调试。来自docs:
如果对象不提供
__dir__()
,则该函数会尽力从对象的__dict__
属性(如果已定义)和其类型对象中收集信息。结果列表不一定完整,并且当对象具有自定义__getattr__()
时可能不准确。...
注意因为
dir()
主要是为了方便在交互式提示中使用而提供的,所以它试图提供一组有趣的名称,而不是尝试提供严格或一致定义的名称集,并且其详细行为可能会在不同版本之间发生变化。例如,当参数是类时,元类属性不在结果列表中。
此外,您使用__builtins__
变量,这是一个实现细节,再次来自docs:
作为一个实现细节,大多数模块都将名称
__builtins__
作为其全局变量的一部分提供。__builtins__
的值通常是此模块或此模块的__dict__
属性的值。由于这是一个实现细节,因此Python的替代实现可能不会使用它。
从本质上讲,你依赖于两个不可靠的东西。请注意,在您的情况下实际发生的是,当您直接运行模块时,它会返回实际的builtins
模块,但是,在导入模块时,__builtins__
包含“此模块的值为__dict__
”。一些调试打印可能会照亮这个:
# builtinstest.py
def get_exceptions():
print(type(__builtins__))
print(dir(__builtins__))
从交互式翻译:
>>> import builtinstest
>>> builtinstest.get_exceptions()
<class 'dict'>
['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
因此,当您在dir
对象上调用dict
时,它只返回从dict-object内省的属性,例如: copy
,fromkeys
,get
,items
和所有其他dict
方法。解决方案是使用builtins
模块并且不使用dir
,使用vars
(它只返回__dict__
属性),因为您需要模块对象的属性。
最后,你使用exec
的方法并不好。如果你想要这样做,请检查它是否是BaseException
的子类,它是所有内置异常的父类,所以来自the docs:
例外
BaseException
所有内置异常的基类。它并不意味着由用户定义的类直接继承(为此,使用
Exception
)。
所以类似于:
import builtins
def get_exceptions_sanely():
exception_list = []
for obj in vars(builtins).values():
if isinstance(obj, type) and issubclass(obj, BaseException):
exception_list.append(obj)
return tuple(exception_list)
你正在努力实现的目标。请注意,这会直接迭代值,因此您最终不会使用像eval
或exec
这样的东西,在这种情况下这是滥用。请注意,这会捕获每个内置异常,例如警告(例如BytesWarning
)和更多深奥的东西,如SystemExit
。
仅仅因为你可以这样做,并不意味着你应该这样做。您声明的目的是:
我有一个函数应该生成所有内置异常的元组,(用于
except (Exception1, Exception2, etc...) as error:
形式)
好吧,你可以使用except BaseException as error
而不是通过首先找到那些例外的琐事(事实上,except <something>
基本上检查<something>
issubclass
是否有任何错误被提出。从根本上说,很少有任何理由有这样的错误。一个广泛的except
条款。你应该尽可能地抓住一个尽可能狭窄的例外。
这是有效的,似乎是获取内置模块的常用技术。
def get_exceptions():
exceptionList = []
for k in __builtins__.keys():
if k.find('Error') != -1:
exec('exceptionList.append({})'.format(k))
return tuple(exceptionList)
if __name__ == '__main__':
print(get_exceptions())