换句话说,我想知道参数X是序列还是我需要将其转换为序列以避免后续特殊情况处理。我可以这样做:
type(X) in (list, tuple)
但是可能存在其他我不知道的序列类型,并且没有通用的基类。-N. 编辑:请参见下面的“答案”,了解为什么大多数答案都无法帮助我。也许您有更好的建议。
type(X) in (list, tuple)
但是可能存在其他我不知道的序列类型,并且没有通用的基类。从2.6开始,请使用抽象基类。
>>> import collections
>>> isinstance([], collections.Sequence)
True
>>> isinstance(0, collections.Sequence)
False
import abc
import collections
class Atomic(object):
__metaclass__ = abc.ABCMeta
@classmethod
def __subclasshook__(cls, other):
return not issubclass(other, collections.Sequence) or NotImplemented
Atomic.register(basestring)
assert isinstance("hello", Atomic) == True
class Atomic(metaclass=abc.ABCMeta):
@classmethod
def __subclasshook__(cls, other):
return not issubclass(other, collections.Sequence) or NotImplemented
Atomic.register(str)
with_metaclass()
函数相同。class _AtomicBase(object):
@classmethod
def __subclasshook__(cls, other):
return not issubclass(other, collections.Sequence) or NotImplemented
class Atomic(abc.ABCMeta("NewMeta", (_AtomicBase,), {})):
pass
try:
unicode = unicode
except NameError: # 'unicode' is undefined, assume Python >= 3
Atomic.register(str) # str includes unicode in Py3, make both Atomic
Atomic.register(bytes) # bytes will also be considered Atomic (optional)
else:
# basestring is the abstract superclass of both str and unicode types
Atomic.register(basestring) # make both types of strings Atomic
在2.6版本之前,operator
模块中有类型检查器。
>>> import operator
>>> operator.isSequenceType([])
True
>>> operator.isSequenceType(0)
False
- Gregg Lindassert operator.isSequenceType("hello") == True (正如其他地方指出的那样,字符串是序列,我相信Coady也知道...原始问题规格不足。)
def to_sequence(arg):
'''
determine whether an arg should be treated as a "unit" or a "sequence"
if it's a unit, return a 1-tuple with the arg
'''
def _multiple(x):
return hasattr(x,"__iter__")
if _multiple(arg):
return arg
else:
return (arg,)
>>> to_sequence("a string")
('a string',)
>>> to_sequence( (1,2,3) )
(1, 2, 3)
>>> to_sequence( xrange(5) )
xrange(5)
这并不能保证处理所有类型,但它可以很好地处理你提到的情况,并且对大多数内置类型应该能做到正确处理。
使用时,请确保接收此输出的任何内容都可以处理可迭代对象。
所以序列不同于可迭代对象。我认为序列必须实现__getitem__
,而可迭代对象必须实现__iter__
。例如,字符串是序列,不实现__iter__
,xrange对象是序列,不实现__getslice__
。
但从您想要做的事情来看,我不确定您是否想要序列,而更多地是想要可迭代对象。因此,如果您不想使用字符串等,请使用hasattr("__iter__", X)
,而不是hasattr("__getitem__", X)
。
在我看来,Python 的做法是将列表作为 *list 传递。例如:
myfunc(item)
myfunc(*items)
myfunc(*items)
会传递一个 items 列表的元组。 - martineautry:
it = iter(X)
# Iterable
except TypeError:
# Not iterable
如果您需要确保它是可重启或随机访问序列(即不是生成器等),那么这种方法将不足够。
正如其他人所指出的,字符串也是可迭代的,因此如果您需要排除它们(特别是在通过项进行递归时很重要,因为list(iter('a'))再次给出['a']),则可能需要使用以下方法来明确地排除它们:
if not isinstance(X, basestring)
str
被视为序列(可迭代,具有 __getitem__
等特性),但通常被视为单个项。我认为我会检查对象是否具有某些指示它是序列的方法。不确定是否有官方定义可以说明什么构成序列。我能想到最好的是,它必须支持切片。因此,你可以这样说:
is_sequence = '__getslice__' in dir(X)
你可能还需要检查一下你将要使用的特定功能。
正如 pi 在评论中指出的那样,一个字符串是一个序列,但你可能不想把它当作一个序列来处理。你可以添加一个显式测试,检查类型是否不是 str。
def is_iterable(x):
if type(x) == str:
return False
try:
iter(x)
return True
except TypeError:
return False
修订答案:
我不知道你所说的“序列”是否与 Python 手册中所称的“序列类型”相匹配,但如果是的话,你应该寻找 __Contains__ 方法。这是 Python 用来实现检查“if something in object:”的方法。
if hasattr(X, '__contains__'):
print "X is a sequence"
我的原始回答:
我会检查你收到的对象是否实现了迭代器接口:
if hasattr(X, '__iter__'):
print "X is a sequence"
对我来说,这是最接近你对序列定义的匹配,因为它允许你做像这样的事情:
for each in X:
print each
__contains__
适用于容器类型,序列类型必须实现 __len__
和 __getitem__
,请参见此处:https://docs.python.org/zh-cn/3/library/collections.abc.html。 - Stan