测试变量是否为列表或元组

312
在Python中,测试变量是否包含列表或元组(即集合)的最佳方法是什么?
(即。一个集合) isinstance()像这里建议的那样邪恶吗? http://www.canonical.org/~kragen/isinstance/ 更新:我最常见的区分列表和字符串的原因是当我有一些无限深度的嵌套树/数据结构,其中有列表、列表、字符串等,我正在使用递归算法探索它们,我需要知道何时到达“叶子”节点。

77
简单地将类型检查视为邪恶是有些轻率的。它是语言的一部分。如果它真的那么邪恶,就应该有人写一份PEP来删除它。 - Adam Crossland
4
“这是语言的一部分”,就像除以零一样。它是可以避免的。在这种情况下,如果没有额外的信息,它可能完全是不必要的。Python中的大多数类型检查都是不必要的。因为并非所有类型检查都不需要,所以有些类型检查需要存在。但这并不意味着它有帮助、价值或者是一个好主意。 - S.Lott
12
你的意思是需要某种类型检查,但尽管如此,它仍然是无用、毫无价值和一个糟糕的想法。抱歉,这并没有意义。 - Glenn Maynard
19
“XXX是邪恶的”这种说法构思不佳,并且误导性强,其实际意思是:“你提出的XXX使用方法表明你可能并不理解它应该在何时使用,而且你很可能想要别的东西。” 这很可能是在这里的情况。 - Glenn Maynard
2
此外,对于延迟方法调用等事情,通常最好采用快速失败的方式;否则在稍后调用失败时很难进行调试。在Python 3中,没有“callable(x)”;检查给定对象是否可调用而不调用它的正确方法是使用isinstance(obj,collections.abc.Callable)。 - Antti Haapala -- Слава Україні
显示剩余4条评论
16个回答

658
if type(x) is list:
    print 'a list'
elif type(x) is tuple:
    print 'a tuple'
else:
    print 'neither a tuple or a list'

1
似乎不起作用:type([]) ==> list; type([]) is list ===> False - sten
3
在Python 2.7.5中:type([]) is list 返回 True - David Geiger
73
type(x) in [list,tuple] 更短。 - Alex Holcombe
如果 x 和 type(x) 是列表:为避免 [] 不匹配 - Kenichi Shibata

125

如果你需要的话,可以使用isinstance。它有点邪恶,因为它会排除自定义序列、迭代器和其他你可能真正需要的东西。然而,有时候你需要根据传入的参数不同而表现出不同的行为,比如当有人传递一个字符串时。在这种情况下,我的偏好是明确地检查strunicode,方法如下:

import types
isinstance(var, types.StringTypes)

注意不要将types.StringTypetypes.StringTypes混淆。后者包含strunicode对象。

许多人认为,types模块已经过时,建议直接检查对象的类型。因此,如果您不想使用上面提到的方法,可以像这样显式地检查strunicode

isinstance(var, (str, unicode)):

编辑:

更好的方法是:

isinstance(var, basestring)

编辑结束

在这两种情况下,您可以回退到像获取正常序列一样的行为,让非序列引发适当的异常。

关于类型检查的“邪恶”之处并不是你可能想要针对某种对象类型执行不同的操作,而是你人为地限制了函数处理意外对象类型时本来能够正确处理的能力。如果您有一个未经类型检查的最终回退机制,您便消除了这种限制。需要注意的是,过多的类型检查是代码异味(code smell),表明您可能需要进行一些重构,但这并不一定意味着您应该从一开始就避免使用它。


2
types模块有点像历史文物。如http://docs.python.org/dev/library/types.html#module-types所述,如果你真的必须检查`str`类型,你应该直接使用它,而不是使用`types.StringType`,因为它只是它的别名。但我认为这个答案并没有回答所问的问题,因为问题是关于“集合”的。除非你使用的Python已经足够新,具备了abc模块,否则你无法使用isinstance进行检查,即使有,我也建议尽可能避免使用检查。 - mzz
1
“assert isinstance(u'abc', str) == False”。 我认同直接检查类型比使用“types”模块更好,但是“types.StringTypes”做了一件“str”不会做的事情:它对“str”和“unicode”对象都返回True。我将编辑我的响应,提供另一种备选方案。 - jcdyer
1
我意识到我没有直接回答关于检查集合的问题,但实际上被问到的问题是“ isinstance 是否邪恶?”我给出了一个反例,它(1)是 isinstance 的一种非邪恶使用,因为有后备选项意味着它不会破坏鸭子类型,并且(2)对于人们想要检查是否是列表或元组(即从字符串中消除歧义)的常见动机来说,这是一个很好的解决方案。 - jcdyer
@AnttiHaapala 这就是为什么我提供另一个版本,它在Python 3中将被翻译为isinstance(foo, (str, bytes)) - jcdyer
无论如何,你的建议很好。然而,我讨厌在创建需要接受单个对象或复合集合并表现为前者是1个集合的方法时,总是不得不单独检查我的“集合”是否恰好是str、unicode或bytes。这不是Python的一个好特性——“字符串作为字符的不可变集合”并不像BDFL最初想象的那样有用 ;) - Antti Haapala -- Слава Україні
显示剩余3条评论

