鸭子类型与使用hasattr

1 投票
2 回答
1001 浏览
提问于 2025-04-17 19:02

我见过很多类似这样的情况:

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))。如果最后发现“字符串”其实不够像字符串,那时候再处理也没问题。

撰写回答