鸭子类型与使用hasattr
我见过很多类似这样的情况:
def parse(text):
if hasattr(text, 'read'):
text = text.read()
# Parse the text here...
但是如果我传递一个下面这个类的实例,它肯定会失败:
class X(object):
def __init__(self):
self.read = 10
我想问的是:处理这个问题的最符合Python风格的方法是什么?
我考虑了两种主要的方法:
if hasattr(text, 'read') and callable(text.read):
text = text.read()
还有
try:
text = text.read()
except ...
2 个回答
4
在Python中,最好的做法是假设text
是合适的类型。只有在你知道这个text
在不同的时间会是完全不同的东西时,才使用try-except
或者hasattr
。
换句话说,不要进行验证。只有在你打算使用else
时,才用if
,而如果你真的想在except
中进行特殊处理,才用try
。
2
在Python中,最好的做法其实是根本不去检查对象的类型。因为这个语言本身就很复杂,你很难确保不包含那些后面会出错的对象(比如你提到的例子:你并没有检查这个函数是否需要0个参数,更别提返回值的类型了),而且更糟糕的是,你可能会不小心排除掉一些有效的代码。
所以,最好的办法就是假设输入的值是没问题的,如果发现有问题再处理。
不过有一个例外:如果你有不同的代码路径需要根据不同的类型来处理(比如字符串和列表),这时候你就得检查类型来决定走哪条路。但再次强调:尽量使用最通用的检查方式(也就是说,如果用isinstance(l, collections.Iterable)
就能解决问题,那就别用isinstance(l, list)
)。如果最后发现“字符串”其实不够像字符串,那时候再处理也没问题。