在python嵌套尝试/除了块是一个很好的编程习惯?
我正在写我自己的容器,它需要通过属性调用来访问字典。 容器的典型用法是这样的:
temp_container = DictContainer() dict_container['foo'] = bar ... print dict_container.foo
我知道写这样的东西可能是愚蠢的,但这是我需要提供的function。 我正在考虑通过以下方式来实现这一点:
def __getattribute__(self, item): try: return object.__getattribute__(item) except AttributeError: try: return self.dict[item] except KeyError: print "The object doesn't have such attribute"
我不确定嵌套try / except块是否是一个好习惯,所以另一种方法是使用hasattr()
和has_key()
:
def __getattribute__(self, item): if hasattr(self, item): return object.__getattribute__(item) else: if self.dict.has_key(item): return self.dict[item] else: raise AttributeError("some customised error")
或者使用其中之一,并尝试像这样catch块:
def __getattribute__(self, item): if hasattr(self, item): return object.__getattribute__(item) else: try: return self.dict[item] except KeyError: raise AttributeError("some customised error")
哪个选项是最pythonic和优雅?
你的第一个例子非常好。 即使是官方的Python文档也推荐这种称为EAFP的风格。
就个人而言,我更喜欢在没有必要时避免嵌套:
def __getattribute__(self, item): try: return object.__getattribute__(item) except AttributeError: pass # fallback to dict try: return self.dict[item] except KeyError: raise AttributeError("The object doesn't have such attribute") from None
PS。 has_key()
在Python 2中已经被弃用了很长一段时间,而是item in self.dict
使用item in self.dict
。
在Java中,使用exception进行stream程控制确实是一个不好的做法(主要是因为exception会强制jvm收集资源( 在这里更多 )),在Python中,有两个重要的原则: Duck Typing和EAFP 。 这基本上意味着你被鼓励按照你认为可以工作的方式尝试使用一个对象,并在事情不是这样的时候处理。
总之,唯一的问题是你的代码太多缩进了。 如果你觉得这样,试着简化一些像lqcbuild议的嵌套
在我看来,这将是Pythonic处理这个问题的最好办法,尽pipe这是因为这会让你的问题变得毫无意义。 请注意,这个定义__getattr__()
而不是__getattribute__()
因为这样做意味着它只需要处理保存在内部字典中的“特殊”属性。
def __getattr__(self, name): """only called when an attribute lookup in the usual places has failed""" try: return self.my_dict[name] except KeyError: raise AttributeError("some customized error message")
对于你的具体例子,你实际上并不需要嵌套它们。 如果try
块中的expression式成功,函数将返回,所以只有在第一次尝试失败时才会运行整个try / except块后面的任何代码。 所以你可以做:
def __getattribute__(self, item): try: return object.__getattribute__(item) except AttributeError: pass # execution only reaches here when try block raised AttributeError try: return self.dict[item] except KeyError: print "The object doesn't have such attribute"
嵌套它们并不坏,但是我想让它保持平坦使得结构更加清晰:你在顺序地尝试一系列的东西,并返回第一个工作的东西。
顺便说一句,你可能想要考虑一下,是否真的想在这里使用__getattribute__
而不是__getattr__
。 使用__getattr__
会简化一些事情,因为你会知道正常的属性查找过程已经失败了。
在Python中,请求原谅比允许要容易。 不要出汗嵌套的exception处理。
(此外,反正总是使用封面下的例外。)
我想避免的一件事是在处理一个旧的例外时引发一个新的例外。 它使错误消息混淆阅读。
例如,在我的代码中,我最初写道
try: return tuple.__getitem__(self, i)(key) except IndexError: raise KeyError(key)
我收到了这个消息。
>>> During handling of above exception, another exception occurred.
我想要的是这样的:
try: return tuple.__getitem__(self, i)(key) except IndexError: pass raise KeyError(key)
它不会影响如何处理exception。 在任何一个代码块中,KeyError都会被捕获。 这只是获得风格点的问题。
我不认为这是一个pythonic或优雅的问题。 这是一个尽可能防止exception的问题。 例外是为了处理可能发生在你无法控制的代码或事件中的错误。 在这种情况下,当检查项目是属性还是字典时,您可以完全控制,所以避免嵌套exception并坚持第二次尝试。
根据文档 ,最好通过元组来处理多个exception,比如:
import sys try: f = open('myfile.txt') s = f.readline() i = int(s.strip()) except IOError as e: print "I/O error({0}): {1}".format(e.errno, e.strerror) except ValueError: print "Could not convert data to an integer." except: print "Unexpected error:", sys.exc_info()[0] raise