好吧,我承认我没有很好地提出这个问题。我会更新我的问题更准确。
我正在编写一个以列表作为参数的函数。我想检查列表的长度,以便我可以遍历列表。
我遇到的问题是当列表只有一个条目时,len(myList)返回该条目的长度(字符串的长度)而不是列表的长度== 1。
如果我强制将参数解析为单个值列表['val'],我可以解决这个问题。但我更喜欢我的API允许用户解析值或值列表。
示例:
def myMethod(self,dataHandle, data,**kwargs):
comment = kwargs.get('comment','')
_dataHandle= list()
_data = list()
_dataHandle.append(dataHandle)
_data.append(data)
for i in range(_dataHandle):
# do stuff.
我希望能够通过
调用我的方法myMethod('ed', ed.spectra,comment='down welling irradiance')
或
myMethod(['ed','lu'] , [ed.spectra,lu.spectra] , comments = ['downwelling', upwelling radiance'])
非常感谢任何帮助。解析['ed']似乎不是什么大不了的事,但到目前为止它破坏了我的API的一致性。
答案 0 :(得分:5)
由单个项组成的列表的正确python语法是[ 'ed' ]
。
您对list('ed')
所做的是要求python将'ed'
转换为列表。这是python中的一致隐喻:当你想将某些东西转换为字符串时,你会说str(some_thing)
。你用来使list('ed')
返回一个只有字符串'ed'的列表的任何hack都会破坏python的内部隐喻。
当python看到list(x)
时,它会尝试将x
转换为列表。如果x
是可迭代的,它会或多或少地与此相同:
def make_list(x):
ret_val = []
for item in x:
ret_val.append(item)
return ret_val
因为你的字符串'ed'是可迭代的,所以python会将它转换为长度为2的列表:[ 'e', 'd' ]
。
在这种情况下,最干净的惯用python可能是让你的函数接受可变数量的参数,所以代替这个
def my_func(itemList):
...
你会这样做
def my_func(*items):
...
而不是像这样称呼它
my_func(['ed','lu','lsky'])
你会这样称呼它:
my_func('ed', 'lu', 'lsky')
通过这种方式,您可以接受任意数量的参数,并且您的API将非常干净。
答案 1 :(得分:3)
您可以询问您的变量是否为list
:
def my_method(my_var):
if isinstance(my_var, list):
for my_elem in my_var:
# do stuff with my_elem
else: # my_var is not iterable
# do stuff with my_var
编辑:另一种选择是尝试迭代它,如果它失败(加注和异常),你认为是一个单独的元素:
def my_method(my_var):
try:
for my_elem in my_var:
# do stuff with my_elem
except TypeError: # my_var is not iterable
# do_stuff with my_var
关于第二个选项的好处是,它不仅可以作为第一个选项用于list
,还可以用于任何可迭代的(string
s,set
s ,dict
等等。)
答案 2 :(得分:1)
如果您希望将列表 ,您确实需要将字符串放在列表中
修改强>
我看到在某些时候字符串前面有一个list
。与您的想法相反,list
不会创建一个项目的列表。它在字符串对象上调用__iter__
并迭代每个项目。因此它创建了一个字符列表。
希望这更清楚:
>>> print(list('abc'))
['a', 'b', 'c']
>>> print(list(('abc',)))
['abc']
答案 3 :(得分:0)
list('ed')
不会创建包含单个元素'ed'
的列表。 list(x)
通常不会创建包含单个元素x
的列表。事实上,如果你一直在使用数字而不是字符串(或其他任何不可迭代的东西),那么这对你来说是显而易见的:
>>> list('ed')
['e', 'd']
>>> list(3)
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
list(3)
TypeError: 'int' object is not iterable
>>
所以你实际上是将一个包含多个元素的列表传递给你的方法,这就是len
返回大于1的原因。它没有返回列表第一个元素的长度。
对于允许传递单个项目或列表的方法,您必须先进行一些检查以查看它是否是单个项目,如果是创建包含myVar = [myVar]
的列表,然后运行你的循环。
然而,这种API实现和使用很棘手,我不推荐它。检查您是否已获得集合或项目的最自然方式是查看myVar
是否可迭代。但是,对于可迭代的字符串,这会失败。不幸的是,字符串跨越集合和单个数据项之间的边界;我们经常将它们用作包含“文本块”的数据项,但它们也是字符集合,Python允许它们这样使用。
这样的API也可能会让你有一天意外地传递一个你认为是单一事物的列表,并期望该方法将其视为一件事。但它是一个列表,所以突然代码的行为会有所不同。
它还提出了有关您如何处理其他数据类型的问题。字典不是列表,但可以迭代。如果您将字典作为myVar
传递,它是否会被视为包含单个字典的列表,还是会迭代字典的键?一个元组怎么样?实现__iter__
的自定义类怎么样?如果实现__iter__
的自定义类尝试“类似字符串”而不是“类似列表”会怎么样?
如果来电者猜错/记得错误,所有这些问题都会带来惊喜。编程导致错误时会感到惊讶。恕我直言,最好只使用额外的两个字符输入([
和]
),让你的API干净简洁。
答案 4 :(得分:0)
我经常遇到同样的问题。正如您在使用“_dataHandle = list()”行一样,从空列表构建列表在Python中很常见,因为我们不会提前保留内存。因此,通常情况是列表的状态将从空转换为一个元素,转换为多个元素。正如您所发现的,Python将一个元素与多个元素的索引视为不同。如果您可以使用列表推导,那么解决方案可以很简单。而不是:
for i in range(_dataHandle):
使用:
for myvar in _dataHandle:
在这种情况下,如果只有一个元素,则循环只会按预期迭代一次。