这是我通常所做的,以确定输入是一个列表/元组-而不是一个str。因为很多次我偶然发现错误,其中一个函数错误地传递了一个str对象,而目标函数在lst中执行x,假设lst实际上是一个列表或元组。

assert isinstance(lst, (list, tuple))

我的问题是:有没有更好的方法来实现这个目标?


当前回答

assert (type(lst) == list) | (type(lst) == tuple), "Not a valid lst type, cannot be string"

其他回答

一般来说,迭代对象的函数不仅适用于元组和列表,也适用于字符串,这是一个特性而不是缺陷。您当然可以使用isinstance或duck类型来检查参数,但为什么要这样做呢?

这听起来像是一个反问句,但事实并非如此。“为什么我要检查参数的类型?”这个问题的答案很可能是针对实际问题的解决方案,而不是感知到的问题。为什么将字符串传递给函数是一个bug ?另外:如果将字符串传递给这个函数是一个bug,那么如果将其他一些非列表/元组可迭代对象传递给它也是一个bug吗?为什么,或者为什么不?

我认为这个问题最常见的答案可能是,编写f(“abc”)的开发人员希望函数的行为就像他们编写的f([“abc”])一样。在某些情况下,保护开发人员不受自己的伤害比支持在字符串中遍历字符的用例更有意义。但我会先好好想想。

我在测试用例中这样做。

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))

没有在发电机上进行测试,我认为如果通过发电机,你会在下一次“屈服”时留下,这可能会把下游的事情搞砸。不过,这是一个unittest

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

因此,要检查list和tuple,它将是:

from typing import List, Tuple

def isit(value):
    return isinstance(value, List) or isinstance(value, Tuple)

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 a dictionary.")

在3.3版更改:将“集合抽象基类”的全局命名空间从abc移动到集合。美国广播公司(abc)模块。为了向后兼容,它们将继续在这个模块中可见,直到3.8版,它将停止工作。

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 or dictionary."
assert (type(lst) == list) | (type(lst) == tuple), "Not a valid lst type, cannot be string"