测试变量是列表还是元组


234

在python中,测试变量是否包含列表或元组的最佳方法是什么?(即集合)

isinstance()邪恶的建议在这里?http://www.canonical.org/~kragen/isinstance/

更新:我想从字符串中区分列表的最常见原因是当我有一些无限深的嵌套树/字符串列表等列表的数据结构时,我正在使用递归算法进行探索,我需要知道我何时击中“叶子”节点。


72
广泛否认类型检查是邪恶的,这很容易。这是语言的一部分。如果它是如此邪恶,那么有人应该写一个PEP来删除它。
亚当·克罗斯兰

4
@亚当·克罗斯兰:“这是语言的一部分。” 就像被零除。这是可以避免的。在这种情况下,如果没有其他信息,则可能完全没有必要。Python中大多数类型检查都是不必要的。由于并非全部都是不必要的,因此需要提供一些类型检查。但这并不意味着它有用,有价值甚至是个好主意。
S.Lott

11
因此,您说的是需要某种类型检查,但是尽管如此,它还是没有用,毫无价值并且是一个坏主意。抱歉,这没有意义。
格伦·梅纳德

18
“ XXX是邪恶的”的概念很糟糕,误导了“您要求做XXX的方式表明您不知道何时应该实际使用它,而您几乎肯定需要其他东西”的简写形式。这很可能是这种情况。
Glenn Maynard '02

2
我没有将其广泛视为邪恶。我写了一篇简短的文章,介绍什么时候是邪恶的,什么时候是合理的。这篇文章可能有很多东西-对,错,清晰,模糊,令人愉悦,无聊-但其中一件事不是对该技术的广泛驳斥。
Kragen Javier Sitaker

Answers:


101

继续使用,isinstance如果需要的话。这有点邪恶,因为它不包括自定义序列,迭代器和您可能实际需要的其他东西。但是,有时,例如,有人传递字符串时,您需要采取不同的行为。我的偏好是明确检查strunicode类似:

import types
isinstance(var, types.StringTypes)

NB千万不要误会types.StringTypetypes.StringTypes。后者包含strunicode对象。

types许多人认为该模块已过时,只支持直接检查对象的类型,因此,如果您不想使用以上内容,则可以替代地显式检查strand unicode,例如:

isinstance(var, (str, unicode)):

编辑:

更好的是:

isinstance(var, basestring)

结束编辑

在这两种情况中的任何一种之后,您都可以回到正常的序列状态,让非序列引发适当的异常。

看到关于类型检查的“邪恶”之处不是您可能不想对某种特定类型的对象表现出不同的行为,而是您人为地限制了函数使用意外的对象类型来执行正确的操作,否则它们将执行正确的操作。如果您有未经过类型检查的最终后备,则可以删除此限制。应该注意的是,过多的类型检查是一种代码异味,表明您可能想要进行一些重构,但这并不一定意味着您应该避免从getgo中进行此操作。


2
类型模块有点历史性。如docs.python.org/dev/library/types.html#module-types所述,如果您确实必须检查str类型,则应直接使用该类型,而不是types.StringType仅使用它的别名。但是我认为这个答案不能回答所提出的问题,因为那是关于“集合”的。除非您使用足够新的python以拥有abc不是您可以isinstance用来检查的模块,否则即使如此,我还是建议您尽可能避免进行检查。
mzz 2010年

1
assert isinstance(u'abc', str) == False。我同意最好直接检查类型,而不是使用types模块,但types.StringTypes这样做str却不行:它为strand unicode对象返回True 。我将编辑我的回复,以提供再次检查的替代方法。
jcdyer '02

1
我意识到我没有直接回答托收检查的问题,但实际提出的问题是“是isinstance邪恶的吗?” 我给出了一个反例,其中(1)是对Evil的非邪恶用途isinstance,因为具有后备意味着它不会破坏鸭嘴兽,并且(2)是人们想要检查是否有非常普遍动机的良好解决方案某物是一个listtuple(即从字符串中消除它们的歧义)。
jcdyer '02

