在 python 中,有没有一种简单的方法来判断某些东西是否不是序列?我试着做:
if x is not sequence
但python不喜欢那样
7 回答
iter(x)
将引发一个TypeError
ifx
不能被迭代 - 但该检查“接受”集合和字典,尽管它“拒绝”其他非序列,例如None
和数字。
另一方面,字符串(大多数应用程序希望将其视为“单个项目”而不是序列)实际上是序列(因此,除非对字符串进行特殊处理,否则任何测试都将确认它们是序列)。因此,这种简单的检查通常是不够的。
在 Python 2.6 及更高版本中,引入了抽象基类,以及其他强大的功能,它们为此类“类别检查”提供了更好、更系统的支持。
>>> import collections
>>> isinstance([], collections.Sequence)
True
>>> isinstance((), collections.Sequence)
True
>>> isinstance(23, collections.Sequence)
False
>>> isinstance('foo', collections.Sequence)
True
>>> isinstance({}, collections.Sequence)
False
>>> isinstance(set(), collections.Sequence)
False
你会注意到字符串仍然被认为是“一个序列”(因为它们是),但至少你得到了 dicts 和 set 的影响。如果你想从你的“序列”概念中排除字符串,你可以使用collections.MutableSequence
(但这也排除了元组,它和字符串一样,是序列,但不是可变的),或者明确地这样做:
import collections
def issequenceforme(obj):
if isinstance(obj, basestring):
return False
return isinstance(obj, collections.Sequence)
调味,趁热食用!-)
PS:对于 Python 3,使用str
代替basestring
,对于 Python 3.3+:抽象基类,如Sequence
已移至collections.abc
.
对于 Python 3 和 2.6+,您可以检查它是否是 的子类collections.Sequence
:
>>> import collections
>>> isinstance(myObject, collections.Sequence)
True
在 Python 3.7 中,您必须使用collections.abc.Sequence
(collections.Sequence
将在 Python 3.8 中删除):
>>> import collections.abc
>>> isinstance(myObject, collections.abc.Sequence)
True
但是,这不适用于实现但不(因为它们应该)子类的鸭子__len__()
类型__getitem__()
序列collections.Sequence
。但它适用于所有内置的 Python 序列类型:列表、元组、字符串等。
虽然所有序列都是可迭代的,但并非所有可迭代的都是序列(例如,集合和字典是可迭代的,但不是序列)。检查hasattr(type(obj), '__iter__')
将返回True
字典和集合。
由于 Python “坚持”鸭子类型,其中一种方法是检查对象是否具有某些成员(方法)。
序列有长度,有项目序列,并且支持切片 [ doc ]。所以,它会是这样的:
def is_sequence(obj):
t = type(obj)
return hasattr(t, '__len__') and hasattr(t, '__getitem__')
# additionally: and hasattr(t, '__setitem__') and hasattr(t, '__delitem__')
它们都是特殊方法,__len__()
应该返回项目数,__getitem__(i)
应该返回一个项目(按顺序它是第i个项目,但不是映射),__getitem__(slice(start, stop, step))
应该返回子序列,并且__setitem__
和__delitem__
你期望的一样。就是这样一个契约,但对象是否真的做这些,取决于对象是否遵守契约。
请注意,上面的函数也会返回True
映射,例如dict
,因为映射也有这些方法。为了克服这个问题,你可以做更重的工作:
def is_sequence(obj):
try:
len(obj)
obj[0:0]
return True
except TypeError:
return False
但大多数时候你不需要这个,只要做你想做的事,就好像对象是一个序列一样,如果你愿意,可以捕获一个异常。这更像是pythonic。
Python 2.6.5 文档描述了以下序列类型:字符串、Unicode 字符串、列表、元组、缓冲区和 xrange。
def isSequence(obj):
return type(obj) in [str, unicode, list, tuple, buffer, xrange]
为了完整起见。numpyis_sequence
库中有一个实用程序(“Python 科学计算的基础包”)。
>>> from numpy.distutils.misc_util import is_sequence
>>> is_sequence((2,3,4))
True
>>> is_sequence(45.9)
False
但它接受集合作为序列并拒绝字符串
>>> is_sequence(set((1,2)))
True
>>> is_sequence("abc")
False
代码看起来有点像@adrian 的(参见numpy git code),有点不稳定。
def is_sequence(seq):
if is_string(seq):
return False
try:
len(seq)
except Exception:
return False
return True
为什么问为什么
尝试获取长度,如果异常返回 false
def haslength(seq):
try:
len(seq)
except:
return False
return True
你为什么做这个?这里的正常方法是要求某种类型的事物(序列或数字或类似文件的对象等),然后在不检查任何内容的情况下使用它。在 Python 中,我们通常不使用类来承载语义信息,而只是使用定义的方法(这称为“鸭子类型”)。我们也更喜欢我们确切知道会发生什么的 API;如果要更改函数的工作方式,请使用关键字参数、预处理或定义另一个函数。