81

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

4

7 回答 7

93

iter(x)将引发一个TypeErrorifx不能被迭代 - 但该检查“接受”集合和字典,尽管它“拒绝”其他非序列,例如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.

于 2010-05-30T00:46:43.270 回答
13

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

>>> import collections
>>> isinstance(myObject, collections.Sequence)
True

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

>>> import collections.abc
>>> isinstance(myObject, collections.abc.Sequence)
True

但是,这不适用于实现但不(因为它们应该)子类的鸭子__len__()类型__getitem__()序列collections.Sequence。但它适用于所有内置的 Python 序列类型:列表、元组、字符串等。

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

于 2019-02-09T22:30:05.070 回答
8

由于 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。

于 2015-06-25T07:00:44.727 回答
4

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

def isSequence(obj):
    return type(obj) in [str, unicode, list, tuple, buffer, xrange]
于 2010-05-30T01:03:12.767 回答
3

为了完整起见。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
于 2020-08-18T09:18:32.230 回答
-3

为什么问为什么

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

def haslength(seq):
    try:
        len(seq)
    except:
        return False
    return True
于 2012-08-26T03:35:13.123 回答
-6

你为什么做这个?这里的正常方法是要求某种类型的事物(序列或数字或类似文件的对象等),然后在不检查任何内容的情况下使用它。在 Python 中,我们通常不使用类来承载语义信息,而只是使用定义的方法(这称为“鸭子类型”)。我们也更喜欢我们确切知道会发生什么的 API;如果要更改函数的工作方式,请使用关键字参数、预处理或定义另一个函数。

于 2010-05-30T00:58:53.580 回答