Python之解析式您知多少?

解析式 解析式 今天给大家介绍Python中的解析式。

解析式简单介绍

解析式,

  1. 列表解析 # Python2只有列表解析
  2. 生成器解析 # Python3特有
  3. 集合解析 # Python3特有
  4. 字典解析 # Python3特有

解析式的作用:

  1. 修改可迭代对象
  2. 过滤可迭代对象

zip方法:

In[1]: help(zip)

Help on class zip in module builtins:

class zip(object)
|  zip(iter1 [,iter2 [...]]) --> zip object
|  
|  Return a zip object whose .__next__() method returns a tuple where
|  the i-th element comes from the i-th iterable argument.  The .__next__()
|  method continues until the shortest iterable in the argument sequence
|  is exhausted and then it raises StopIteration.

In[3]: list(zip(range(10), range(10)))
Out[3]: 
[(0, 0),
(1, 1),
(2, 2),
(3, 3),
(4, 4),
(5, 5),
(6, 6),
(7, 7),
(8, 8),
(9, 9)]

In[4]: {x:y for x, y in zip(range(10), range(10))}
Out[4]: {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}

In[5]: list(zip(range(5), range(10), range(20)))
Out[5]: [(0, 0, 0), (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4)]

zip方法用于合并多个可迭代对象,合并后的长度等于最短的可迭代对象的长度。

每种解析式都可以翻译为for循环。为什么没有元组解析?

列表解析

列表解析式示例

列表解析的一般形式:

[expression for item in iterable]

接下来看几个示例:

In[23]: [2 ** n for n in range(10)]
Out[23]: [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]

In[24]: def inc(x):
    ...:     return x + 1
    ...: 

In[25]: [inc(x) for x in range(10)]
Out[25]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

In[26]: [0 for x in range(10)]
Out[26]: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

In[27]: def non_return(x):
    ...:     pass
    ...: 

In[28]: [non_return(x) for x in range(10)]
Out[28]: [None, None, None, None, None, None, None, None, None, None]

列表解析式返回的结果是列表,列表的内容是表达式执行的结果。接着看例子:

In[13]: [x for x in range(10) if x % 2 == 0]
Out[13]: [0, 2, 4, 6, 8]

# 上面的语句等效于
ret = []
for x in range(10):
    if x % 2 == 0:
        ret.append(x)
# 可以使用ipython的timeit来测试两种方式的执行效率。
# 列表解析的执行效率会好一些

列表解析式中带有if关键字

如果列表解析式中有if关键字呢:

[exper for item in iterable if cond]
# 等价于
ret = []
for item in iterable:
    if cond:
        ret.append(exper)

以上介绍的只带了一个if关键字,如果有多个if关键字呢:

[exper for item in iterable if cond1 if cond2]
# 等价于
ret = []
for item in iterable:
    if cond1:
        if cond2:
            ret.append(exper)

针对上面来个例子:

[x for x in range(10) if x % 2 == 0 if x > 1]
[2, 4, 6, 8]

# 再来个例子
lst = [[0, 1], [1, 2], [2, 3], [3, 4], [4]]
[x for x in lst if len(x) > 1 and x.pop(0) % 2 == 0]

不但可以有多个if关键字,还可以有多个for关键字:

>>> [(x, y) for x in range(5) for y in range(5)]
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4)]

写成一个公式类的写法为:

[expr for item1 in iterable1 for item2 in iterable2]
# 等价于
ret = []
for item1 in iterable1:
    for item2 in iterable2:
        ret.append(expr)

那么for与if都有呢?多个for语句相当于逐层for嵌套。

# 逐层嵌套
In[11]: [(x, y) for x in range(10) for y in range(10) if (x+y) % 2 == 0]
Out[11]: 
[(0, 0),
 (0, 2),
 (0, 4),
 (0, 6),
 (0, 8),
 (1, 1),
 (1, 3),
 (1, 5),
 (1, 7),
 (1, 9),
 (2, 0),
 (2, 2),
 (2, 4),
 (2, 6),
 (2, 8),
 (3, 1),
 (3, 3),
 (3, 5),
 (3, 7),
 (3, 9),
 (4, 0),
 (4, 2),
 (4, 4),
 (4, 6),
 (4, 8),
 (5, 1),
 (5, 3),
 (5, 5),
 (5, 7),
 (5, 9),
 (6, 0),
 (6, 2),
 (6, 4),
 (6, 6),
 (6, 8),
 (7, 1),
 (7, 3),
 (7, 5),
 (7, 7),
 (7, 9),
 (8, 0),
 (8, 2),
 (8, 4),
 (8, 6),
 (8, 8),
 (9, 1),
 (9, 3),
 (9, 5),
 (9, 7),
 (9, 9)]

[(x, y) for x in range(10) if x % 2 == 0 for y in range(10)]
# 等价于
ret = []
for x in range(10):
    if x % 2 == 0:
        for y in range(10):
            ret.append((x, y))

# 如果for关键字不在第一个位置,会不会出问题呢
In[12]: [x if True for x in range(10)]
  File "<ipython-input-12-c9daacf14b27>", line 1
    [x if True for x in range(10)]
                 ^
SyntaxError: invalid syntax

# 因此,for关键字要写在前面,后面可以用for或if进行嵌套

多看几个例子吧:

