07Python学习列表解析&三元运算&lambda&迭代器

一. 三元表达式

1.1 一元表达式

>>> 1<2
True
>>> {1,2,} - {2,3}
{1}

1.2 三元表达式

>>> a = 1
>>> b = 2
>>> c = 0
>>> if a > b:
...     c = a
... else:
...     c = b
...
>>> c
2

# 上面等价于以下
>>> c = a if a > b else b	# 等价于Java  (a>b)?a:b
>>> c
2

二. 列表解析

2.1 列表解析即通过[]方括号括起来,表达式来创建列表, 如下代码

>>> l = []
>>> for x in range(10):
...     l.append(x)
...
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

可以使用一句代码来完成创建

>>> ll = [x for x in range(10)]
>>> ll
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

通过三元表达式来抽取单数

>>> l = [x for x in range(1,11) if x%2 != 0]
>>> l
[1, 3, 5, 7, 9]

注:上述列表直接解析 在数据量不是很大的情况下 问题不大 但是如果涉及大量数据时 这个存在弊端 由于列表解析是一次性的读取并塞入内存中 存在内存不够使用的风险

此时可以通过迭代器来进行依次获取数据

三.生成器

通过列表解析,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器generator

要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表解析表达式的[]改成(),就创建了一个generator:

>>> l = (x for x in range(100))	#此处不使用[] 使用() 代表生成的是一个生成器
>>> l
<generator object <genexpr> at 0x1057d37c8>
>>> next(l)
0
>>> next(l)
1
>>> for x in l:
...     print(x,end=",")
...
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,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,

如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:

>>> def test():
...     yield 1
...     yield 2
...     yield 3
...     yield 4
...     yield 5
...
>>> test()
<generator object test at 0x1057d3840>
>>> for x in test():
...     print(x)
...
1
2
3
4
5
# 变量生成器三种方式
>>> def yield_value(x):
...     for i in range(x):
...             name = yield i
...             print("Name is:%s" % name)
...
# 用for循环 如上所示

>>> for x in yield_value(5):
...     print(x)
...
0
Name is:None
1
Name is:None
2
Name is:None
3
Name is:None
4
Name is:None
# 生成迭代器,再next方法遍历
>>> yield_it = yield_value(5).__iter__()
>>> yield_it.__next__()
0
>>> yield_it.__next__()
Name is:None
1
>>> yield_it.__next__()
Name is:None
2
>>> yield_it.__next__()
Name is:None
3
>>> yield_it.__next__()
Name is:None
4
>>> yield_it.__next__()
Name is:None
Traceback (most recent call last):
  File "", line 1, in <module>
StopIteration
# 使用send(value) 进行遍历
>>> yv = yield_value(5)
>>> yv.send(None)
0
>>> yv.send(None)
Name is:None
1
>>> yv.send("hello")
Name is:hello
2
>>> yv.send("world")
Name is:world
3
>>> yv.send(1)
Name is:1
4
>>> yv.send(1)
Name is:1
Traceback (most recent call last):
  File "", line 1, in <module>
StopIteration
>>> yv.send(2)
Traceback (most recent call last):
  File "", line 1, in <module>
StopIteration

四. 迭代器

我们已经知道,可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如listtupledictsetstr等;

一类是generator,包括生成器和带yield的generator function。

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

可以使用==isinstance==()判断一个对象是否是**Iterable**对象:

>>> from collections import Iterable
>>> isinstance([],Iterable)
True
>>> test()
<generator object test at 0x1057d38b8>
>>> isinstance(test(),Iterable)
True

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator

①凡是可作用于for循环的对象都是Iterable类型

②凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

③集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

④Python的for循环本质上就是通过不断调用next()函数实现的

4.1 遍历可迭代对象的几种方式

4.1.1 通过变量调用内置函数__iter__()获取iterator对象

# 遍历可迭代对象的几种方式

# 方式一.
# 通过内置函数__iter__()获取iterator对象
>>> l = [1,2,3]
>>> iter_l = l.__iter__()

