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

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

isinstance()是否如这里所建议的那样邪恶?http://www.canonical.org/~kragen/isinstance/

更新:我想要区分列表和字符串的最常见原因是,当我有一些无限深嵌套的字符串列表的列表的列表的树/数据结构时,我正在用递归算法探索,我需要知道什么时候我已经碰到了“叶”节点。

373407 次浏览

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

原则上,我同意上面Ignacio的观点,但你也可以使用类型来检查某物是否是元组或列表。

>>> a = (1,)
>>> type(a)
(type 'tuple')
>>> a = [1]
>>> type(a)
(type 'list')

使用isinstance没有任何问题,只要它不是多余的。如果一个变量应该只是一个列表/元组,那么就记录接口并这样使用它。否则,检查是完全合理的:

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

这种类型的检查确实有一些很好的用例,比如标准字符串startswith / endswith方法(尽管准确地说,这些方法是用CPython中的C实现的,使用显式检查来查看它是否是元组——解决这个问题的方法不止一种,正如你链接到的文章中提到的那样)。

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

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

如果需要的话,继续使用isinstance。这有点邪恶,因为它排除了自定义序列、迭代器和其他您可能实际需要的东西。然而,有时如果有人传递一个字符串,则需要采取不同的行为。我的偏好是显式检查strunicode,如下所示:

import types
isinstance(var, types.StringTypes)

注意:不要把types.StringType误认为types.StringTypes。后者包含strunicode对象。

types模块被很多人认为是过时的,只适合直接检查对象的类型,所以如果你不想使用上面的方法,你可以显式检查strunicode,就像这样:

isinstance(var, (str, unicode)):

编辑:

更好的是:

isinstance(var, basestring)

最后编辑

在完成这两种操作后,您可以退回到获取正常序列的行为,让非序列引发适当的异常。

关于类型检查的“邪恶”之处并不是你想要对某种类型的对象做出不同的行为,而是你人为地限制了你的函数对意外的对象类型做正确的事情,否则这些对象类型会做正确的事情。如果您有一个没有类型检查的最终回退,则可以删除此限制。应该注意的是,过多的类型检查是一种代码气味,表明您可能需要进行一些重构,但这并不一定意味着您应该从一开始就避免它。

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

>>> l = []
>>> l.__class__.__name__ in ('list', 'tuple')
True
if type(x) is list:
print 'a list'
elif type(x) is tuple:
print 'a tuple'
else:
print 'neither a tuple or a list'

hasattr(a, "__iter__")怎么样?

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

在Python 2.8中type(list) is list返回false
我建议用这种可怕的方式比较类型:

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

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

如果你真的想把任何东西都当作函数参数来处理,测试就会更复杂。

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

不过,通常只要说明函数需要可迭代对象,然后只检查type(a) != type('')就足够了。

也有可能发生,对于一个字符串,你有一个简单的处理路径,或者你会很好地做一个分割等等,所以你不想对字符串大喊大叫,如果有人给你发送了一些奇怪的东西,让他有一个异常。

另一个简单的方法来确定一个变量是列表还是元组,或者检查变量类型:

    def islist(obj):


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


else : return False

不是最优雅的,但我做到了(对于Python 3):

if hasattr(instance, '__iter__') and not isinstance(instance, (str, bytes)):
...

这允许其他可迭代对象(如Django queryset),但不包括字符串和字节串。我通常在接受单个对象ID或对象ID列表的函数中使用这种方法。有时候对象id可以是字符串我不想一个字符一个字符地遍历这些。:)

你知道的…我这么做可能有点蠢,但我是这么做的

try:
len(thing)
except:
# not a list

如果我能知道它的长度,那肯定不止一件事。

编辑:刚刚意识到,如果非列表项是字符串(因为字符串本质上是字符列表),它将不起作用。

另一种方法是将isinstancetyping一起使用。

from typing import List, Tuple
>> isinstance([1,2], Tuple)
False
>> isinstance([1,2], List)
True