【问题标题】:How to print the progress of a list comprehension in python?如何在python中打印列表理解的进度?
【发布时间】:2018-11-18 05:54:01
【问题描述】:

在我的方法中,我必须在列表中返回一个列表。我想要一个列表理解,因为创建列表需要大约 5 分钟的性能。

[[token.text for token in document] for document in doc_collection]

是否有可能打印出当前创建过程在哪个文档中的进度?类似的东西:

[[token.text for token in document] 
  and print(progress) for progress, document in enumerate(doc_collection)]

感谢您的帮助!

【问题讨论】:

  • 使用循环而不是理解!
  • @KlausD。肯定这会起作用,但是有没有可能将它添加到理解中?还是谢谢!
  • @Chris_Rands 不错的发现。但我认为这个问题更好(更短更清晰,并且没有pandas 用法),所以最好关闭旧问题作为这个问题的欺骗。我们只需要一个“不要那样做;改用 for 循环”的答案,然后我们就准备好了。
  • @Aran-Fey 为时已晚...但我可以重新打开并执行此操作。完成
  • @Jean-FrançoisFabre 更好并不意味着好:p

标签: python list list-comprehension


【解决方案1】:

tqdm

使用tqdm 包,这是一个快速且多功能的进度条实用程序

pip install tqdm
from tqdm import tqdm

def process(token):
    return token['text']

l1 = [{'text': k} for k in range(5000)]
l2 = [process(token) for token in tqdm(l1)]
100%|███████████████████████████████████| 5000/5000 [00:00<00:00, 2326807.94it/s]

无要求

1/ 使用辅助函数

def report(index):
    if index % 1000 == 0:
        print(index)

def process(token, index, report=None):
    if report:
        report(index) 
    return token['text']

l1 = [{'text': k} for k in range(5000)]

l2 = [process(token, i, report) for i, token in enumerate(l1)]

2/ 使用andor 语句

def process(token):
    return token['text']

l1 = [{'text': k} for k in range(5000)]
l2 = [(i % 1000 == 0 and print(i)) or process(token) for i, token in enumerate(l1)]

3/ 同时使用

def process(token):
    return token['text']

def report(i):
    i % 1000 == 0 and print(i)

l1 = [{'text': k} for k in range(5000)]
l2 = [report(i) or process(token) for i, token in enumerate(l1)]

所有 3 种方法都打印:

0
1000
2000
3000
4000

2 的工作原理

  • i % 1000 == 0 and print(i): and 仅在第一个语句为 True 时检查第二个语句,因此仅在 i % 1000 == 0 时打印
  • or process(token): or 总是检查两个语句,但返回第一个评估为True 的语句。
    • 如果i % 1000 != 0,那么第一个语句是Falseprocess(token) 被添加到列表中。
    • 否则,第一个语句是None(因为print 返回None),同样,or 语句将process(token) 添加到列表中

3 的工作原理

与 2 类似,因为 report(i) 没有 return 任何东西,所以它评估为 Noneorprocess(token) 添加到列表中

【讨论】:

  • 我不会使用global i,而是使用enumerate 并将index 传递给function
  • @Ev.Kounis 并使用回调将报告部分排除在外(已编辑代码以修复这两点)。
  • 这比for 循环更慢且可读性更差。在我(诚然非常有限)的测试中,Alex 的解决方案需要 10 秒,for 循环需要 13 秒,而这个需要 17 秒。
  • @Aran-Fey 虽然功能不同;无法直接比较它们。
  • @Ev.Kounis 嗯?有什么不同?结果是一样的,据我所知......
【解决方案2】:
doc_collection = [[1, 2],
                  [3, 4],
                  [5, 6]]

result = [print(progress) or
          [str(token) for token in document]
          for progress, document in enumerate(doc_collection)]

print(result)  # [['1', '2'], ['3', '4'], ['5', '6']]

我不认为这是好的或可读的代码,但这个想法很有趣。

之所以有效,是因为print 总是返回None,所以print(progress) or x 将永远是x(根据or 的定义)。

【讨论】:

  • 这不应该是公认的答案——就我而言,这样的代码不会通过代码审查。泰德的解决方案是解决问题的正确方法。
【解决方案3】:
def show_progress(it, milestones=1):
    for i, x in enumerate(it):
        yield x
        processed = i + 1
        if processed % milestones == 0:
            print('Processed %s elements' % processed)

只需将此函数应用于您正在迭代的任何内容。无论您使用循环还是列表推导,它都可以在任何地方轻松使用,几乎不需要更改代码。例如:

doc_collection = [[1, 2],
                  [3, 4],
                  [5, 6]]

result = [[str(token) for token in document]
          for document in show_progress(doc_collection)]

print(result)  # [['1', '2'], ['3', '4'], ['5', '6']]

如果您只想显示每 100 个文档的进度,请编写:

show_progress(doc_collection, 100) 

【讨论】:

    【解决方案4】:

    这是我的实现。

    pip install progressbar2

    from progressbar import progressbar
    new_list = [your_function(list_item) for list_item in progressbar(old_list)]`
    

    在运行上面的代码块时,你会看到一个进度条。

    【讨论】:

      【解决方案5】:

      只要做:

      from time import sleep
      from tqdm import tqdm
      
      def foo(i):
          sleep(0.01)
          return i
      
      [foo(i) for i in tqdm(range(1000))]
      

      对于 Jupyter 笔记本:

      from tqdm.notebook import tqdm
      

      【讨论】:

        【解决方案6】:

        我需要使@ted 的答案 (imo) 更具可读性并添加一些解释。

        整理解决方案:

        # Function to print the index, if the index is evenly divisable by 1000:
        def report(index):
            if index % 1000 == 0:
                print(index)
        
        # The function the user wants to apply on the list elements
        def process(x, index, report):
             report(index) # Call of the reporting function
             return 'something ' + x # ! Just an example, replace with your desired application
        
        # !Just an example, replace with your list to iterate over
        mylist = ['number ' + str(k) for k in range(5000)]
        
        # Running a list comprehension
        [process(x, index, report) for index, x in enumerate(mylist)]
        

        解释: of enumerate(mylist):使用函数enumerate,除了可迭代对象的元素之外,还可以有索引(参见this question and its answers)。例如

        [(index, x) for index, x in enumerate(["a", "b", "c"])] #returns
        [(0, 'a'), (1, 'b'), (2, 'c')]
        

        注意: indexx 不是保留名称,只是我觉得方便的名称 - [(foo, bar) for foo, bar in enumerate(["a", "b", "c"])] 产生相同的结果。

        【讨论】:

          猜你喜欢
          • 2013-12-16
          • 2015-04-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-12-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多