# 通过调用内置__next__()方法来获取值
>>> iter_l.__next__()
1
>>> iter_l.__next__()
2
>>> iter_l.__next__()
3

# 没有数据 提示抛出StopIteration异常
>>> iter_l.__next__()
Traceback (most recent call last):
  File "", line 1, in <module>
StopIteration

4.1.2 通过iter(变量)获取iterator对象

>>> l
[1, 2, 3]
>>> it_l = iter(l)
>>> it_l
<list_iterator object at 0x1058524e0>
>>> it_l.__next__()
1
>>> it_l.__next__()
2
>>> it_l.__next__()
3
>>> it_l.__next__()
Traceback (most recent call last):
  File "", line 1, in <module>
StopIteration

4.1.3 通过for循环直接操作变量获取其iterator对象

for循环直接会处理StopIteration异常

>>> l
[1, 2, 3]
>>> for x in l:  # 此处l等价于 l.__iter__()
...     print(x,end=" , ")
...
1 , 2 , 3

4.1.4 通过内置next(迭代器)获取数据 or 迭代器.__next__()获取数据

>>> l
[1, 2, 3]
>>> a = iter(l)
>>> b = l.__iter__()
>>> next(a)
1
>>> next(a)
2
>>> next(a)
3
>>> b.__next__()
1
>>> b.__next__()
2
>>> b.__next__()
3

五.lambda表达式 匿名函数

>>> def lbd(x,y):
...     return x+y
...
>>> lbd(1,2)
3

# 与上述函数等价
# lambda 跟一个或多个形参 冒号后面跟 return的返回值
>>> x = lambda a,b:a+b
>>> x(1,2)
3

六. 高阶函数 map reduce filter使用

6.1所谓高阶函数指:把一个函数当做一个参数传给另外一个函数。

举例:l = [1,2,3,4,5,6,8,9] 对每个元素进行平方运算,常规方法如下

>>> l = [x for x in range(1,10)]
>>> l
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> res_l = []
>>> for x in l:
...     res_l.append(x**2)
...
>>> res_l
[1, 4, 9, 16, 25, 36, 49, 64, 81]

6.2高阶函数的用法

其好处在于,func参数传递的是一个函数。此时不管是灵活度也好,维护性也好。都非常?

如果需求变更为每个列表加2的话,直接修改squ函数即可。

>>> l
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> def squ(x):
...     return x**2
...
>>> def res(func,value):
...     res = []
...     for i in value:
...             res.append(func(i))
...     return res
...
>>> res(squ,l)
[1, 4, 9, 16, 25, 36, 49, 64, 81]

6.3 map函数的用法

对于上述需求直接可以通过map函数来简化代码

map函数的用法,map(函数名或lambda表达式,一个或多个可迭代对象)

map主要是争对可迭代对象中每个元素的操作,map返回的是可迭代对象

>>> l
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> m = map(lambda x:x**2,l)
>>> m
<map object at 0x105857668>
>>> list(m)
[1, 4, 9, 16, 25, 36, 49, 64, 81]

6.4 filter函数的用法

filter跟map的使用类似,功能上则是过滤可迭代对象中的元素

需求:l = [1,2,3,4,5,6,8,9] 筛选出3的倍数的数

>>> l
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> ft = filter(lambda x: x % 3 == 0,l)
>>> ft
<filter object at 0x1058576d8>
>>> list(ft)
[3, 6, 9]

6.5 reduce函数的用法

reduce参数跟map、filter一样。reduce(函数名或lambda表达式,一个或多个可迭代对象,可选初始值)

功能上,reduce最终是聚合一个值

使用前需要导入该模块From functools import reduce

需求:l = [1,2,3,4,5,6,8,9] 求集合中每个元素相乘的乘积

>>> l
[1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> from functools import reduce
>>> res = reduce(lambda x,y:x*y,l)
>>> res
362880

>>> a = 1
>>> for x in l:
...     a = a*x
...
>>> a
362880

你可能感兴趣的:(Python)