Python:检查对象是否是序列

nic*_*ine 58 python if-statement sequences sequence

在python中有一个简单的方法来判断某些东西是不是一个序列?我试着这么做: if x is not sequence但是python并不喜欢这样

Ale*_*lli 67

iter(x)将提出一个TypeErrorif x不能迭代 - 但该检查"接受"集和字典,虽然它"拒绝"其他非序列,如None和数字.

另一方面手,字符串(其中大多数应用需要考虑"单品",而不是序列)实际上序列(因此,任何测试,除非specialcased的字符串,是要确认它们).因此,这种简单的检查通常是不够的.

在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
Run Code Online (Sandbox Code Playgroud)

你会注意到字符串仍然被认为是"一个序列"(因为它们),但至少你得到了dicts和set.如果你想从你的"正在序列"的概念中排除字符串,你可以使用collections.MutableSequence(但这也排除了元组,像字符串一样,是序列,但不是可变的),或者明确地做:

import collections

def issequenceforme(obj):
    if isinstance(obj, basestring):
        return False
    return isinstance(obj, collections.Sequence)
Run Code Online (Sandbox Code Playgroud)

品尝季节,热腾腾! - )

  • 请注意,此代码示例将为实现序列协议的对象返回错误的结果,但不涉及`collections.Sequence` ABC. (11认同)
  • 是的:与简单的ABCs不同,Sequence没有实现`__subclasshook__`类方法,所以它永远不会自动识别一个选择不用它来"注册"(或从它继承)的类 - 它基本上是不可能的通过内省来判断一个类的`__getitem__`是否接受整数和切片,在错误的索引上引发`IndexError`等等 - 所有你需要排除`dict`和`set`,基本上(_do_似乎"实现序列协议) "如果你只是做内省......但后来却不去! - ). (4认同)
  • 提到的警告的一个很好的例子是 numpy 数组,它具有序列所需的所有属性,但无法被 isinstance 识别。如果这甚至不适用于 numpy 数组,那么似乎非常无望。 (2认同)

Hum*_*mad 9

我认为以下代码片段可以满足您的需求:

def is_sequence(obj):
    return hasattr(type(obj), '__iter__')
Run Code Online (Sandbox Code Playgroud)

  • 应该是`hasattr(type(obj),'__ user __')`,参见[this comment](/sf/ask/205598011/#comment71833903_31043360). (3认同)

Al *_*art 9

对于 Python 3 和 2.6+,您可以检查它是否是以下的子类collections.Sequence

>>> import collections
>>> isinstance(myObject, collections.Sequence)
True
Run Code Online (Sandbox Code Playgroud)

在 Python 3.7 中,您必须使用collections.abc.Sequencecollections.Sequence将在 Python 3.8 中删除):

>>> import collections.abc
>>> isinstance(myObject, collections.abc.Sequence)
True
Run Code Online (Sandbox Code Playgroud)

然而,这对于其实现鸭类型的序列将无法正常工作__len__()__getitem__(),但不会(因为他们应该)的子类collections.Sequence。但它适用于所有内置的 Python 序列类型:列表、元组、字符串等。

虽然所有序列都是可迭代的,但并非所有可迭代的都是序列(例如,集合和字典是可迭代的,但不是序列)。检查hasattr(type(obj), '__iter__')将返回True字典和集合。


fik*_*r4n 6

由于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__')
Run Code Online (Sandbox Code Playgroud)

它们都是特殊的方法,__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
Run Code Online (Sandbox Code Playgroud)

但是大多数时候你不需要这个,只要做你想要的就好,就像对象是一个序列一样,如果你愿意,也可以捕获异常.这更像是pythonic.

  • 如果使用`hasattr()`,则需要检查魔术方法的对象类型,而不是对象本身.请参阅[Python 2](https://docs.python.org/2/reference/datamodel.html#special-method-lookup-for-new-style-classes)和[Python 3](https:// docs关于如何查找特殊方法的.python.org/3/reference/datamodel.html#special-method-lookup)文档. (2认同)

Dav*_*ian 5

Python的2.6.5文档介绍以下序列类型:字符串,Unicode字符串,列表,元组,缓冲,还有range.

def isSequence(obj):
    return type(obj) in [str, unicode, list, tuple, buffer, xrange]
Run Code Online (Sandbox Code Playgroud)

  • 这个答案的问题是它不会检测不是内置类型的序列.Python"序列"是实现响应序列操作所必需的方法的任何对象. (17认同)
  • 另外,使用`isinstance`而不是`type`来支持子类. (4认同)

lov*_*sus 5

为了完整性。numpyis_sequence库中有一个实用程序(“Python 科学计算的基础包”)。

>>> from numpy.distutils.misc_util import is_sequence
>>> is_sequence((2,3,4))
True
>>> is_sequence(45.9)
False
Run Code Online (Sandbox Code Playgroud)

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

>>> is_sequence(set((1,2)))
True
>>> is_sequence("abc")
False
Run Code Online (Sandbox Code Playgroud)

该代码看起来有点像 @adrian 的(请参阅numpy git code),有点不稳定。

def is_sequence(seq):
    if is_string(seq):
        return False
    try:
        len(seq)
    except Exception:
        return False
    return True
Run Code Online (Sandbox Code Playgroud)