【问题标题】:Passing a non-iterable to list.extend ()将一个不可迭代对象传递给 list.extend ()
【发布时间】:2010-04-06 21:03:12
【问题描述】:

我正在创建一个公共方法以允许调用者将值写入设备,例如将其称为 write_vals()。

由于这些值将被实时输入,我想通过允许他们输入列表或单个值来简化用户的生活,具体取决于他们需要写入多少个值。例如:

write_to_device([1,2,3])

write_to_device(1)

我的函数想使用一个平面列表,所以我想聪明一点,编写如下代码:

input_list = []  
input_list.extend( input_val )

当用户输入一个列表时,这很有效,但当用户输入一个整数时,这会很糟糕:

TypeError: 'int' 对象不可迭代

使用 list.append() 会在传入列表时创建一个嵌套列表,这会增加展平的麻烦。

检查传入的对象的类型似乎很笨拙且非pythonic,并希望 list.extend() 接受非可迭代对象让我无处可去。因此也尝试了各种其他编码方法。

非常感谢您提出建议(请仅与编码相关)。

【问题讨论】:

  • 当您说用户输入一个列表或单个值时,这是否意味着您将他们的输入作为单个字符串接收?然后你必须将它解析为逗号吗?

标签: python list


【解决方案1】:

你可以用isinstance()函数检查传递的参数是否是一个列表。

更好的解决方案可能是支持可变数量的参数:

def write_to_device(*args):
   # |args| is now a list of all the arguments given to the function
   input_list.extend(args)

这样,即使不必将它们显式指定为列表,也可以为函数赋予多个值:

write_to_device(1)
write_to_device(1,2,3)

【讨论】:

  • 如果你想传递一个列表给 write_to_device,你可以使用 *: write_to_device(*mylist)
  • write_to_device(*args) 向用户表明不传递写入值是合法的,在这种情况下是不合法的。
  • @JS:你可以像if len(args)==0: raise TypeError('Missing arguments')这样添加支票
【解决方案2】:

你可以使用try...except...:

try:
    input_list = list(input_val)
except TypeError:
    input_list = list((input_val,))

这是pythonic。

P.S.:变量参数,如@sth proposes,要好得多,但为了完整起见,我留下这个答案。有时您不能使用可变参数。

【讨论】:

  • 我曾希望找到一个不那么冗长的解决方案,但这个解决方案效果很好。我确实喜欢你的“list((input_val,))”把戏。谢谢!
  • 如果将单个字符串传递给函数,则会中断,例如 'abc'。
【解决方案3】:

您可以使用 try 来代替检查类型,除了。不过,我很想知道比我更擅长 python 的人是如何做到这一点的。

input_list = []
try:
    input_list.extend(input_val)
except TypeError:
    input_list.append(input_val)

从错误检查的角度来看,这对我来说似乎是不完整的,但如果您知道用户只会输入单个值或列表,这将起作用。

【讨论】:

  • @Zach 感谢您的关注!
【解决方案4】:

有几种方法可以做到这一点,您可以根据自己的需要选择哪一种。

您可以尝试将参数转换为列表,并假设如果它不起作用,则应将其解释为单个参数:

def write_to_device(args):
    try:
        args = list(args)
    except TypeError:
        args = [args]

    print args

这很好用,但是如果您将字符串作为参数传递,您可能会遇到问题:

>>> write_to_device(1)
[1]
>>> write_to_device([1,2])
[1, 2]
>>> write_to_device('abc')
['a', 'b', 'c']

您可以通过使用isinstance 来检查参数是否为字符串来更正:

def write_to_device(args):
    if isinstance(args, basestring):
        args = [args]
    else:
        try:
            args = list(args)
        except TypeError:
            args = [args]

    print args

这给了你:

>>> write_to_device(1)
[1]
>>> write_to_device([1,2])
[1, 2]
>>> write_to_device('abc')
['abc']  

正如有人指出的那样,您可以允许您的函数采用任意数量的参数:

def write_to_device(*args):
    print args

这让你:

>>> write_to_device(1)
(1,)
>>> write_to_device([1,2])
([1, 2],)
>>> write_to_device('abc')
('abc',)
>>> write_to_device(*[1,2])
(1, 2)

我推荐的方法是要求将列表传递给函数:

write_to_device([1])
write_to_device([1, 2, 3])

这是简单、直接且明确的。

【讨论】:

  • 我喜欢你的第一个建议。干净优雅。用户将传递一个或一组十六进制值,因此如果他们传递一个字符串,脚本就会爆炸,这只是甜点。 ;-) 好的好的。我会检查一个字符串并优雅地失败(抱怨):-)
【解决方案5】:

根据之前的情况,我创建了这个:

def add2list(l,*args): l.extend(args)
# behaves like .extend, gets round issues of iterability     
# so simple, so powerful!

例子:

answer = 42
mylist = []
add2list(mylist,1)
add2list(mylist,2,3,'a','b','c',answer)
print mylist

结果:[1, 2, 3, 'a', 'b', 'c', 42]

【讨论】:

    猜你喜欢
    • 2021-11-08
    • 2018-10-22
    • 2012-06-22
    • 2017-05-06
    • 1970-01-01
    • 2015-09-15
    • 2013-06-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多