什么是列表解析?
列表解析就是根据已有列表,高效生成新列表的方式
列表解析是python迭代机制的一种应用,它常用于实现创建新的列表,因此要放置于[]中
语法:
|
1
2
|
[expression
for
iter_var
in
iterable]
[expression
for
iter_var
in
iterable
if
cond_expr]
|
例:
|
1
|
In [
1
]: L
=
[i
*
*
2
for
i
in
xrange
(
9
)]
|
|
1
2
|
In [
2
]:
print
L
[
0
,
1
,
4
,
9
,
16
,
25
,
36
,
49
,
64
]
|
假设现在有一个列表list1,需要取得列表list1中每一个元素的平方,并生成一个新列表,可以这样做:
|
1
2
3
4
5
6
|
In [
3
]: list1
=
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
In [
4
]: list2
=
[i
*
*
2
for
i
in
list1]
In [
5
]:
print
list2
[
1
,
4
,
9
,
16
,
25
,
36
,
49
,
64
]
|
只把list1中元素值大于或等于3的计算机其平方,并生成新列表,可以这样做:
|
1
2
3
4
|
In [
6
]: list3
=
[i
*
*
2
for
i
in
list1
if
i >
=
3
]
In [
7
]:
print
list3
[
9
,
16
,
25
,
36
,
49
,
64
]
|
列表解析能够使用比for循环快近一倍的方式基于已有的列表来生成新列表
求1到10范围内10个数字的平方除以2的结果:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
In [
8
]:
for
i
in
[i
*
*
2
for
i
in
xrange
(
1
,
11
)]:
...:
print
i
/
2
...:
0
2
4
8
12
18
24
32
40
50
|
返回1到10范围内所有偶数的平方除以2的结果:
|
1
2
3
4
5
6
7
8
|
In [
9
]:
for
i
in
[i
*
*
2
for
i
in
xrange
(
1
,
11
)
if
i
%
2
=
=
0
]:
...:
print
i
/
2
...:
2
8
18
32
50
|
把/root目录下所有以.log结尾的文件取出来,生成一个新列表:
|
1
2
3
4
5
6
|
In [
10
]:
import
os
In [
11
]: filelist
=
[i
for
i
in
os.listdir(
"/root"
)
if
i.endswith(
".log"
)]
In [
12
]:
print
filelist
[
'install.log'
]
|
把/etc目录下所有目录取出来,生成一个新列表:
|
1
2
3
4
|
In [
13
]: directory1
=
[i
for
i
in
os.listdir(
"/etc"
)
if
os.path.isdir(
"/etc/"
+
i)]
In [
14
]:
print
directory1
[
'pkcs11'
,
'sasl2'
,
'xml'
,
'pear'
,
'terminfo'
,
'iscsi'
,
'sysconfig'
,
'security'
,
'statetab.d'
,
'NetworkManager'
,
'.java'
,
'rc4.d'
,
'gcrypt'
,
'xinetd.d'
,
'ssh'
,
'httpd'
,
'dhcp'
,
'php.d'
,
'rc6.d'
,
'rpm'
,
'cron.daily'
,
'audit'
,
'selinux'
,
'depmod.d'
,
'dracut.conf.d'
,
'ntp'
,
'xdg'
,
'init'
,
'init.d'
,
'ConsoleKit'
,
'pm'
,
'yum'
,
'openldap'
,
'sudoers.d'
,
'logrotate.d'
,
'lxc'
,
'ppp'
,
'ld.so.conf.d'
,
'rwtab.d'
,
'dbus-1'
,
'gnupg'
,
'cron.weekly'
,
'sgml'
,
'pki'
,
'rc2.d'
,
'modprobe.d'
,
'audisp'
,
'exim'
,
'blkid'
,
'profile.d'
,
'cron.hourly'
,
'default'
,
'opt'
,
'rc0.d'
,
'ssl'
,
'fonts'
,
'sysctl.d'
,
'iproute2'
,
'X11'
,
'rc1.d'
,
'plymouth'
,
'rc.d'
,
'yum.repos.d'
,
'polkit-1'
,
'cron.monthly'
,
'pango'
,
'pam.d'
,
'rsyslog.d'
,
'prelink.conf.d'
,
'alternatives'
,
'rc3.d'
,
'makedev.d'
,
'popt.d'
,
'docker'
,
'udev'
,
'gconf'
,
'lvm'
,
'cgconfig.d'
,
'cron.d'
,
'chkconfig.d'
,
'bash_completion.d'
,
'skel'
,
'multipath'
,
'rc5.d'
]
|
在使用列表解析时,for循环还可以嵌套for循环。举例说明:
假设现在有两个列表list1和list2,现在要实现两个列表的元素交叉相乘,可以这样做:
|
1
2
3
4
5
6
7
8
|
In [
15
]: list1
=
[
'x'
,
'y'
,
'z'
]
In [
16
]: list2
=
[
1
,
2
,
3
]
In [
17
]: list3
=
[(i,j)
for
i
in
list1
for
j
in
list2]
In [
18
]:
print
list3
[(
'x'
,
1
), (
'x'
,
2
), (
'x'
,
3
), (
'y'
,
1
), (
'y'
,
2
), (
'y'
,
3
), (
'z'
,
1
), (
'z'
,
2
), (
'z'
,
3
)]
|
接下来实现当list2中元素值不为1时与list1交叉相乘,可以这样做:
|
1
2
3
4
|
In [
19
]: list4
=
[(i,j)
for
i
in
list1
for
j
in
list2
if
j !
=
1
]
In [
20
]:
print
list4
[(
'x'
,
2
), (
'x'
,
3
), (
'y'
,
2
), (
'y'
,
3
), (
'z'
,
2
), (
'z'
,
3
)]
|
列表解析会直接返回一个新列表,如果某个原列表里面的元素非常多,而列表解析又以几何倍数向上增长以后,就会极其占用内存,如此将导致效率低下。
但是列表生成以后,一般一次只取一个元素,而for循环一次只遍历迭代其中的一个元素,基于此,使用直接生成一个列表的方式如此占用内存是极其不好的。
由此我们可以对列表解析作一个扩展,就是把[]变成(),这就叫做生成器
生成器和列表解析的关系就相当于xrange和range的关系,它可以让我们使用一个表达式,一次只生成计算出一个值,叫惰性计算方式。
生成器不像列表解析一样,不管你用不用直接就生成了。生成器仅仅是你调用一次,它就可以返回一个,再调用一次,再返回一个。
生成器表达式并不真正创建数字列表,而是返回一个生成器对象,此对象在每次计算出一个条目后,把这个条目“产生”(yield)出来.生成器表达式使用了“惰性计算”或称作“延迟求值”的机制
当序列过长,并且每次只需要获取一个元素时,应当考虑使用生成器表达式而不是列表解析
生成器特点:
1、只有在调用时才会生成相对应的数据
2、只记录当前位置,无法向前回溯,只能一步步往后走
3、可以通过__next__()方法一次取一个值
4、可以通过for循环取得所有值
生成器表达式语法:
|
1
2
|
(expr
for
iter_var
in
iterable)
(expr
for
iter_var
in
iterable
if
cond_expr)
|
生成器生成方法:
1、通过列表解析进行生成
|
1
|
[ i
*
2
for
i
in
range
(
10
) ]
|
2、通过函数生成(这里用著名的裴波那契数列来举例)
|
1
2
3
4
5
6
7
|
def
fib(
max
):
count,a,b
=
0
,
0
,
1
while
count <
max
:
yield
b
a,b
=
b,a
+
b
count
+
=
1
return
'done'
|
生成器的return返回值包含在异常当中,为避免程序抛出异常,仅通过捕捉异常的方式才能取得return返回值。
yield保存了函数的中断状态。
生成器是什么情况下会用到呢?这里通过一个例子来说明一下:
生成器可以实现在单线程(串行)的情况下实现并发运算的效果
生成器的__next__()方法只调用生成器的状态而不传值;
生成器的send()方法在调用生成器的状态的同时给生成器传一个值
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
import
time
def
cut(cutter):
print
(
'%s 已经准备好撕纸了。'
%
cutter)
num
=
1
while
True
:
paper
=
yield
print
(
'第%s张%s刚做好了,已经被%s撕了。'
%
(num,paper,cutter))
num
+
=
1
def
make(maker):
cutter1
=
cut(
'撕纸员1'
)
cutter2
=
cut(
'撕纸员2'
)
cutter1.__next__()
cutter2.__next__()
print
(
'%s已经准备好做纸了。'
%
maker)
for
i
in
range
(
1
,
11
):
time.sleep(
1
)
print
(
'%s已经做好了1张纸'
%
maker)
cutter1.send(i)
cutter2.send(i)
make(
'Tom'
)
|
返回1到10范围内所有正整数的平方:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
In [
21
]: g1
=
(i
*
*
2
for
i
in
range
(
1
,
11
))
In [
22
]: g1.
next
()
Out[
22
]:
1
In [
23
]: g1.
next
()
Out[
23
]:
4
In [
24
]: g1.
next
()
Out[
24
]:
9
In [
25
]: g1.
next
()
Out[
25
]:
16
In [
26
]: g1.
next
()
Out[
26
]:
25
In [
27
]: g1.
next
()
Out[
27
]:
36
In [
28
]: g1.
next
()
Out[
28
]:
49
In [
29
]: g1.
next
()
Out[
29
]:
64
In [
30
]: g1.
next
()
Out[
30
]:
81
In [
31
]: g1.
next
()
Out[
31
]:
100
In [
32
]: g1.
next
()
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
StopIteration Traceback (most recent call last)
<ipython
-
input
-
32
-
9066a8f18086
>
in
<module>()
-
-
-
-
>
1
g1.
next
()
StopIteration:
|
返回1到10范围内所有正整数的平方除以2的结果:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
In [
33
]:
for
i
in
(i
*
*
2
for
i
in
range
(
1
,
11
)):
...:
print
i
/
2
...:
0
2
4
8
12
18
24
32
40
50
|
产生偏移和元素,使用enumerate函数:
range可在非完备遍历中用于生成索引偏移,而非偏移处的元素
如果同时需要偏移索引和偏移元素,则可以使用enumerate()函数,此内置函数返回一个生成器对象,例:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
In [
35
]: url
=
'www.python.org'
In [
36
]: g2
=
enumerate
(url)
In [
37
]: g2.
next
()
Out[
37
]: (
0
,
'w'
)
In [
38
]: g2.
next
()
Out[
38
]: (
1
,
'w'
)
In [
39
]: g2.
next
()
Out[
39
]: (
2
,
'w'
)
In [
40
]: g2.
next
()
Out[
40
]: (
3
,
'.'
)
In [
41
]: g2.
next
()
Out[
41
]: (
4
,
'p'
)
In [
42
]: g2.
next
()
Out[
42
]: (
5
,
'y'
)
In [
43
]: g2.
next
()
Out[
43
]: (
6
,
't'
)
In [
44
]: g2.
next
()
Out[
44
]: (
7
,
'h'
)
In [
45
]: g2.
next
()
Out[
45
]: (
8
,
'o'
)
In [
46
]: g2.
next
()
Out[
46
]: (
9
,
'n'
)
In [
47
]: g2.
next
()
Out[
47
]: (
10
,
'.'
)
In [
48
]: g2.
next
()
Out[
48
]: (
11
,
'o'
)
In [
49
]: g2.
next
()
Out[
49
]: (
12
,
'r'
)
In [
50
]: g2.
next
()
Out[
50
]: (
13
,
'g'
)
In [
51
]: g2.
next
()
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
StopIteration Traceback (most recent call last)
<ipython
-
input
-
51
-
6d69cefe8ba3
>
in
<module>()
-
-
-
-
>
1
g2.
next
()
StopIteration:
|