2011-11-29 34 views
0

好吧我承认我没有很好地问这个问题。我会更新我的问题更加精确。列表有单个值时Python列表的长度

我正在写一个函数,它将一个列表作为参数。我想检查列表的长度,以便我可以遍历列表。

我的问题是,当列表只有一个条目,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的一致性。

+2

您期待'myVar ='ed''创建一个大小为1的列表吗? – GWW

+2

这很多都是无效的Python。 –

+0

只记得(或者学习)Python不是Java ... – JBernardo

回答

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 S,作为第一位的,但什么是迭代(string S,set S,dict S等)

+1

这不是静态检查的地方...如果你真的想检查异常情况(字符串不可迭代) – JBernardo

+0

在我发布之前没有看到你的答案;基本上是一样的想法,但是,这是更好的。本森的答案虽然更好。 –

+0

是的,我认为这是迄今为止最好的解决方案。我过去是如何处理它的。但这意味着我必须编写两段代码。一个用于处理这个列表,另一个用于处理这个列表。我希望有一个MATLAB风格的解决方案。每一件事物都是一个矩阵,即使1x1也是一个矩阵。 – Caustic

1

你确实需要把你的字符串在列表如果你希望它被视为像列表

编辑

我看到,在某些时候有一个list在字符串前面。 list与您可能认为的相反,不会创建一个项目的列表。它在字符串对象上调用__iter__并遍历每个项目。因此它制作了一个字符列表。

希望这使得它更清晰:

>>> print(list('abc')) 
['a', 'b', 'c'] 
>>> print(list(('abc',))) 
['abc'] 
+0

是的,我忘了添加我使用list()看我的编辑。欢呼声 – Caustic

+1

我不认为这是做你认为的事情。 –

5

正确包含单个项目的列表的Python语法是[ 'ed' ]

你在做什么list('ed')是要求Python将'ed'转换为列表。这是python中的一个隐喻:当你想把某些东西转换成字符串时,你说str(some_thing)。任何黑客你会使用list('ed')返回一个列表,只是字符串'ed'会破坏python的内部隐喻。

当python看到list(x)时,它会尝试将x转换为列表。如果x是迭代的,它的东西这或多或少相当于:

def make_list(x): 
    ret_val = [] 
    for item in x: 
    ret_val.append(item) 
    return ret_val 

因为你的字符串“编”是迭代的,蟒蛇将其转换为长度为2的列表:[ 'e', 'd' ]

在这种情况下,清洁的习惯蟒蛇可能是有你的函数接受可变数量的参数,所以不是这个

def my_func(itemList): 
    ... 

你应该这样做

def my_func(*items): 
    ... 

,取而代之的这样称呼它

my_func(['ed','lu','lsky']) 

你会这样称呼它:

my_func('ed', 'lu', 'lsky') 

通过这种方式,您可以接受任意数量的参数,并且您的API将会非常干净。

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干净简单。

+0

谢谢Ben,这是一个很好的描述。我可能不得不忍受额外的字符。我避开它的原因是,我不会使用这个代码。对于一些对编码知之甚少的人来说,他们迄今为止所使用的语法更接近我一直试图实现的API。感谢您花时间回复这么多细节 – Caustic

+0

@苛刻的我看到了困境;但如果您的用户是编写代码的非编码人员,我认为这样做更有理由让事情尽可能简单。当“魔术”试图让自己变得更好时,非编码人员完全没有办法处理它,并找出改变目标的方法。你只需要给他们非常明确的说明,其中有很多具体的例子和他们可以适应的“食谱”。 – Ben

0

我经常遇到同样的问题。正如您对“_dataHandle = list()”行所做的那样,从空列表构建列表在Python中很常见,因为我们不提前预留内存。因此,列表状态通常会从空到一个元素转换为多个元素。正如您发现的那样,Python将一个元素与多个元素的索引视为不同。如果您可以使用列表理解,那么解决方案可以很简单。相反的:

for i in range(_dataHandle): 

使用:

for myvar in _dataHandle: 

在这种情况下,如果只有一个元素,循环迭代唯一一次你所期望的。

相关问题