Python:检查对象是否是序列

Python:检查对象是否是序列,python,if-statement,sequence,sequences,Python,If Statement,Sequence,Sequences,在python中,有没有一种简单的方法来判断某个东西是否不是序列?我试着做: 如果x不是序列但python不喜欢这样iter(x)将引发类型错误,如果x不能被迭代——但该检查“接受”集合和字典,尽管它“拒绝”其他非序列,如None和数字 另一方面,字符串(大多数应用程序需要考虑的是单个项而不是序列)实际上是序列(因此,任何测试,除非字符串专用,都要确认它们是)。因此,这种简单的检查往往是不够的 在Python2.6及更高版本中,引入了抽象基类,在其他强大功能中,它们为此类“类别检查”提供了更好、

在python中,有没有一种简单的方法来判断某个东西是否不是序列?我试着做:
如果x不是序列
但python不喜欢这样

iter(x)
将引发
类型错误
,如果
x
不能被迭代——但该检查“接受”集合和字典,尽管它“拒绝”其他非序列,如
None
和数字

另一方面,字符串(大多数应用程序需要考虑的是单个项而不是序列)实际上是序列(因此,任何测试,除非字符串专用,都要确认它们是)。因此,这种简单的检查往往是不够的

在Python2.6及更高版本中,引入了抽象基类,在其他强大功能中,它们为此类“类别检查”提供了更好、系统化的支持

你会注意到字符串仍然被认为是“序列”(因为它们是),但至少你得到了dicts和set。如果要从“序列”的概念中排除字符串,可以使用
集合.MutableSequence
(但这也排除元组,元组与字符串一样是序列,但不是可变的),或者显式执行:

import collections

def issequenceforme(obj):
    if isinstance(obj, basestring):
        return False
    return isinstance(obj, collections.Sequence)
调味,趁热享用!-)


PS:对于Python3,使用
str
而不是
basestring
,对于Python3.3+:像
Sequence
这样的抽象基类已经移动到
集合。abc
为什么要这样做?这里的正常方法是需要某种类型的东西(序列、数字或类似文件的对象等),然后在不检查任何东西的情况下使用它。在Python中,我们通常不使用类来携带语义信息,而只是使用定义的方法(这称为“duck类型”)。我们也更喜欢API,因为我们确切地知道预期的结果;如果要更改函数的工作方式,请使用关键字参数、预处理或定义其他函数。

描述了以下序列类型:字符串、Unicode字符串、列表、元组、缓冲区和xrange

def isSequence(obj):
    return type(obj) in [str, unicode, list, tuple, buffer, xrange]
为什么要问为什么

尝试获取长度,如果异常返回false

def haslength(seq):
    try:
        len(seq)
    except:
        return False
    return True
由于Python“坚持”duck类型,其中一种方法是检查对象是否有成员(方法)

序列具有长度、项目序列,并支持切片[]。所以,它是这样的:

def is_sequence(obj):
    t = type(obj)
    return hasattr(t, '__len__') and hasattr(t, '__getitem__')
    # additionally: and hasattr(t, '__setitem__') and hasattr(t, '__delitem__')

它们都是特殊的方法,
\uuuu len\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu,和
\uuuu setitem\uuuu
\uuu delitem\uuuu
如您所料。这是一种契约,但客体是否真的这样做取决于客体是否遵守契约

注意上述函数也将返回映射的
True
,例如
dict
,因为映射也有这些方法。要克服这一点,您可以做更繁重的工作:


但是大多数时候,你不需要这个,只要做你想做的事情,就好像对象是一个序列,如果你愿意,捕获一个异常。这更像是python。

我认为下面的代码片段符合您的要求:

def is_sequence(obj):
    return hasattr(type(obj), '__iter__')

对于Python3和2.6+,您可以检查它是否是
集合的子类

>>> import collections
>>> isinstance(myObject, collections.Sequence)
True
在Python3.7中,必须使用
collections.abc.Sequence
collections.Sequence
将在Python3.8中删除):

但是,这对于实现
\uu len\uuuuuuuuuuuuuuuuuuu()
\uuuuuuu getitem\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu()
的duck类型序列不起作用,但。但它适用于所有内置Python序列类型:列表、元组、字符串等


虽然所有序列都是可iterable,但并非所有的可iterable都是序列(例如,集合和字典都是可iterable,但不是序列)。为完整起见,检查字典和集合的hasattr(type(obj),“\uu iter”
将返回
True

。库中有一个实用工具
is_sequence
(“使用Python进行科学计算的基本包”)

但它接受集合作为序列,并拒绝字符串

代码看起来有点像@adrian的(参见),有点不稳定

def is_sequence(seq):
    if is_string(seq):
        return False
    try:
        len(seq)
    except Exception:
        return False
    return True

相关:在python中,如何确定变量是否是可写的?是的,但尽管所有序列都是可重用的,但并非所有的可重用都是序列(例如,集合和dict是内置的可重用容器,它们不是序列)。请注意,对于实现sequence协议但不涉及
集合的对象,此代码示例将返回错误的结果。sequence
ABC。是的:与更简单的ABC不同,sequence不实现
\uuuuuu子类钩子\uuuu
类方法,因此,它永远不会自动识别一个选择不向其注册(或继承)的类——本质上不可能通过内省来判断一个类的
\uuu getitem\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
是否接受整数和切片,是否在错误的索引上引发
索引器,等等——基本上,你需要排除
dict
set
(如果你只是做内省的话,这看起来确实“实现了序列协议”…但结果却不是!-)。集合很容易排除,因为它们没有
\uGetItem\uuuuu
,但映射要困难得多。我见过的最好的检查可能是查找
,就像
dict.update
那样,但这仍然有很多地方需要改进。因此,要将我的自定义类型检测为序列,我必须对序列进行子类化?提到的警告的一个很好的例子是numpy数组,具有序列的所有必需属性,但isinstance无法识别这些属性。如果这对numpy数组都不起作用,那就太没希望了。这是一个赋值约束。如果争论
>>> import collections
>>> isinstance(myObject, collections.Sequence)
True
>>> import collections.abc
>>> isinstance(myObject, collections.abc.Sequence)
True
>>> 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
def is_sequence(seq):
    if is_string(seq):
        return False
    try:
        len(seq)
    except Exception:
        return False
    return True