循环Python:在第一次迭代之前做一些事情

时间:2016-04-04 10:08:57

标签: python loops optimization

我想优化。

简单解决方案

connection = get_db_connection()
for item in my_iterator:
    push_item_to_db(item, connection)

缺点:

get_db_connection()很慢。如果my_iterator为空,那么我想避免调用它。

"如果没有"溶液

connection = None
for item in my_iterator:
    if connection is None:
        connection = get_db_connection()
    push_item_to_db(item, connection)

缺点:

如果my_iterator中有100k项,那么if connection is None会被调用100k次(尽管只需要一次)。我想避免这种情况。

完美的解决方案......

    如果迭代器为空,
  1. 不要调用get_db_connection()
  2. 每次迭代都不会毫无用处地致电if connection is None:
  3. 有什么想法吗?

5 个答案:

答案 0 :(得分:5)

您可以执行以下操作:

connection = None
for item in my_iterator:
    if connection is None:
        connection = get_db_connection()
    push_item_to_db(item, connection)

简单的解决方案。不需要过度思考它。即使有100k的操作,x is None只是一个参考比较,只需要一个Python操作码。与每次插入时发生的完整tcp往返+磁盘写入相比,您真的不需要优化它。

答案 1 :(得分:2)

我不是Python的专家,但我会做这样的事情:

def put_items_to_database (iterator):
    try:
        item = next(iterator)

        # We connect to the database only after we 
        # know there at least one element in the collection            
        connection = get_db_connection()

        while True:
            push_item_to_db(item, connection)
            item = next(iterator)
    except StopIteration:
        pass

这可能是因为性能与数据库绑定在一起。然而问题是如何找到一种方法来避免做不必要的工作,以上是一种精确控制迭代过程中发生的事情的基本方法。

其他解决方案在某种程度上“更简单”,但另一方面,我认为这个解决方案更明确,并遵循最不惊讶的原则。

答案 2 :(得分:2)

for item in my_iterator:
    # First item (if any)
    connection = get_db_connection()
    push_item_to_db(item, connection)
    for item in my_iterator:
        # Next items
        push_item_to_db(item, connection)

答案 3 :(得分:1)

解决方案1 ​​

这没有while True循环。

try:
    next(my_iterator)
    connection = get_db_connection()
    push_item_to_db(item, connection)
except StopIteration:
    pass
for item in my_iterator:
    push_item_to_db(item, connection)

解决方案2

如果您知道迭代器永远不会返回None(或任何其他唯一对象),您可以利用next()的默认值:

if next(my_iterator, None) is not None:
    connection = get_db_connection()
    push_item_to_db(item, connection)
for item in my_iterator:
    push_item_to_db(item, connection)

解决方案3

如果您无法保证迭代器永远不会返回的值,则可以使用标记。

sentinel = object()
if next(my_iterator, sentinel) is not sentinel:
    connection = get_db_connection()
    push_item_to_db(item, connection)
for item in my_iterator:
    push_item_to_db(item, connection)

解决方案4

使用itertools.chain()

from itertools import chain

for first_item in my_iterator:
    connection = get_db_connection()
    for item in chain([first_item], my_iterator):
        push_item_to_db(item, connection)

答案 4 :(得分:-1)

您可以在代码的整个部分之前检查迭代器计数

if (len(my_iterator)>0): 
    connection = get_db_connection()
    for item in my_iterator:
        push_item_to_db(item, connection)