Python,允许将单个字符串和字符串列表传递给函数

Ant*_*rdi 2 python string list

我有一个调用 REST API 的函数。其中一个参数是以逗号分隔的名称列表。为了生成它,我这样做:

','.join(names)
Run Code Online (Sandbox Code Playgroud)

但是,我也希望允许用户提供一个名称。问题是,names = ERII例如,如果它导致['E', 'R', 'I', 'I'],但我需要它来['ERII']代替。

现在,我可以强制用户输入一个只有一个值的列表(names=['ERRI']names=('ERII',)。我更愿意允许用户提供一个字符串。有没有一种聪明的方法来做到这一点,而无需if else检查提供的值是否为Iterable?

Alos,我不确定这里的最佳实践是什么,强制提供列表还是允许单个字符串?

aba*_*ert 16

可以是事物或可迭代的参数或事物是代码气味。当事物是字符串时更糟,因为字符串可迭代的,甚至是序列(因此您的测试isinstance(names, Iterable)会做错事)。

Python stdlib 确实有一些这样的情况——最臭名昭著的str.__mod__——但大多数都在另一个方向上犯了错误,明确要求一个元组而不是任何可迭代的,而且大多数被认为是错误的,或者至少是不会的事情不会被添加到今天的语言中。有时它仍然是最好的答案,但气味应该让你在做之前思考。

我不确切知道您的用例是什么,但我怀疑这会好得多:

def spam(*names):
    namestr = ','.join(names)
    dostuff(namestr)
Run Code Online (Sandbox Code Playgroud)

现在用户可以这样调用它:

spam('eggs')
spam('eggs', 'cheese', 'beans')
Run Code Online (Sandbox Code Playgroud)

或者,如果他们碰巧有一个列表,这仍然很容易:

spam(*ingredients)
Run Code Online (Sandbox Code Playgroud)

如果这不合适,另一种选择是关键字,甚至可能是仅关键字参数:

def spam(*, name=None, names=None):
    if name and names:
        raise TypeError('Not both!')
    if not names: names = [name]
Run Code Online (Sandbox Code Playgroud)

但是如果最好的设计真的是一个字符串或一个(非字符串)可迭代的字符串,或者一个字符串或一个字符串元组,那么标准的方法就是类型切换。它可能看起来有点难看,但它提醒人们注意这样一个事实:你正在做你正在做的事情,而且它以最惯用的方式做。

def spam(names):
    if isinstance(names, str):
        names = [names]
    dostuff(names)
Run Code Online (Sandbox Code Playgroud)