In[9]: [(x+1, x+2) for x in range(5)]
Out[9]: [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]

In[10]: [{x+1:x+2} for x in range(5)]
Out[10]: [{1: 2}, {2: 3}, {3: 4}, {4: 5}, {5: 6}]

列表解析用于可迭代对象做过滤和转换,返回值是列表。

help(filter)

filter(lambda x: x % 2 == 0, range(10))

list(filter(lambda x: x % 2 == 0, range(10)))

help(map)
list(map(lambda x: x+1, range(10)))

[x+1 for x in range(10)]

# Python里,可以不用filter及map函数,使用列表解析式可以秒杀filter及map
# 上面的话并不是绝对的,当数据比较大时,使用filter及map将会比列表解析式快

再来看一个例子,偶数求平方,奇数求立方。

lst = list(range(10))
     [x ** 2 if x % 2 == 0 else x ** 3 for x in lst]

   #+RESULTS:
   | 0 | 1 | 4 | 27 | 16 | 125 | 36 | 343 | 64 | 729 |

总结上述代码:

x if cond else y
当条件满足时返回x,当条件不满足时返回y。

列表解析的一个例子

#!/usr/bin/env python
# coding: utf-8

import time

is_forloop = input('0 is list comprehension, 1 is for loop: ')

min_time = 1000
avg_time = 0.0
run_loops = 1000

for num in range(run_loops):
    start_clock = time.clock()
    if is_forloop:
    a = []
    for x in range(0, 100):
        for y in range(0, 100):
        if x * y > 25:
            a.append((x, y))
    else:
    a = [(x, y) for x in range(100) for y in range(100) if x * y > 25]

    end_clock = time.clock()
    avg_time += end_clock - start_clock
    if (end_clock - start_clock) < min_time:
    min_time = end_clock - start_clock

print "length of result is", len(a)
print run_loops, u"次的最好运行时间为", min_time, 's'
print run_loops, u"次的平均运行时间为", avg_time / run_loops, 's'

列表解析式总结

  1. 使用列表解析式为了让代码更简洁

字典解析

字典解析也需要一个大括号,并且要有两个表达式:一个生成key,一个生成value;两个表达式之间使用冒号分隔,返回结果是字典。

In[14]: {str(x):x for x in range(10)}
Out[14]: 
{'0': 0,
 '1': 1,
 '2': 2,
 '3': 3,
 '4': 4,
 '5': 5,
 '6': 6,
 '7': 7,
 '8': 8,
 '9': 9}

看一个例子:

{str(x):y for x in range(3) for y in range(4)} # 取决于短的那个
{'0': 3, '1': 3, '2': 3}

ret = {}
for x in range(3):
    for y in range(4):
        ret[str(x)] = y
print(ret)

集合解析

集合解析把列表解析的中括号变成大括号,返回集合。

In[45]: {x for x in range(10)}
Out[45]: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

In[46]: set01 = {x for x in range(10)}

In[47]: set01
Out[47]: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

In[48]: type(set01)
Out[48]: set

本文总结

今天给大家介绍了几种解析式,分别是:

  1. 列表解析式
  2. 字典解析式
  3. 集合解析式

在前进的路上我们并不孤单,每天都进步一点点,加油!小白甘愿做个知识的搬运工为大家服务。

原文发布于微信公众号 - 小白的技术客栈(XBDJSKZ)

原文发表时间:2017-09-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Laoqi's Linux运维专列

多类型传值和冗余参数+递归调用

967
来自专栏CodingToDie

Python学习(二):基础

第2 章 基础 Table of Contents 输入和输出 输出 输入 数据类型 整数 浮点数 字符串 布尔值 空值 变量 常量 输入和输出 输出 prin...

2955
来自专栏柠檬先生

JavaScript 基础(一)

基本语法: 区分大小写:       ECMAScript 中的一切(变量,函数名和操作符)都区分大小写。 标识符:     表示符就是指,变量,函数,属性...

18810
来自专栏个人随笔

房上的猫:java基础知识部分知识点

1.Java常见的注释有哪些,语法是怎样的?  1)单行注释用//表示,编译器看到//会忽略该行//后的所文本  2)多行注释/* */表示,编译器看到/*时...

35314
来自专栏夏时

PHP 特色:可变变量

984
来自专栏前端小作坊

Javascript 原型链

本来想写一篇“如何用JS实现面向对象”,发现自己对prototype原型链还是有很多的不理解的地方。先看一张原型链关系图:

781
来自专栏Android 研究

Retrofit解析3之反射

反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。在计算机科学领域,反射是一类应用,它们能够自描述和自控制。这类应用通过某种机制来实现对自己行为的...

652
来自专栏有趣的django

5.python函数

函数介绍 定义:  函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可。 特性:减少重复代码、使程序变的可扩展、使程...

2636
来自专栏noteless

[三] java虚拟机 JVM字节码 指令集 bytecode 操作码 指令分类用法 助记符

计算机指令就是指挥机器工作的指示和命令,程序就是一系列按一定顺序排列的指令,执行程序的过程就是计算机的工作过程。

992
来自专栏猿人谷

运算符重载

  C++中预定义的运算符的操作对象只能是基本数据类型。但实际上,对于许多用户自定义类型(例如类),也需要类似的运算操作。这时就必须在C++中重新定义这些运算符...

2017

扫码关注云+社区