列表理解中的临时变量

pis*_*hio 14 python list-comprehension

我经常遇到一段看起来像这样的代码.

raw_data  = [(s.split(',')[0], s.split(',')[1]) for s in all_lines if s.split(',')[1] != '"NaN"']
Run Code Online (Sandbox Code Playgroud)

基本上,我想知道是否有办法创建一个临时变量splitted_s,以避免必须在循环对象上重复操作(例如,在这种情况下,必须将其拆分三次).

mya*_*aut 11

如果您有两个处理操作,则可以嵌入另一个列表解析:

raw_data  = [(lhs, rhs) 
            for lhs, rhs 
            in [s.split(',')[:2] for s in all_lines]
            if rhs != '"NaN"']
Run Code Online (Sandbox Code Playgroud)

你可以在里面使用发电机(它也会带来很小的性能提升):

            in (s.split(',')[:2] for s in all_lines)
Run Code Online (Sandbox Code Playgroud)

它甚至比你的实现更快:

import timeit

setup = '''import random, string;
all_lines = [','.join((random.choice(string.letters),
                    str(random.random() if random.random() > 0.3 else '"NaN"')))
                    for i in range(10000)]'''
oneloop = '''[(s.split(',')[0], s.split(',')[1]) 
              for s in all_lines if s.split(',')[1] != '"NaN"']'''
twoloops = '''raw_data  = [(lhs, rhs) 
                for lhs, rhs 
                in [s.split(',') for s in all_lines]
                if rhs != '"NaN"']'''

timeit.timeit(oneloop, setup, number=1000)  # 7.77 secs
timeit.timeit(twoloops, setup, number=1000) # 4.68 secs
Run Code Online (Sandbox Code Playgroud)

  • 这只有在`split`产生2个项目时才有效.此外,内部列表理解可以是生成器. (3认同)

Xav*_*hot 7

开始Python 3.8,并引入赋值表达式(PEP 572):=运算符),可以在列表推导式中使用局部变量以避免两次调用相同的表达式:

在我们的例子中,我们可以将 的评估命名line.split(',')为变量,parts同时使用表达式的结果过滤列表 ifparts[1]不等于NaN; 从而重新使用parts以生成映射值:

# lines = ['1,2,3,4', '5,NaN,7,8']
[(parts[0], parts[1]) for line in lines if (parts := line.split(','))[1] != 'NaN']
# [('1', '2')]
Run Code Online (Sandbox Code Playgroud)

  • @ElRudi哦,我明白了,是的,你可以这样做:`[((parts := line.split(','))[0], parts[1]) for line inlines]`。感觉读起来有点困难,if条件中的赋值使它更清晰一些。 (3认同)