我同意,但要注意的是,自定义类型也常常像字符串一样有用。但是Python的OO只能走这么远……
Kragen Javier Sitaker

class Foo(str): pass想做什么?
jcdyer 2010年

567
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([])是list ===> False
sten 2014年

3
在Python 2.7.5中:type([]) is list返回True
David Geiger

54
type(x) in [list,tuple]更短。
Alex Holcombe 2015年

如果x和type(x)是列表:避免[]不匹配
Shibata Kenichi

我不得不向下滚动太多。:D
Rithwik

38

没有什么错误使用isinstance,只要它不是多余的。如果变量仅应是列表/元组,则记录该接口并按原样使用它。否则,检查是完全合理的:

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

这种类型的检查确实有一些很好的使用情况,如与标准字符串startswith / 的endsWith方法(虽然是准确的,这些都是使用一个明确的检查,看它是否是一个元组用C语言实现的CPython的-有不止一种方法如您所链接的文章所述,以解决此问题)。

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


15
这是检查变量是否可迭代的好方法。但是,对于这个问题,它可能行不通。请注意,字符串也是可迭代的,并且可能会产生误报。
Corey O.

一个set对象也是一个迭代,这意味着,虽然你肯定可以从弹出它的元素,但它并不能保证一定的顺序,这是一定的算法非常危险的事情。在元素的顺序确实很重要的情况下,使用此代码段的算法可能会在不同的运行中产生不同的结果!
koo


12

如何:hasattr(a, "__iter__")

它告诉返回的对象是否可以作为生成器进行迭代。默认情况下,元组和列表可以,但字符串类型不能。


我发现这真的很有用。
javadba

8
对于字符串,结果也为True(至少在Python 3上)。
SzieberthAdam 2013年

2
这是错误的答案。由于类型“ str”也具有方法“ iter ”。@SzieberthAdam是正确的。类型“集合”也是可迭代的,但不可排序。
PADYMKO '16

也有字典__iter__
thet

如果您继续,__iter__由于某种原因,任何自定义类型都可能具有...
Alexander Irbis

10

在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)是list也会计算为false吗?
Dmitriy Sintsov


您好,我很好奇:您为什么认为您的示例“可怕”?
赛斯·康奈尔

type(list) is list回报False,因为type(list)type,不listtype(list()) is list或与列表的任何其他实例一起返回True
迈克尔·格林

8

Python使用“鸭子类型”,即,如果变量像鸭子一样醒来,则它一定是鸭子。在您的情况下,您可能希望它是可迭代的,或者您想以某个索引访问该项目。您应该这样做:即在块中for var:或块var[idx]内使用对象try,如果遇到异常,它就不是鸭子。


7
问题是如果var发生字符串迭代可能会产生意外结果。
Brian M. Hunt

尽管Brian M. Hunt指出了事实,但就请求宽恕而不是允许而言,他的解决方案是相当不错的。
盖佐Török

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

3

如果您只需要知道是否可以foo[123]对变量使用符号,则可以使用以下命令检查__getitem__属性的存在(这是python在通过索引访问时调用的内容)hasattr(foo, '__getitem__')


2

如果您真的想处理几乎任何函数参数,则必须进行更复杂的测试。

type(a) != type('') and hasattr(a, "__iter__")

尽管通常只需说明一个函数期望可迭代然后仅检查即可type(a) != type('')

也可能会发生这样的情况:对于字符串,您具有简单的处理路径,或者您会变得很好并进行拆分等,因此您不想大喊大叫,如果有人给您发送一些奇怪的东西,请让他拥有一个例外。


2

找出变量是列表变量还是元组变量或通常检查变量类型的另一种简便方法是:

    def islist(obj):

        if ("list" in str(type(obj)) ): return True

        else : return False

1

原则上,我同意上面的Ignacio,但是您也可以使用type来检查某项是元组还是列表。

>>> a = (1,)
>>> type(a)
(type 'tuple')
>>> a = [1]
>>> type(a)
(type 'list')
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.