检查输入是否为字符串列表/元组或单个字符串。

76

我有一个方法,希望能够接受单个字符串(路径,但不一定存在于运行代码的机器上)或字符串列表/元组。

鉴于字符串看作字符列表,如何判断方法接收到了哪种类型?

我想接受单个标准或Unicode字符串,以及多个列表或元组,因此isinstance似乎不是答案,除非我错过了它的巧妙用法(例如利用共同祖先类?)

Python版本为2.5


3
样例输入/输出使这些问题更容易解释。 - David Berger
这里的简单答案 https://dev59.com/O3NA5IYBdhLWcg3wh-cC#26797718 -- 由于py2-3的变化而不明显。 - sorin
9个回答

86

你可以使用以下方法检查变量是否为字符串或Unicode字符串:

  • Python 3:
    isinstance(some_object, str)
  • Python 2:
    isinstance(some_object, basestring)

这将对字符串和unicode字符串都返回True

如果您使用的是Python 2.5,您可以像以下这样做:

if isinstance(some_object, basestring):
    ...
elif all(isinstance(item, basestring) for item in some_object): # check iterable for stringness of all items. Will raise TypeError if some_object is not iterable
    ...
else:
    raise TypeError # or something along that line

Stringness可能不是一个词,但我希望你能理解这个概念。


啊哈!我想肯定有一些共同的祖先,只是我找不到参考资料... - mavnn
12
Python 3 已经移除了 basestring。请改用 str(如果你有字节,请使用 bytes)来替代。 - spazm
1
使用 six 库,您可以使用 six.string_types 替换 strbasestring 以实现兼容性。 - Dakota
由于性能原因,在生产中应避免使用isinstancetype。应改用鸭子类型检查。 - bardosd

34

isinstance 是一个选项:

In [2]: isinstance("a", str)
Out[2]: True

In [3]: isinstance([], str)
Out[3]: False

In [4]: isinstance([], list)
Out[4]: True

In [5]: isinstance("", list)
Out[5]: False

20

类型检查:

def func(arg):
    if not isinstance(arg, (list, tuple)):
        arg = [arg]
    # process

func('abc')
func(['abc', '123'])

可变参数:

def func(*arg):
    # process

func('abc')
func('abc', '123')
func(*['abc', '123'])

6

由于我喜欢保持简单,这里提供了兼容2.x和3.x的最短表单:

# trick for py2/3 compatibility
if 'basestring' not in globals():
   basestring = str

v = "xx"

if isinstance(v, basestring):
   print("is string")

5
>>> type('abc') is str
True
>>> type(['abc']) is str
False

这段代码兼容Python 2和3。


今天来看,这似乎是最简洁和清晰的方式。 - user8554766
使用Python2,这将会忽略Unicode字符串,这就是为什么Python2示例使用basestring的原因。例如:type(u'abc') is str -> False - spazm

3

使用isinstance(arg, basestring)检查类型。


3

我很惊讶没有人给出了鸭子类型的答案,而是给出了不明确或高度依赖于类型或版本的答案。同时,被接受的答案不幸地在Python 2和3中有不同的代码。Python使用并鼓励鸭子类型,所以(比Sorin的“最短形式”多一行,但不是鸭子类型),我建议使用以下代码:

def is_str(v):
    return hasattr(v, 'lower')

你可以使用任何其他属性(记住引号),这样,使用你的软件的客户端代码可以发送任何类型的字符串,只要它具有你的软件所需的接口即可。对于其他类型,鸭子类型在这种方式下更加有用,但通常是最好的方式。

或者你还可以这样做(或者一般情况下检查AttributeError并采取其他措施):

def is_str(v):
    try:
        vL = v.lower()
    except AttributeError:
        return False
    return True

但是,如果你正在编写一个 is_str 函数,那么这真的是鸭子类型吗?我想是的,但如果你需要使用 .lower(),那就直接使用 .lower() 并捕获潜在的 AttributeError。没有必要浪费时间先检查。问题是,有时您不会调用任何特定的字符串方法。例如,也许您直接将字符串传递给另一个函数。在理想的情况下,那个函数会为非字符串引发异常,但您并不总是能够依赖它。有时,isinstance() 确实是理想的解决方案。 - Dominick Pastore
@DominickPastore 是的,您不会使用我的函数(但它是一个例子,并直接回答了问题)。在此之前我说过“或者你可以...”,而不是使用该函数进行鸭子类型。正如您所说的那样,那将是将我的函数体(或执行您正在说的内容或在函数之前执行我之前说过的内容)内联并形成代码周围的代码。我不同意关于isinstance的说法-鸭子类型的重点以及Python使用它的原因是当一个对象做你想做的事情时不要出现错误,而是处理单个异常-如果它“像一只鸭子一样呱呱叫”,那么它就是一只鸭子(或者您可以依赖它用于特定情况)。 - Poikilos
请注意,我说的是将“函数体”放在一行内,而不是定义。您只需使用其中的代码而不是定义它,然后您可以修改代码以执行特定于您的代码的操作,而不是函数所执行的操作。 - Poikilos

1

你考虑过使用 varargs 语法吗?我不太确定这是否是你所问的,但像 this question 这样的东西是否符合你的要求?


那不会强制调用者指定发送哪个吗?如果可能的话,我更愿意避免这种情况。 (而且我也很想知道是否有一种优雅的方式来实现我想要做的事情...) - mavnn

-2

你不能这样做吗:

(i == list (i) or i == tuple (i))

它会回复输入是元组还是列表。唯一的问题是,它不能正确处理只包含一个变量的元组。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接