2013-02-07 24 views
0

当调用一个接受列表的函数时,谁负责(调用者 - 用户或被调用函数)以确保它是list而不是generator列表和发生器 - 呼叫者或功能责任

一个例子:

>>> def print_collection(coll): 
...  for element in coll: 
...   print element 

>>> def print_collection_twice(coll): 
...  print_collection(coll) 
...  print_collection(coll) 

有了一个名单,将没有惊喜工作:

>>> print_collection_twice([x*2 for x in xrange(3)]) 
0 
2 
4 
0 
2 
4 

并配有发电机,显然只打印一次,这可能会导致一个讨厌的错误:

>>> print_collection_twice((x*2 for x in xrange(3))) 
0 
2 
4 

什么是最佳实践他回覆?一个函数是否应该假设一个列表,并且一个用户可以提供list,或者该函数的起始位置始终是real_list = list(input_list),这样用户就不会在乎了吗?

编辑

知道如何检查元素和assert的类型,我的问题是相当高的水平

回答

3

任何一种方法都是可行的。这是函数的职责文档它想要什么类型的参数,以及调用者负责传递符合文档的参数。如果函数说明它需要一个列表并且你传递了一个生成器,那么它不能保证它能够工作。

真正的问题是功能应该它想要的,答案是它应该说它只是它所需要的,而不是更多。所以如果你真正需要的是一个可迭代的,那么不要说你需要一个列表。一般来说,如果你的函数需要使用通用迭代器所没有的列表的特性(例如索引),那么它应该只使用这些特性,并且如果有人通过一个不参与的参数支持他们。如果你的功能不需要这些功能,那么它不需要列表。

你的例子有点不现实,因为它所做的只是打印参数。在现实生活中,除了消费迭代器之外,你几乎总是需要做一些事情,而“你需要做的事情”的性质将会澄清你应该接受什么样的论证。不过,对于您的具体示例,我会说是,请拨打list(内部print_collection_twice,而不是print_collection)。原因是print_collection_twice想要多次使用这些数据,这对于通用迭代是不可能的。

0

在我oppinion这取决于函数中的应用程序。重要的是,你文档你的函数是否只接受列表或迭代器。在函数内部调用明确的list()可能会导致长列表的额外开销,如果您只想遍历列表/生成器一次,则不需要这样做。

+1

你可以试试'LEN(参数)',看看它是否会抛出一个错误。 这没有太多的开销,应该始终工作。 – Bakuriu

1

最好的做法当然是文件你需要什么。记录参数是否应该是可迭代的或序列。 Python的哲学是使用鸭子打字,所以你应该简单地使用参数,就好像它是一个序列一样。

如果要检查参数是否是一个序列,这样做的一个简单的方法,没有创造使用的是len内置函数一个新的列表:

>>> len(iter([1,2,3])) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: object of type 'listiterator' has no len() 

如果你得到的异常,你可以请拨打listtuple以获取序列或让例外通过并让用户处理它。选择哪种“政策”取决于您,完全取决于您。 Python程序员应该仔细阅读文档并传递可以正常工作的参数,以便您可以声明您需要可迭代的参数并始终调用list来获取序列,或者声明您想要序列并在对象为一个可迭代的。当你允许迭代时,我没有看到说明论证应该是一个序列。顺便说一下,如果你只是想迭代多次迭代,你可以使用itertools.tee

例如:

def print_twice(iterable): 
    old, new = itertools.tee(iterable) 
    for element in old: 
     # do stuff 
    for element in new: 
     # do stuff 
+1

'itertools.tee'对于一般问题是一个好主意,但对于这个特殊的用途来说它并不是最好的。根据[文档](http://docs.python.org/2/library/itertools.html#itertools.tee):“通常,如果一个迭代器在另一个迭代器启动之前使用大部分或全部数据,它使用'list()'而不是'tee()'会更快。“ – BrenBarn

+0

@BrenBarn我只是想指出一个替代方案。我认为OP应该介绍可能的解决方案,并且看看哪一种解决方案更适合他的情况。 – Bakuriu

+0

“最好的做法是记录你需要的东西。”不同意。最佳实践是错误输入 –