1. 三元表达式
1.1 格式
当需求为二选一的情况下推荐使用三元表达式 .
格式 : 条件成立采用的值 if 条件 else 条件不成立采用的值 .
值不能是关键字 , . . . 属于特殊的符号 , 不是关键字 .
1.2 示例
a = 0
b = 1
print ( a if a > b else b)
def func1 ( ) :
print ( '哈哈哈' )
while True :
func1( ) if input ( '输入q退出否则继续>>>:' ) . strip( ) == 'q' else . . .
1.3 嵌套
三元表达式可以嵌套使用 , 尽量不要去使用 , Python语句注重可读性 , 嵌套太复杂了 .
a = 0
b = 1
c = 2
print ( a if a > b else ( c if c > b else a) )
2. 生成式
生成式 ( comprehensions ) , 也称推导式 , 作用是为容器类型快速生成元素 .
生成式中for与if一起使用 , 则不能搭配else , 应为else从句能跟for也能跟if这会会出现矛盾 .
2.1 列表生成式
列表生成式语法 : [ 满足条件执行的表达式 for 迭代变量 in 容器对象 ]
print ( [ i for i in range ( 10 ) ] )
list1 = [ 'kid' , 'qz' , 'qq' ]
print ( [ i + '_vip' for i in list1] )
list1 = [ 'kid_vip' , 'qz_vip' , 'qq_vip' ]
print ( [ i. strip( '_vip' ) for i in list1] )
list1 = [ 'kid_vip' , 'qz_vip' , 'qq_vip' ]
print ( [ i. strip( '_vip' ) for i in list1 if i == 'kid_vip' ] )
list1 = [ lambda x: x + i for i in range ( 10 ) ]
print ( list1)
print ( list1[ 0 ] ( 10 ) )
print ( list1[ 1 ] ( 10 ) )
print ( list1[ 2 ] ( 10 ) )
函数具有调用时才查找变量的特性 , 在没调用之前它不会保存变量的具体值 .
只有调用它的时候 , 才逐一去找这些变量的具体值 , 无所调用第几个匿名函数 , 变量i已经循环完毕 , 变成 9 了 .
list1 = [ lambda x, i= i: x + i for i in range ( 10 ) ]
print ( list1[ 0 ] ( 10 ) )
print ( list1[ 1 ] ( 10 ) )
2.2 字典生成式
list1 = [ 'name' , 'age' , 'hobby' ]
list2 = [ 'kid' , 18 , 'red' ]
dic = { }
for i in range ( len ( list1) ) :
dic[ list1[ i] ] = list2[ i]
print ( dic)
list1 = [ 'name' , 'age' , 'hobby' ]
list2 = [ 'kid' , 18 , 'red' ]
res = { list1[ i] : list2[ i] for i in range ( len ( list1) ) }
print ( res)
2.3 集合生成式
list1 = [ 'name' , 'age' , 'hobby' ]
res = { i for i in list1}
print ( res)
2.4 元组生成式
( ) 被python中的生成器占用 , 想要使用元组生成式在括号前面加上关键字tuple .
print ( tuple ( x for x in range ( 5 ) ) )
3. 可迭代对象
迭代 : 迭代即更新的意思 , 每次更新都必须依赖上一次的结果 , 其目是为了更逼近所需结果 .
可迭代对象 : 即可以进行迭代操作的一类对象 , 能被for循环遍历取值的对象的都是可迭代对象 .
内置isinstance ( Object , Iterable ) 函数 : 判断一个对象是否是可迭代对象 .
管方解释说只能识别对象含有 . __iter__ ( ) 方法的对象 ,
那么意味着对象含有 . __iter__ ( ) 方法都是 '可迭代对象' .
一般情况下所有的双下方法都会有一个与之对应的简化写法的函数 .
例 : . __iter__ ( ) 方法 -- > iter ( ) 函数 .
针对双下划线开头 , 双下滑线结尾的方法标准的读法是 '双下方法名' , 例 : 双下iter .
from collections import Iterable
str1 = ''
print ( isinstance ( str1, Iterable) )
str1. __iter__( )
4. 迭代器
迭代器 : 是一种通过迭代方式取值的方式 , 从序列的第⼀个元素开始访问 , 直到所有的元素被访问完 , 结束 .
迭代器可以记住遍历对象所在的位置 , 只能往后取值 , 不会后退 .
通常含有 . __next__ ( ) 方法的对象就是迭代器 .
4.1 迭代器的优缺点
迭代器的优点 : 节省内存 , 迭代器在内存中只占一个数据的空间 .
每次通过next ( ) 取值 , 便会计算出一个值 , 内存空间内加载当前的值 , 将上一条值舍弃 .
迭代器的缺点 : 不能直观的查看里面的数据 , 取值时不走回头路 , 只能一直向下取值 .
取值方式对比 :
迭代取值 : 是通用取值方式 , 不依赖于索引取值 . 特点 : 永远都是往下一个取值 , 无法重复获取 .
索引取值 : 不通用取值方式 , 有序的容器类型 , 才能使用 . 特点 : 可以重复取值 .
4.2 迭代器的惰性机制
迭代器的惰性机制 : next一次 , 取一个值 , 绝不过多取值 .
迭代是数据处理的基石 , 内存中放不下的数据集时 ,
需要一种惰性获取数据项的方式 , 即按需一次获取一个数据项 , 这就是迭代器模式 .
4.3 生成迭代器
字符串 , 列表 , 字典 , 元组 , 集合 , 文件都是可迭代对象 , 通过 . __iter__ ( ) 方法实例化得到迭代器 .
迭代取值固定语法 : for element in Iterable , for语句内部通过 . __next__ ( ) 方法获取迭代器对象的元素 .
直接使用 . __next__ ( ) 方法取值 , 一次取出一个 , 取完再取则报错 :
英 : StopIteration .
中 : 停止迭代 .
4.4 文本IO包装器
文件对象本身就是迭代器对象 .
"""
a.txt内容:
1
2
3
"""
rf = open ( 'a.txt' , 'rt' )
text_io_wrapper = rf. __iter__( )
print ( text_io_wrapper, type ( text_io_wrapper) )
print ( text_io_wrapper. __next__( ) )
print ( rf, type ( rf) )
print ( rf. __next__( ) )
4.5 字符串迭代器
str_iterator = '123' . __iter__( )
print ( str_iterator, type ( str_iterator) )
print ( str_iterator. __next__( ) )
print ( str_iterator. __next__( ) )
print ( str_iterator. __next__( ) )
print ( str_iterator. __next__( ) )
4.6 列表迭代器
list_iterator = [ 1 , 2 , 3 ] . __iter__( )
print ( list_iterator, type ( list_iterator) )
print ( list_iterator. __next__( ) )
print ( list_iterator. __next__( ) )
print ( list_iterator. __next__( ) )
4.7 字典键迭代器
dict_keyiterator = { 'k1' : 'v1' , 'k2' : 'v2' } . __iter__( )
print ( dict_keyiterator, type ( dict_keyiterator) )
print ( dict_keyiterator. __next__( ) )
print ( dict_keyiterator. __next__( ) )
4.8 元组迭代器
tuple_iterator = ( 1 , 2 , 3 ) . __iter__( )
print ( tuple_iterator, type ( tuple_iterator) )
print ( tuple_iterator. __next__( ) )
print ( tuple_iterator. __next__( ) )
print ( tuple_iterator. __next__( ) )
4.9 集合迭代器
set_iterator = { 1 , 2 , 3 } . __iter__( )
print ( set_iterator, type ( set_iterator) )
print ( set_iterator. __next__( ) )
print ( set_iterator. __next__( ) )
print ( set_iterator. __next__( ) )
4.10 注意事项
每次执行 . __iter__ ( ) 方法都生成一个新的迭代器对象 , 都是第一次迭代取到的值是同一个值 .
str1 = 'abc'
print ( str1. __iter__( ) . __next__( ) )
print ( str1. __iter__( ) . __next__( ) )
print ( str1. __iter__( ) . __next__( ) )
print ( str1. __iter__( ) . __next__( ) )
4.11 模拟for循环
1. 执行步骤
for循环执行步骤 :
* 1. in关键字后面的序列类型调用 . __iter__ ( ) 方法转为迭代器对象 .
* 2. 循环执行 . __next__ ( ) 方法取值 .
* 3. 取完之后再次执行 . __next__ ( ) 就会报错 , 会自动捕获错误并处理 .
2. 异常捕获
异常 : 是一个事件 , 该事件会在程序执行过程中发生 , 影响程序的正常执行 .
在解释器无法正常处理程序时就会发生异常 , 程序会终止执行 .
错误类型 :
* 1. 语法错误 : 解释器在解释源文件语句前会进行语法检测出的错误 , 源代码不符合Python的编写规范 .
* 2. 逻辑错误 : 程序执行之后出现的错误 , 语法正确 , 但其代码违反逻辑规则而产生的错误 , 种类很多 . . .
异常信息三个组成部分 :
* 1. 回溯信息 : 最近一次错误所在行 :
Traceback ( most recent call last ) :
File "xxx" , line 1 , in < module >
. . .
* 2. 错误类型 :
NameError : xxx . . .
* 3. 冒号后面的错误的详情原因 , 解决bug的关键 .
语法错误必须立刻修改 , 否则程序无法执行 . 出现逻辑错误可以进行针对性处理 , 觉得是都让程序继续运行 .
异常处理语法格式 :
try :
被检测的代码 .
except 错误类型 as 接收错误信息的变量 :
被检测代码出错后的处理机制 .
try :
name
except NameError as e:
print ( e, '结束程序运行!' )
Exception 是所有异常的父类 , 所有异常都可以检测到 .
3. while循环遍历迭代器对象
l1 = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 11 , 22 , 33 , 44 , 55 ]
list_iterator = l1. __iter__( )
count = len ( l1)
while count:
i = list_iterator. __next__( )
print ( i)
count -= 1
l1 = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 11 , 22 , 33 , 44 , 55 ]
list1 = l1. __iter__( )
while True :
try :
print ( list1. __next__( ) )
except Exception:
break
* try语句检测程序会占用额外的资源 , 执行一次就有一句try语句 , 不推荐使用大量的try语句 .
4. 递归遍历迭代器对象
l1 = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 11 , 22 , 33 , 44 , 55 ]
list_iterator = l1. __iter__( )
count = len ( l1)
def func ( counts) :
if counts == 0 :
return
i = list_iterator. __next__( )
print ( i)
return func( counts - 1 )
func( count)
l1 = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 11 , 22 , 33 , 44 , 55 ]
list1 = l1. __iter__( )
def func ( list1) :
try :
print ( list1. __next__( ) )
except Exception:
return
return func( list1)
func( list1)
5. 生成器
有时候序列或集合的元素的非常多 , 如果所有对象都直接存放在内存中 , 会占用大量内存的资源 .
于是设计出一种按某种顺序推导元素的算法 , 需要哪个元素就迭代计算出哪个元素 , 而不必创建完整的元素集合 .
每次仅占用一个元素的空间 , 元素被取出后 , 给下一个计算结果使用 , 从而节省大量的空间 .
在Python中这种计算出元素的机制 , 称为生成器 : generator .
生成器属于自定义迭代器 , 生成器保存的是计算元素的算法或表达式 , 可以使用for迭代取值 .
5.1 生成器生成式
Python规定生成器生成式使用 ( ) 圆括号 .
生成器生成式能够快速生成一个生成器 , 保存了计算元素的算法 .
只有在迭代取值的时候才会执行计算元素的算法 , 每次仅提供一个元素 .
g1 = ( i for i in range ( 10 ) )
print ( g1)
print ( next ( g1) )
print ( next ( g1) )
print ( next ( g1) )
for i in g1:
print ( i, end= ' ' )
5.2 生成器的特点
生成器的特点 , 在使用的时候才会计算 , 通过一个案例来讲解 :
# a . txt
123456789
123456789
123456789
with open ( 'a.txt' ) as f:
g1 = ( len ( line) for line in f)
print ( sum ( g1) )
为何报错?ValueError : I / O operation on closed file .
ValueError : 对已关闭文件的 IO 操作 .
迭代器只有在使用的时候才执行 , 元组生成式走了过场什么都什么做 .
你以为代码是 : ( 换行 '\n' 算一个字符 . )
g1 = ( 10 , 10 , 9 )
其实代码是这样的 :
g1 = ( len ( for line in f ) , len ( for line in f ) , len ( for line in f )
当需要执行的时候 , 文件的io操作已经关闭了 , 所有报错 .
with open ( 'a.txt' ) as f:
g1 = ( len ( line) for line in f)
print ( sum ( g1) )
5.3 yield关键字
yield关键字 : 在函数内使用 , 调用函数时 , 函数不会执行 , 而是返回一个生成器 .
yield的作用 :
* 1. 当函数体内含有yield关键字时 , 那么在调用函数的时候 , 函数体代码不会执行 , 而是返回一个生成器 .
* 2. 可以使用yield设置返回值 , 也就是生成器的元素 , 多个值会组织成元组 , 不写默认返回None .
* 3. 第三种传值的方式 , yeied可以传递参数 .
1. 返回生成器
当函数体内含有yield关键字时 , 那么在调用函数的时候 , 函数体代码不会执行 , 而是直接返回一个生成器 .
def func ( ) :
print ( '你好' )
yield
res = func( )
print ( res, type ( res) )
2. 迭代取值
调用 . __next__ ( ) 方法取值时才会执行函数中的语句 , 遇到yield语句返回一个值 , 并保存当前函数的执行状态 .
下一个次 . __next__ ( ) 方法则从上次暂停的位置处往回执行 , 后续没有yield则执行到底 .
def func ( ) :
num = 0
print ( num)
yield 'yield1'
num += 1
print ( num)
yield 'yield2'
num += 1
print ( num)
res = func( )
print ( res. __next__( ) )
print ( res. __next__( ) )
try :
res. __next__( )
except StopIteration as e:
print ( e)
运行工具窗口显示 :
0
yield1
1
yield2
2
def func ( ) :
num = 0
print ( num)
yield 'yield1'
num += 1
print ( num)
yield 'yield2'
num += 1
print ( num)
res = func( )
for i in res:
print ( i)
def func ( ) :
print ( 1 )
yield
res = func( )
for i in res:
print ( i)
3. yield传参
yield传参格式 :
生成器函数 . send ( 参数 1 , ··· ) , . send ( ) 方法可以让函数运行 ( 包括yield停止的情况 ) , 遇到yield停止 .
函数中接收参数 :
value = yield
程序中第一次使用生成器调用 . send ( ) 方法时 , 不能使用带参数的send ( ) 函数 .
def my_ge ( ) :
num = yield
print ( num)
res = my_ge( )
print ( res. send( None ) )
def my_ge ( ) :
num = yield
print ( num)
res = my_ge( )
print ( res. send( 1 ) )
运行工具窗口显示 :
Traceback ( most recent call last ) :
File "C:\Users\13600\PycharmProjects\test\test.py" , line 8 , in < module >
print ( res . send ( 1 ) )
TypeError : can ' t send non-None value to a just-started generator
英 : TypeError : can ' t send non-None value to a just-started generator .
中 : 无法向刚启动的生成器发送非None值 ,
yield语句的完整执行顺序 :
* 0. 调用含有yield的函数 , 函数体代码不会执行 , 而是返回一个生成器 , 这里可以称为生成器函数 .
* 1. 使用 . __next__ ( ) 方法时会执行函数体代码
* 2. 遇到yield语句则返回跟随它的值 ( 双下next方法就是要这个值 ) , 并且会暂停函数的运行保存函数的状态 .
* 3. 生成器函数通过 . send方法 ( ) 返回一个参数给yield语句执行的结果 .
* 4. 使用变量接收yield语句执行的结果 .
* 5. 后续可以使用send传递的参数 .
执行过yield语句后 , 才能使用 . send ( ) 方法传值给yield ,
这个值作可以理解为yield语句执行的结果 , 可以使用变量接收 .
def my_ge ( ) :
while True :
print ( '执行my_ge函数!' )
num = yield '可以传递了!'
print ( num)
res = my_ge( )
print ( res. __next__( ) )
res. send( 1 )
res. send( 2 )
5.4 实例
def func1 ( ) :
for i in range ( 10 ) :
yield i + 1 - 1 * 2 / 2
def func2 ( ) :
res = func1( )
for i in res:
print ( i)
func2( )
def my_range ( start_num, end_num= None , len_num= 1 ) :
if not end_num:
end_num = start_num
start_num = 0
while start_num < end_num:
yield start_num
start_num += len_num
for i in my_range( 1 , 10 , 2 ) :
print ( i)
def test ( ) :
for i in range ( 4 ) :
yield i
g = test( )
for n in [ 1 , 10 ] :
g = ( i + n for i in g)
"""
n = 1
g = (i + n for i in g)
n = 10
g = (i + n for i in (i + n for i in test()))
"""
res = list ( g)
"""
g = (i + n for i in (i + n for i in (0, 1, 2, 3)) # n 为 10.
g = (i + 10 for i in (i + 10 for in (0, 1, 2, 3))
g = (i + 10 for i in (10, 11, 12, 13)
g = (10+10, 11+10, 12+10, 13+10
"""
print ( res)
6. 练习
1. 使用递归打印斐波那契数列 ( 前两个数的和得到第三个数 , 如 : 1 , 2 , 3 , 5 , 8 , 13. . )
def num ( x, y) :
if y > 100 :
return
y, x = y + x, y
print ( y, end= ' ' )
num( x, y)
num( 0 , 1 )
2. 一个嵌套很多层的列表 , 用递归取出所有的值 .
list1 = [ 1 , 2 , [ 3 , [ 4 , 5 , 6 , [ 7 , 8 , [ 9 , 10 , [ 11 , 12 , 13 , [ 14 , 15 ] ] ] ] ] ] ]
def get_num ( list1) :
if not len ( list1) :
return
for i in list1:
if type ( i) == int :
print ( i, end= ' ' )
else :
get_num( i)
get_num( list1)