如何检查一个对象是列表或元组(但不是字符串)?

35 浏览
0 Comments

如何检查一个对象是列表或元组(但不是字符串)?

为了确定输入是一个list/tuple,而不是一个str,我通常会这样做。因为很多时候,我会遇到一个函数错误地传递了一个str对象,目标函数会假定lst实际上是一个listtuple,并执行for x in lst

assert isinstance(lst, (list, tuple))

我的问题是:有没有更好的方法来实现这个目的?

admin 更改状态以发布 2023年5月20日
0
0 Comments

记住,在 Python 中我们想要使用“鸭子类型”。所以,任何像列表一样的东西都可以被视为列表。因此,不要检查列表的类型,只需要看它是否像列表那样即可。

但是字符串也像列表一样,而且这通常并不是我们想要的。有时甚至是一个问题!因此,明确检查字符串,但然后使用鸭子类型。

这是我为了好玩写的一个函数。它是 repr() 的一个特殊版本,可以在尖括号('<'、'>')中打印任何序列。

def srepr(arg):
    if isinstance(arg, basestring): # Python 3: isinstance(arg, str)
        return repr(arg)
    try:
        return '<' + ", ".join(srepr(x) for x in arg) + '>'
    except TypeError: # catch when for loop fails
        return repr(arg) # not a sequence so just return repr

整体上这很简洁、优雅。但是那个 isinstance() 检查是干什么的?那有点像黑客攻击。但它是必不可少的。

这个函数在任何像列表一样的东西上递归地调用自己。如果我们没有特别处理字符串,那么它会被视为一个列表,一个字符一个字符地分割开来。但是然后递归调用会尝试将每个字符都视为一个列表——并且它会工作!甚至一个只有一个字符的字符串也像一个列表!函数会继续递归调用自己,直到栈溢出。

像这个函数一样,依赖于每个递归调用分解要做的工作的函数,必须特别处理字符串——因为你不能将字符串分解到一个字符以下的级别,而且甚至一个只有一个字符的字符串也像一个列表。

注意:try/except 是表示我们意图最清晰的方式。但如果这段代码在某种程度上是时间关键的,则我们可能希望用某种测试来查看 arg 是否是一个序列,而不是测试类型,我们应该测试行为。如果它有一个 .strip() 方法,那么它就是一个字符串,因此不要将其视为序列;否则,如果它可以被索引或迭代,那么它就是一个序列:

def is_sequence(arg):
    return (not hasattr(arg, "strip") and
            hasattr(arg, "__getitem__") or
            hasattr(arg, "__iter__"))
def srepr(arg):
    if is_sequence(arg):
        return '<' + ", ".join(srepr(x) for x in arg) + '>'
    return repr(arg)

编辑:我最初写上了一个检查 __getslice__() 的代码,但我注意到在 collections 模块的文档中,有趣的方法是 __getitem__();这是有道理的,这是你索引一个对象的方式。那似乎比 __getslice__() 更基础,所以我修改了上面的内容。

0
0 Comments

只适用于Python 2(不适用于Python 3):

assert not isinstance(lst, basestring)

实际上这是你想要的,否则你会错过很多表现得像列表,但不是listtuple子类的东西。

0