测试变量是列表还是元组
Posted
技术标签:
【中文标题】测试变量是列表还是元组【英文标题】:Test if a variable is a list or tuple 【发布时间】:2011-01-12 04:47:58 【问题描述】:在 python 中,测试变量是否包含列表或元组的最佳方法是什么? (即一个集合)
isinstance()
是否像这里建议的那样邪恶? http://www.canonical.org/~kragen/isinstance/
更新:我想将列表与字符串区分开来的最常见原因是当我有一些无限深的嵌套树/字符串列表列表的数据结构等时,我正在使用递归算法进行探索我需要知道我什么时候点击了“叶子”节点。
【问题讨论】:
广泛地将类型检查视为邪恶是有点轻率的。这是语言的一部分。如果它如此邪恶,应该有人写一个 PEP 来删除它。 @Adam Crossland:“这是语言的一部分。”就像除以零一样。这是可以避免的。在这种情况下,如果没有额外的信息,它可能完全没有必要。 Python 中的大多数类型检查都是不必要的。由于不是 all 是不必要的,因此需要进行一些类型检查。但这并不意味着它有用、有价值,甚至是个好主意。 所以你说需要进行一些类型检查,但尽管如此,它是无用的、毫无价值的,而且是个坏主意。抱歉,这没有任何意义。 “XXX 是邪恶的”是错误的,误导性的简写为“你要求做 XXX 的方式表明你不明白什么时候应该实际使用它,而且你几乎肯定想要别的东西”。这很可能是这种情况。 我并没有大体上认为它是邪恶的。我写了一篇关于什么时候是邪恶的,什么时候是正当的短文。那篇文章可能有很多东西——正确的、错误的、清晰的、模糊的、令人愉快的、无聊的——但它不是一件事就是对技术的广泛忽视。 【参考方案1】:if type(x) is list:
print 'a list'
elif type(x) is tuple:
print 'a tuple'
else:
print 'neither a tuple or a list'
【讨论】:
似乎不起作用:type([]) ==> list; type([]) is list ===> False 在 Python 2.7.5 中:type([]) is list
返回 True
type(x) in [list,tuple]
更短。
如果 x 和 type(x) 是列表:避免 [] 不匹配【参考方案2】:
如果需要,请继续使用isinstance
。这有点邪恶,因为它排除了自定义序列、迭代器和其他您可能实际需要的东西。但是,有时您需要采取不同的行为,例如,如果有人传递了一个字符串。我的偏好是明确检查str
或unicode
,如下所示:
import types
isinstance(var, types.StringTypes)
注意不要将types.StringType
误认为types.StringTypes
。后者包含str
和unicode
对象。
types
模块被许多人认为已经过时,只支持直接检查对象的类型,因此,如果您不想使用上述模块,您也可以明确检查 str
和 unicode
,像这样:
isinstance(var, (str, unicode)):
编辑:
更好的是:
isinstance(var, basestring)
结束编辑
在其中任何一个之后,您都可以恢复为获得正常序列的行为,让非序列引发适当的异常。
看到类型检查的“邪恶”并不是你可能想对某种类型的对象采取不同的行为,而是你人为地限制你的函数使用意外的对象类型做正确的事情,否则会做正确的事。如果您有一个未经过类型检查的最终回退,则删除此限制。应该注意的是,过多的类型检查是一种代码味道,表明您可能想要进行一些重构,但这并不一定意味着您应该从一开始就避免它。
【讨论】:
类型模块有点像历史文物。如docs.python.org/dev/library/types.html#module-types 所述,如果您真的必须检查str
类型,您应该直接使用它,而不是使用types.StringType
,这只是它的别名。但我不认为这个答案回答了所提出的问题,因为那是关于“收藏”的。除非您使用的 python 足够新,可以拥有 abc
模块,否则您无法使用 isinstance
进行检查,即便如此,我还是建议尽可能避免检查。
assert isinstance(u'abc', str) == False
。我同意最好直接检查类型,而不是使用types
模块,但是types.StringTypes
做了str
没有做的事情:它为str
和unicode
对象返回True。我将编辑我的回复以提供双重检查作为替代方案。
我意识到我没有直接回答检查收藏的问题,但实际提出的问题是“isinstance
邪恶吗?”我举了一个反例,(1)是isinstance
的非恶意使用,因为有一个后备意味着它不会破坏ducktyping,并且(2)对于人们想要的一个非常常见的动机来说是一个很好的解决方案检查某个东西是list
还是tuple
(即从字符串中消除歧义)。
我同意,但需要注意的是,自定义类型的行为通常也像字符串一样有用。但是 Python 的 OO 只能走到这一步……
class Foo(str): pass
做你想做的事吗?【参考方案3】:
使用isinstance
没有任何问题,只要它不是多余的。如果一个变量应该只是一个列表/元组,那么记录接口并直接使用它。否则检查是完全合理的:
if isinstance(a, collections.Iterable):
# use as a container
else:
# not a container!
这种类型的检查确实有一些很好的用例,例如使用标准字符串 startswith / endswith 方法(虽然准确地说,这些方法是在 CPython 中使用显式检查来实现的,以查看它是否是tuple - 解决此问题的方法不止一种,如您链接到的文章中所述)。
显式检查通常比尝试将对象用作容器并处理异常要好 - 这可能会导致代码部分或不必要地运行的各种问题。
【讨论】:
这是检查变量是否可迭代的好方法。但是,它可能不适用于这个问题。请注意,字符串也是可迭代的,并且可能会产生误报。 一个set
对象也是一个可迭代对象,这意味着虽然你可以从其中弹出元素,但它并不能保证一定的顺序,这对于某些算法来说是非常危险的事情。在元素的顺序确实很重要的情况下,使用此 sn-p 的算法可能会在不同的运行中产生不同的结果!【参考方案4】:
将参数记录为需要为序列,并将其用作序列。不要检查类型。
【讨论】:
【参考方案5】:怎么样:hasattr(a, "__iter__")
?
它告诉返回的对象是否可以作为生成器进行迭代。默认情况下,元组和列表可以,但字符串类型不可以。
【讨论】:
字符串的结果也为 True(至少在 Python 3 上)。 这是错误的答案。由于类型'str'也有方法'iter'。 @SzieberthAdam 是对的。 'set' 类型也是可迭代的,但不可排序。 字典也有__iter__
。
如果继续,任何自定义类型都可能出于某种原因有__iter__
...【参考方案6】:
在 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) is list 也评估为 false ? 你的意思是 Python 2.7.8 吗? python.org/dev/peps/pep-0404/#official-pronouncement 你好,我很好奇:为什么你认为你的例子“可怕”?type(list) is list
返回False
,因为type(list)
是type
,而不是list
。 type(list()) is list
或列表的任何其他instance 将返回True
。【参考方案7】:
>>> l = []
>>> l.__class__.__name__ in ('list', 'tuple')
True
【讨论】:
【参考方案8】:Python 使用“鸭子类型”,即如果一个变量像鸭子一样咕咕叫,它一定是鸭子。在您的情况下,您可能希望它是可迭代的,或者您希望访问某个索引处的项目。你应该这样做:即在 try
块内使用 for var:
或 var[idx]
中的对象,如果你遇到异常,它不是鸭子......
【讨论】:
这个问题是如果var
是一个字符串迭代,可能会出现意想不到的结果。
尽管 Brian M. Hunt 陈述了这一事实,但就请求宽恕而不是许可而言,他的解决方案相当蟒蛇。【参考方案9】:
确定变量是列表还是元组或通常检查变量类型的另一种简单方法是:
def islist(obj):
if ("list" in str(type(obj)) ): return True
else : return False
【讨论】:
【参考方案10】:如果您只需要知道是否可以将foo[123]
表示法与变量一起使用,您可以使用hasattr(foo, '__getitem__')
检查__getitem__
属性(当您按索引访问时python 调用的属性)是否存在
【讨论】:
【参考方案11】:如果您真的想将任何东西作为函数参数处理,则必须进行更复杂的测试。
type(a) != type('') and hasattr(a, "__iter__")
虽然,通常只需说明一个函数需要可迭代,然后只检查type(a) != type('')
就足够了。
也可能发生这样的情况,对于一个字符串,你有一个简单的处理路径,或者你会很好地进行拆分等,所以你不想对字符串大喊大叫,如果有人给你发了一些奇怪的东西,只是让他有一个例外。
【讨论】:
【参考方案12】:原则上,我同意上述 Ignacio 的观点,但您也可以使用 type 来检查某个内容是元组还是列表。
>>> a = (1,)
>>> type(a)
(type 'tuple')
>>> a = [1]
>>> type(a)
(type 'list')
【讨论】:
【参考方案13】:不是最优雅的,但我喜欢(对于 Python 3):
if hasattr(instance, '__iter__') and not isinstance(instance, (str, bytes)):
...
这允许其他迭代(如 Django 查询集),但不包括字符串和字节串。我通常在接受单个对象 ID 或对象 ID 列表的函数中使用它。有时对象 ID 可以是字符串,我不想逐个字符地迭代这些字符。 :)
【讨论】:
【参考方案14】:你知道...我这样做可能很愚蠢,但我这样做:
try:
len(thing)
except:
# not a list
就像,如果我能知道它的长度,那肯定不止一件事。
编辑:刚刚意识到如果非列表项是字符串(因为字符串本质上是字符列表),它将不起作用。
【讨论】:
不过,类型检查器可能对此有点生气。 不过,这不会将列表或其他集合与字符串分开。字符串支持 len() 刚刚意识到。不过,它适用于数字等。以上是关于测试变量是列表还是元组的主要内容,如果未能解决你的问题,请参考以下文章