这是我通常所做的,以确定输入是list
/ tuple
- 而不是str
。因为很多次我偶然发现函数错误地传递str
对象的错误,而目标函数假设for x in lst
实际上是lst
或{{1} }}
list
我的问题是:有没有更好的方法来实现这一目标?
答案 0 :(得分:322)
仅在python 2中(不是python 3):
assert not isinstance(lst, basestring)
实际上是你想要的,否则你会错过很多像列表一样的东西,但不是list
或tuple
的子类。
答案 1 :(得分:168)
请记住,在Python中我们想要使用“duck typing”。因此,任何像列表一样的东西都可以被视为列表。因此,不要检查列表的类型,只要查看它是否像列表一样。
但字符串也像列表一样,而且往往不是我们想要的。有时甚至是一个问题!因此,请明确检查字符串,然后使用duck typing。
这是我写的一个有趣的功能。它是repr()
的特殊版本,可在尖括号中打印任何序列('<','>')。
def srepr(arg):
if isinstance(arg, basestring): # Python 3: isinstance(arg, str)
return repr(arg)
try:
return '<' + ", ".join(srepr(x) for x in arg) + '>'
except TypeError: # catch when for loop fails
return repr(arg) # not a sequence so just return repr
总的来说,这是干净而优雅的。但isinstance()
检查那里做了什么?那是一种黑客攻击。但这很重要。
此函数以递归方式调用自身,就像列表一样。如果我们没有特别处理字符串,那么它将被视为一个列表,并一次拆分一个字符。但是,递归调用会尝试将每个字符视为一个列表 - 它会起作用!即使是单字符字符串也可以作为列表使用!该函数将继续递归调用自身直到堆栈溢出。
像这样的函数依赖于每个递归调用来分解要完成的工作,必须使用特殊情况字符串 - 因为你不能分解低于单字符字符串级别的字符串,并且即使是一个单字符的字符串就像一个列表。
注意:try
/ except
是表达我们意图的最简洁方式。但是如果这段代码在某种程度上是时间关键的,我们可能想用某种测试来替换它,看看arg
是否是一个序列。我们应该测试行为,而不是测试类型。如果它有一个.strip()
方法,它是一个字符串,所以不要把它当作一个序列;否则,如果它是可索引的或可迭代的,那就是一个序列:
def is_sequence(arg):
return (not hasattr(arg, "strip") and
hasattr(arg, "__getitem__") or
hasattr(arg, "__iter__"))
def srepr(arg):
if is_sequence(arg):
return '<' + ", ".join(srepr(x) for x in arg) + '>'
return repr(arg)
编辑:我最初编写了上面的__getslice__()
检查,但我注意到在collections
模块文档中,有趣的方法是__getitem__()
;这是有道理的,这就是你如何索引一个对象。这似乎比__getslice__()
更基础,所以我改变了上述内容。
答案 2 :(得分:118)
H = "Hello"
if type(H) is list or type(H) is tuple:
## Do Something.
else
## Do Something.
答案 3 :(得分:61)
对于Python 2:
import collections
if isinstance(obj, collections.Sequence) and not isinstance(obj, basestring):
print "obj is a sequence (list, tuple, etc) but not a string or unicode"
对于Python 3:
import collections.abc
if isinstance(obj, collections.abc.Sequence) and not isinstance(obj, str):
print("obj is a sequence (list, tuple, etc) but not a string or unicode")
在版本3.3中更改:将集合抽象基类移动到collections.abc模块。为了向后兼容,它们将继续在此模块中可见,直到3.8版本将停止工作。
答案 4 :(得分:31)
Python的PHP风格:
def is_array(var):
return isinstance(var, (list, tuple))
答案 5 :(得分:10)
一般来说,迭代对象的函数对字符串以及元组和列表起作用的事实比bug更具特色。你肯定可以使用isinstance
或鸭子打字来检查一个参数,但你为什么要这样做?
这听起来像是一个修辞问题,但事实并非如此。答案为“我为什么要检查参数的类型?”可能会建议解决真正的问题,而不是感知问题。将字符串传递给函数时,为什么会出现错误?另外:如果将字符串传递给此函数时出现错误,如果将其他非list / tuple iterable传递给它,它是否也是一个错误?为什么,或为什么不呢?
我认为这个问题最常见的答案可能是编写f("abc")
的开发人员希望该函数的行为就像编写f(["abc"])
一样。在某种情况下,保护开发人员更有意义,而不是支持迭代字符串中字符的用例。但我首先想到的很长很难。
答案 6 :(得分:7)
请尝试以获取可读性和最佳做法:
Python2
import types
if isinstance(lst, types.ListType) or isinstance(lst, types.TupleType):
# Do something
Python3
import typing
if isinstance(lst, typing.List) or isinstance(lst, typing.Tuple):
# Do something
希望它有所帮助。
答案 7 :(得分:6)
str
对象没有__iter__
属性
>>> hasattr('', '__iter__')
False
所以你可以做检查
assert hasattr(x, '__iter__')
这也会为任何其他不可迭代的对象引发一个很好的AssertionError
。
编辑: 正如Tim在评论中提到的,这只适用于python 2.x,而不是3.x
答案 8 :(得分:5)
这不是为了直接回答OP,但我想分享一些相关的想法。
我对上面的@steveha回答非常感兴趣,这似乎给出了鸭子打字似乎打破的例子。然而,第二个想法是,他的例子表明鸭子打字很难符合,但不表明str
值得进行任何特殊处理。
毕竟,非str
类型(例如,维护一些复杂递归结构的用户定义类型)可能会导致@steveha srepr
函数导致无限递归。虽然这是不太可能的,但我们不能忽视这种可能性。因此,我们应该澄清在无限递归结果时我们希望str
做什么,而不是srepr
中的特殊套srepr
。
似乎一种合理的方法是在srepr
list(arg) == [arg]
时刻打破递归。事实上,这将完全解决str
的问题,而没有任何isinstance
。
但是,一个非常复杂的递归结构可能会导致list(arg) == [arg]
永远不会发生的无限循环。因此,虽然上述检查很有用,但还不够。我们需要对递归深度进行严格限制。
我的观点是,如果你计划处理任意参数类型,通过鸭子输入处理str
远比处理你可能(理论上)遇到的更一般的类型容易得多。因此,如果您觉得需要排除str
个实例,则应该要求该参数是您明确指定的少数几种类型之一的实例。
答案 9 :(得分:3)
我找到了一个名为is_sequence in tensorflow的函数。
def is_sequence(seq):
"""Returns a true if its input is a collections.Sequence (except strings).
Args:
seq: an input sequence.
Returns:
True if the sequence is a not a string and is a collections.Sequence.
"""
return (isinstance(seq, collections.Sequence)
and not isinstance(seq, six.string_types))
我已经确认它符合您的需求。
答案 10 :(得分:2)
我在我的测试用例中这样做。
def assertIsIterable(self, item):
#add types here you don't want to mistake as iterables
if isinstance(item, basestring):
raise AssertionError("type %s is not iterable" % type(item))
#Fake an iteration.
try:
for x in item:
break;
except TypeError:
raise AssertionError("type %s is not iterable" % type(item))
在发电机上未经测试,我认为如果传入发电机,你会被留在下一个'收益',这可能会使下游的事情变得棘手。但话说回来,这是一个'单元测试'
答案 11 :(得分:1)
最简单的方法......使用any
和isinstance
>>> console_routers = 'x'
>>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)])
False
>>>
>>> console_routers = ('x',)
>>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)])
True
>>> console_routers = list('x',)
>>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)])
True
答案 12 :(得分:1)
以“鸭子打字”的方式,
try:
lst = lst + []
except TypeError:
#it's not a list
或
try:
lst = lst + ()
except TypeError:
#it's not a tuple
分别。这样可以避免isinstance
/ hasattr
的内省。
您也可以反之亦然:
try:
lst = lst + ''
except TypeError:
#it's not (base)string
所有变体实际上都不会更改变量的内容,而是暗指重新分配。我不确定在某些情况下这是否不受欢迎。
有趣的是,如果+=
是 list (不是,则在任何情况下使用“就地”分配TypeError
都不会引发lst
>元组)。这就是为什么以这种方式完成分配的原因。也许有人可以阐明原因。
答案 13 :(得分:1)
鸭式打字的另一种版本,可以帮助区分字符串对象和其他序列对象。
类似字符串的对象的字符串表示形式是字符串本身,因此您可以检查是否从str
构造函数中获得了相等的对象:
# If a string was passed, convert it to a single-element sequence
if var == str(var):
my_list = [var]
# All other iterables
else:
my_list = list(var)
这应该适用于与str
兼容的所有对象以及所有可迭代的对象。
答案 14 :(得分:0)
就这样做
if type(lst) in (list, tuple):
# Do stuff
答案 15 :(得分:0)
Python 3具有以下功能:
from typing import List
def isit(value):
return isinstance(value, List)
isit([1, 2, 3]) # True
isit("test") # False
isit({"Hello": "Mars"}) # False
isit((1, 2)) # False
因此要同时检查列表和元组,应该是:
from typing import List, Tuple
def isit(value):
return isinstance(value, List) or isinstance(value, Tuple)
答案 16 :(得分:0)
assert (type(lst) == list) | (type(lst) == tuple), "Not a valid lst type, cannot be string"
答案 17 :(得分:-3)
在python> 3.6
中import collections
isinstance(set(),collections.abc.Container)
True
isinstance([],collections.abc.Container)
True
isinstance({},collections.abc.Container)
True
isinstance((),collections.abc.Container)
True
isinstance(str,collections.abc.Container)
False
答案 18 :(得分:-6)
我倾向于这样做(如果我真的,真的必须这样做):
for i in some_var:
if type(i) == type(list()):
#do something with a list
elif type(i) == type(tuple()):
#do something with a tuple
elif type(i) == type(str()):
#here's your string