pythonic方式将变量转换为列表

hoj*_*oju 17 python arguments list

我有一个函数,其输入参数可以是元素或元素列表.如果这个参数是单个元素,那么我将它放在一个列表中,这样我就可以以一致的方式迭代输入.

目前我有这个:

def my_func(input):
    if not isinstance(input, list): input = [input]
    for e in input:
        ...
Run Code Online (Sandbox Code Playgroud)

我正在使用现有的API,因此无法更改输入参数.使用isinstance()感觉hacky,所以有一个正确的方法来做到这一点?

Ale*_*lli 14

通常情况下,字符串(plain和unicode)是你想要作为"单个元素"的唯一迭代 - basestring内置存在特定于让你测试任何一种字符串isinstance,所以对于那个特殊情况它是非常难以理解的;-).

所以我对最常见案例的建议方法是:

  if isinstance(input, basestring): input = [input]
  else:
    try: iter(input)
    except TypeError: input = [input]
    else: input = list(input)
Run Code Online (Sandbox Code Playgroud)

这是将每个可迭代的EXCEPT字符串直接作为列表处理,将字符串和数字以及其他非迭代作为标量(将其规范化为单项列表)的方法.

我明确地列出了各种迭代的列表,所以你知道你可以进一步执行各种列表技巧 - 排序,迭代不止一次,添加或删除项目以方便迭代等,所有这些都不需要改变ACTUAL输入列表(如果列表确实是;-).如果您只需要一个简单的for循环,那么最后一步是不必要的(如果输入是一个巨大的打开文件,实际上没有用),我建议使用辅助生成器:

def justLoopOn(input):
  if isinstance(input, basestring):
    yield input
  else:
    try:
      for item in input:
        yield item
    except TypeError:
      yield input
Run Code Online (Sandbox Code Playgroud)

现在,在你需要这种参数规范化的每一个函数中,你只需使用:

 for item in justLoopOn(input):
Run Code Online (Sandbox Code Playgroud)

您可以使用辅助规范化功能,即使在另一种情况下(您需要一个真正的列表以用于进一步的恶意目的); 实际上,在这种(更罕见的)情况下,您可以这样做:

 thelistforme = list(justLoopOn(input))
Run Code Online (Sandbox Code Playgroud)

所以(不可避免地)有点毛茸茸的归一化逻辑只是在一个地方,就像应该的那样! - )

  • `try` /`iter(x)`/`except`并不是特别贵.AND,`iter(x)`成功为某些对象w/o`__iter__`(例如,一个对象w /一个合适的`__getitem__`接受数字键,但没有`__iter__`). (3认同)

Pau*_*McG 10

我喜欢Andrei Vajna的建议hasattr(var,'__iter__').请注意一些典型Python类型的结果:

>>> hasattr("abc","__iter__")
False
>>> hasattr((0,),"__iter__")
True
>>> hasattr({},"__iter__")
True
>>> hasattr(set(),"__iter__")
True
Run Code Online (Sandbox Code Playgroud)

这具有将字符串视为不可迭代的附加优点 - 字符串是灰色区域,因为有时您希望将它们视为元素,其他时候将其视为字符序列.

请注意,在Python 3中,str类型确实具有该__iter__属性,但这不起作用:

>>> hasattr("abc", "__iter__")
True
Run Code Online (Sandbox Code Playgroud)