43

只要不多余,使用 isinstance 没有问题。如果一个变量应该只是列表/元组,则记录接口并将其用作此类。否则,检查是完全合理的:

if isinstance(a, collections.abc.Iterable):
    # use as a container
else:
    # not a container!

这种检查确实有一些很好的用例,例如与标准字符串startswith / endswith方法一起使用(尽管要准确的说,这些方法在CPython中是用C语言实现的,使用了显式的检查来判断它是否是元组 - 正如你所链接的文章中提到的那样,解决这个问题的方法不止一种)。

直接进行检查通常比试图将对象用作容器并处理异常更好-这可能会导致代码部分或不必要地运行而导致各种问题。


22
这是一种检查变量是否可迭代的不错方法。然而,对于这个问题的目的来说,它可能行不通。请注意,字符串也是可迭代的,可能会产生错误的结果。 - Corey O.
一个 set 对象也是可迭代的,这意味着你可以从中弹出元素,但它不保证特定的顺序,对于某些算法来说这是非常危险的。在元素的顺序很重要的情况下,使用此代码片段的算法可能会在不同的运行中产生不同的结果! - koo
1
看起来在2.x版本中,它可以在collections.Iterable下使用,但现在已经被移动到抽象基类(abc)中,所以现在它被称为collections.abc.Iterable - KyleMit

12

将参数记录为需要是序列,并将其用作序列。不要检查类型。


11

在Python 2.8中,type(list) is list返回的是false。我建议使用这种可怕的方式进行比较:

if type(a) == type([]) :
  print "variable a is a list"

(至少在我的系统上,使用Mac OS X Yosemite上的Anaconda)


1
type(a)是否为列表也会评估为假吗? - Dmitriy Sintsov
4
你的意思是指 Python 2.7.8 吗?https://www.python.org/dev/peps/pep-0404/#official-pronouncement - Carl
你好,我很好奇:为什么你认为你的例子“可怕”? - Seth Connell
1
type(list) is list 返回 False,因为 type(list)type,而不是 listtype(list()) is list 或者任何其他 列表实例 将返回 True - Michael Greene

10
>>> l = []
>>> l.__class__.__name__ in ('list', 'tuple')
True

9

如何理解:hasattr(a, "__iter__")

这段代码用来判断返回的对象是否可以被迭代,即是否可以像生成器一样遍历。默认情况下,元组和列表可以被迭代,但是字符串类型不行。


12
同样适用于字符串(至少在Python 3上)。 - SzieberthAdam
4
这个答案是错误的。因为类型'str'也有方法'iter'。@SzieberthAdam是正确的。类型'set'也是可迭代的,但不可排序。 - PADYMKO
字典也有“__iter__”。 - thet
1
如果您继续,任何自定义类型都可能因某种原因具有 __iter__ - Alexander Irbis

8

Python 使用“鸭子类型”,即如果一个变量像鸭子一样嘎嘎叫,那它就是只鸭子。在您的情况下,您可能希望它是可迭代的,或者您希望访问特定索引处的项目。您应该这样做:即在 for var:var[idx] 中使用对象,并将其放在 try 块中,如果出现异常,它就不是一只鸭子...


7
问题在于,如果“var”是一个字符串,那么迭代将会出现意料之外的结果。 - Brian M. Hunt
尽管Brian M. Hunt所述的事实是他的解决方案相当Pythonic,即通过请求宽恕而不是允许来解决问题。 - Géza Török

8
我建议采用纯Python的方式:
if isinstance(x, (list, tuple))): pass


2
在原问题发布13年后,这个答案是在Python3中实现这一目标最直接的方法。 - Nicolás Ozimica
这个替代方案适用于类型的 tuple,而不是它们的 list - Nicolás Ozimica
同样适用于dict。这应该是被接受的答案。 - Gilles Quénot

5

判断变量是列表还是元组,或者通常检查变量类型的另一种简单方法是:

def islist(obj):
    if ("list" in str(type(obj))):
        return True
    else:
        return False

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接