考虑 Python 中用于getattr
动态获取方法或值的情况。
def message(obj, msg, *args, **kwargs):
result = getattr(obj, msg, None)
if result is not None:
try:
return result(*args, **kwargs)
except TypeError:
return result
...只是,等等——这不是很好的行为。即使这是一个错误的getattr
调用,无论如何都会隐式返回 None —— 对于这种函数来说,这不一定是很好的行为。
为了确定一个可靠的“相信我,你不想返回这个”值,面对没有好的和体面的哨兵(无论如何我都知道),我考虑将默认值设置为getattr
一个引发例外。通过这种方式,错误的搜索应该总是很明显并被抓住,除非“其他人”决定变得可爱并让这个无用的哨兵成为一个属性。
class _BadMessageException(Exception):
pass
def _did_not_find(*args, **kwargs):
raise BadMessageException
def _raise_right_exception(msg, obj):
if not isinstance(msg, basestring):
raise TypeError("Message '{}' was not a string".format(msg))
else:
raise AttributeError("Bad message '{}' sent to object '{}'".format(msg, obj))
通过这种方式,当消息返回 None 时,它总是至少处于 up-and-up 状态,因为它在您要求它查看的地方找到了一个 None。然后它还会引发您期望的异常:没有此类方法/ivar的对象的AttributeError,传递的参数过多的TypeError等。编辑:自然,我第一次发布了错误的代码片段。这是更正后的功能。
def message(obj, msg, *args, **kwargs):
result = getattr(obj, msg, _did_not_find)
try:
return result(*args, **kwargs)
except TypeError:
if not args or kwargs:
return result
else:
_raise_right_exception(msg, obj)
except _BadMessageException:
_raise_right_exception(msg, obj)
感觉就像很多额外的代码只是为了确保它以正确的方式失败。一个引发异常的函数,这只是一个 McGuffin 引发首选异常,只是为了安抚eafp
半神...... Hrrm。
是否有更简单的语法来声明有效的“失败”标记,无论是在这种情况下还是在返回值未知或无法保证的其他情况下?