0225-0303函数
1.函数
- 函数就类似于一个工具,提前准备好,方便后续使用
- 函数解决的问题:1.解决代码冗余问题 2.兼容性更强 3.修改更方便
2.函数语法结构
def my_func(a,b):
'''注释'''
print(123)
return [1,2,3]
# 1.def:定义或声明一个函数,不能省略
# 2.函数名():相当于变量名,遵循变量名的命名规范,见名知意,括号不可省略
# 3.参数:函数的精髓,在使用函数前要满足一定的条件,可有可无
# 4.函数体代码注释:主要写一些函数功能的介绍和一些参数的解释,可有可无,最好有
# 5.函数体代码[核心]:核心
# 6.返回值:关键字是return,函数执行完毕后返回的结果,可有可无
3.函数的分类
# 1.内置函数:在python解释器中提前存在的,我们可以直接使用
# 2.自定义参数:我们自己写的参数
2.1 无参函数:没有参数的函数
2.2 有参函数:含参数的函数
2.3 空函数:啥都没有
def my_func():
pass # 补全函数的结构;帮助我们数理逻辑
4.函数的定义与调用[重点]
# 定义阶段:
1.函数必须先定义后调用
2.函数在定义阶段,如果有参数,调用阶段也需要给对应的参数
3.函数在定义阶段只检测语法是否准确,不执行具体的代码功能
# 调用阶段:
1.函数在调用阶段会执行具体的函数体代码
2.如何调用函数? 函数名()
'''
函数的底层原理:
1.申请一块内存地址,存储函数体代码
2.把函数体代码绑定给函数值
3.通过调用函数名(),执行函数体代码
'''
5.函数的返回值[重点]
'''
1.当函数没有返回值return时,返回的是None
2.当函数中只有return关键字时,返回的是None
3.当return后有数据时,写什么返回什么
4.当return后有多个数据时,会组成元组的形式返回
5.当你想返回多个值时,最好使用容器类型包一下
6.在函数中只要用到return,代码立刻终止执行,一个函数最多只能同时拥有一个return关键字
7.return只能出现在函数中,if else中绝对不可以出现
'''
6.函数参数的2大分类
# 1.形式参数
* 在函数定义阶段,括号中填入的变量名:def my_func(a,b)
* 形参的表现形式————变量名
# 2.实际参数
* 在函数调用阶段,括号中传入的数据值:my_func(1,2)
* 实参的表现形式————具体的数据值、变量、函数的返回值
a=1
b=2
res=my_min(a,b) # 实参是变量
res=my_min(10*2,10*my_min(3,4)) #实参是返回值
'''
实参以 变量名 = 数据值的形式进行传递
在函数调用阶段,实参和形参临时绑定,函数调用完毕绑定解除
'''
7.位置参数与关键字参数[重点]
# 1.位置参数:按顺序定义的参数
1.1 位置形参:在函数定义阶段,括号中从左往右填写的变量名 def index(a,b,c)
1.2 位置实参:在函数调用阶段,括号中从左往右传入的数据值 index(1,2,3)
# 2.关键字实参:可以完全不按照从左到右读懂顺序定义,但仍能为指定的形参赋值
res = my_max(111,b=20)
'''
1.在函数调用阶段,位置实参与位置形参一一对应,且个数要一致
2.位置参数不能放在关键字参数的后面(参数越简单,越靠前放)
'''
8.默认参数[重点]
#默认形参:在函数定义阶段就可以给变量赋值
# 练习题1:
# 参数的默认值如果给的是一个列表,那么,后续的数据都会指向同一个列表,(同一个内存空间)
def my_func(name, age, hobby=[]):
hobby.append(age)
print("%s:%s:%s" % (name, age, hobby))
my_func('kevin1', '20', [])
my_func('kevin2', '18', [])
my_func('kevin3', '39', [])
#kevin1:20:['20']
#kevin2:18:['18']
#kevin3:39:['39']
my_func('kevin1', '20', )
my_func('kevin2', '18', )
my_func('kevin3', '39', )
#kevin1:20:['20']
#kevin2:18:['20', '18']
#kevin3:39:['20', '18', '39']
'''
1.在调用阶段如果你给了数据值就使用你的,如果你不传数据值就使用默认的
2.当有了默认参数,可以传值或者不传值
'''
9.可变长参数[重点]
# 1.形参
1.1 *在形参中接受多余的位置参数并组装成元组的形式一一返回
def index(x, y, *a):
print(x,y)
print(a) # (3, 4, 5, 6)
index(1,2,3,4,5,6)
def index(a, b, *args ):
print(a, b, args)
index(1, 2, 3)# 1 2 (3,)
l = [11, 22, 33,44,55]
index(l[0], l[1], l[2]) # 11 22 (33,)
1.2 **在形参中接收多余的关键字参数并且将其组织成字典的形式
def func( **a):
print(a)#{'age': 20, 'name': 'kevin', 'salary': 1000, 'gender': 'male'}
func(age=20, name='kevin', salary=1000, gender='male')
# 2.实参
2.1 *把列表、元组内的各个元素打散,然后一一传值
def index(a, b, *args ):
print(a, b, args)
t = (11, 22, 33,44,55)
index(*t) # index(11, 22, 33,44,55)
print(*t) # 11 22 33 44 55
2.2 **把字典内的元素打散,然后以关键字的形式一一传入
def index(**kwargs):
print(kwargs) # {'username': 'kevin', 'age': '18', 'gender': 'male'}
index(**dict)
index(**{'username': 'kevin', 'age': '18', 'gender': 'male'}) # index(username='kevin', age='age', gender='male')
'''
1.不管传入多少个位置参数和关键字参数,函数都可以正常运行
2.python中推荐使用 *args **kwargs
'''
10.其他函数参数的了解
def index(a, b, *, sex, height): #*是分隔符号,右边的都是关键字参数;如果形参中已经有一个args了,命名关键字参数就不再需要一个单独的*作为分隔符号了
pass
index(1, 2, sex='male', height='180')
# 上述定义方式,传参的时候一定要按照关键字传参
11.名称空间和作用域
# 1.定义:存放变量值和变量名关系的地方
# 2.分类:
2.1 内置的名称空间:在python解释器中存在
2.2 全局的名称空间:在py文件中,顶格写的代码都在全局名称空间中 查看:print(globals()) # 字典形式
2.3 局部的名称空间:在函数体代码执行完产生的数据 查看:print(locals()) # 一定写在函数内部
# 3.存活周期
3.1 内置的:伴随python解释器的启动/关闭而产生/回收
3.2 全局的:伴随python文件的开始执行/执行完毕而产生/回收
3.3 局部的:伴随函数的调用/结束而临时产生/回收
# 4.名字的查找顺序
首先确定你所在的位置:
4.1 如果在局部中:
局部 >>> 全局 >>> 内置
4.2 如果在全局中:
全局 >>> 内置
# 5.作用域:作用的范围
5.1 内置的:在任何阶段任何时间都可以使用 (全局有效)
5.2 全局的:在任何阶段任何时间都可以使用 (全局有效)
5.3 局部的:在函数内部阶段使用 (局部有效)
12.global与nonlocal关键字的使用
# 1.global:局部修改全局
1.1 修改的是不可变类型,必须使用
1.2 修改的是可变类型,直接改
# 2.nonlocal:内部的局部修改外部的局部
2.1 如果是不可变类型,必须使用
2.2 如果是可变类型,不使用
13.函数对象[函数名]
# 1.函数名可以当成变量赋值
# def index():
# print('from index')
'''函数名不加括号就是函数的内存地址'''
# a = index
# a()
# print(a)
# 2. 函数名可以当成函数的实参
# def index():
# print('from index')
#
# def func(a):
# # print(a) # a => index
# a()
# print('from func')
# func(index)
# func(index())
# 3. 函数名可以当成函数的返回值
# def index():
# print('from index')
#
# def func():
# print('from func')
# return index # 返回的就是index函数的内存地址
#
# res=func() # res就是index函数的内存地址
# res()
# 4. 函数名可以当成容器类型的元素
# def index():
# print('from index')
#
# return 'from index'
#
# # l = [11, 22, 33, index]
# l = [11, 22, 33, index()]
# print(l)
'''函数名只要加括号,就会执行!!!!!!!!!'''
14.函数的嵌套调用
def my_max(a, b):
if a > b:
return a
return b
# 判断4个数的大小,返回大的
def many_max(a, b, c, d):
res=my_max(a, b) # b
res1=my_max(res, c)
res2=my_max(res1, d)
return res2
ret=many_max(1,2,3,4)
print(ret)
'''再多数的比较,最终都是两两比较
函数内部调用其他函数,注意:别出现无限递归(不要出现相互调用的情况)
'''
15.函数的嵌套定义
# 在函数内部定义函数
# 把复杂的功能隐藏起来,暴露给外界一个简单的接口
def all_func(type):
def register():
pass
def login():
pass
def shopping():
pass
def transfer():
pass
if type == '1':
register()
elif type == '2':
login()
elif type == '3':
shopping()
elif type == '4':
transfer()
else:
print('不存在')
all_func('1') # 注册功能
all_func('2') # 登录
16.闭包函数
# 闭:定义在函数内部的函数
# 包:内部函数使用外部函数名称空间中得名字
'''只有同时满足以上两个条件的函数,才是闭包函数'''
# 作用:第二种传参方式
#第一种
def index(username):
print(username)
#第二种
def outer(username):
# username = 'aaa'
def inner():
print(username)
return inner
res=outer('kevin')
res()
res()
res()
res()
res1=outer('jack')
res1()
res1()
res1()
# 拓展爬虫知识
import requests
res=requests.get('http://ww.baidu.com') # url地址不是所有的都能爬出来
17.装饰器[重点]
# 核心思想
在不改变被装饰对象的内部代码和原有调用方式的基础上在添加额外的功能
def index():
pass
index()
# 统计index函数的执行时间
import time
time.time() # 时间戳(秒数)
time.sleep(3) # 括号里面写几就是几秒
17.1装饰器简易版本:统计index函数的执行时间
# 1.一开始可以实现,但是执行不同的函数会重复相同的代码,需要优化
# 2.实现了不用重复代码,但是改变了函数原有调用方式,不是装饰器,需要优化增加闭包函数
# 3.使用闭包函数,成功实现了装饰器装饰index函数统计执行时间的功能
def outer(func_name):
# func_name = index
def get_time():
# 1. 在函数执行之前,要记录一下此时的时间
start_time = time.time()
# 2. 开始执行函数
func_name()
# 3. 函数执行完毕之后,再次记录此时的时间
end_time = time.time()
# 4. 统计函数的执行时间
print('执行了%s秒' % (end_time - start_time))
return get_time
index=outer(index) # get_time的内存地址
index()
17.2进阶版本:解决参数问题
# 1.当定义的函数括号中有参数时,简易版本调用函数括号中有无参数都会报错不能执行,不够兼容,继续优化至正常运行,引入可变长参数
# 2.将内部定义函数和从外部传过来的参数的括号中都填上可变长参数,函数执行成功
def outer(func_name):
# func_name = index
def get_time(*args, **kwargs):
# 1. 在函数执行之前,要记录一下此时的时间
start_time = time.time()
# 2. 开始执行函数
func_name(*args, **kwargs)
# 3. 函数执行完毕之后,再次记录此时的时间
end_time = time.time()
# 4. 统计函数的执行时间
print('执行了%s秒' % (end_time - start_time))
return get_time
index = outer(index) # get_time的内存地址
index()
# login=outer(login)
login('jack')
17.3进阶版本:解决返回值问题
# 1.我们想要执行函数的返回值,可当我们打印出来时,返回值是None,检查发现我们打印出来的是内部函数的返回值,需优化
# 2.我们将内部函数中真正函数返回值赋值为res,然后将内部函数的返回值写为res,最后打印,优化成功
def outer(func_name):
# func_name = index
def get_time(*args, **kwargs):
# 1. 在函数执行之前,要记录一下此时的时间
start_time = time.time()
# 2. 开始执行函数
res=func_name(*args, **kwargs) # index()
# 3. 函数执行完毕之后,再次记录此时的时间
end_time = time.time()
# 4. 统计函数的执行时间
print('执行了%s秒' % (end_time - start_time))
return res # 才是真正的函数的返回结果
return get_time
# index = outer(index) # get_time的内存地址
# res=index()
# print(res) # None
home=outer(home)
print(home())
17.4练习题:认证功能
# 1.写一个认证装饰器,定义一个index函数,让用户输入用户名和密码,如果输入正确执行index,否则不执行
# 2.升华:如果有一个函数被认证成功,后续的函数都不再认证
# 定义一个变量来存储是否认证成功
is_login={'is_login':False}
def login_auth(func_name):
# func_name = index
def auth():
if is_login.get('is_login'):
res = func_name()
return res
# 1. 让用户输入用户名和密码
username = input('username:').strip()
password = input('password:').strip()
# 2. 要认证,判断用户名和密码是否正确
if username == 'kevin' and password == '123':
# 才是正常执行的函数
res=func_name()
is_login['is_login'] = True
return res
else:
print('认证失败,不能执行函数')
return auth
'''
注意:使用标志位的时候直接使用 is_login = True会造成内部函数里的 is_login = True成为一个局部变量,与全局不是同一个is_login,老师使用字典,用可变类型修改是可以直接用不需要关键字声明
'''
17.5装饰器的固定模板
def outer(func):
def inner(*args, **kwargs):
print('在函数执行之前需要添加的功能')
res=func(*args, **kwargs)
print('在函数执行之后需要添加的功能')
return res
return inner
17.6语法糖
# 每次调用函数都要写2行很别扭,引入语法糖@outer == index = outer(index)
# 书写规范:1.语法糖要紧贴再被装饰对象的头上 2.原理:把紧贴着的被装饰对象自动传给装饰器函数
# 本质:函数的执行
def outer(func):
def inner(*args, **kwargs):
print('在函数执行之前需要添加的功能')
res=func(*args, **kwargs)
print('在函数执行之后需要添加的功能')
return res
return inner
@outer # index=outer(index)
def index():
print('from index')
index()
@outer
def home():
print('from home')
home()
17.7双层语法糖
# 写的时候从上往下写,执行的原理是从下往上,实际执行是从上往下
# 调用的时候虽然名字一样,但是并不是原函数,被装饰器伪装了
import time
def outer(func_name):
# func_name = index
def get_time(*args, **kwargs):
# 1. 在函数执行之前,要记录一下此时的时间
start_time = time.time()
# 2. 开始执行函数
func_name(*args, **kwargs)
# 3. 函数执行完毕之后,再次记录此时的时间
end_time = time.time()
# 4. 统计函数的执行时间
print('执行了%s秒' % (end_time - start_time))
return get_time
def login_auth(func_name):
# func_name = index
def auth():
# 1. 让用户输入用户名和密码
username = input('username:').strip()
password = input('password:').strip()
# 2. 要认证,判断用户名和密码是否正确
if username == 'kevin' and password == '123':
# 才是正常执行的函数
res=func_name()
return res
else:
print('认证失败,不能执行函数')
return auth
@login_auth # index=login_auth(get_time)
@outer # get_time=outer(index)
def index():
time.sleep(1)
print('from index')
index() # auth()
17.8装饰器修复技术
# print(index)和help(index)可以帮助看清本质
#固定用法:
from functools import wraps
'在outer函数里写'
@wraps(func_name) # 为了让被装饰对象不容易被察觉,没啥用
'再help(index)就查找不到本质,被伪装了'
from functools import wraps
def login_auth(func_name):
# func_name = index
@wraps(func_name) # 修复技术是为了让被装饰对象不容易被察觉装饰了
def auth():
# 1. 让用户输入用户名和密码
username = input('username:').strip()
password = input('password:').strip()
# 2. 要认证,判断用户名和密码是否正确
if username == 'kevin' and password == '123':
# 才是正常执行的函数
res=func_name()
return res
else:
print('认证失败,不能执行函数')
return auth
17.9有参装饰器
# 在无参装饰器外面再包一层来装参数
# 写死了,解决办法和无参装饰器一样
# @outer('file')函数名遇到括号优先级最高,先执行out('file'),然后@+返回结果,又变成双层装饰器,外面包一层仅仅是为了传参
# 假如还需要参数,不需要再包,直接再外面的函数括号李传参,就是普通函数传参
def outter(source_data,a,b,c,d,e,f, *args, **kwargs):
source_data='file'
def login_auth(func_name):
# func_name = index
def auth(*args, **kwargs):
# 1. 让用户输入用户名和密码
username = input('username:').strip()
password = input('password:').strip()
# 2. 要认证,判断用户名和密码是否正确
if source_data == 'file':
print('数据来源是文件')
elif source_data=='mysql':
print('数据来源是MySQL')
elif source_data=='oracle':
print('数据来源是oracle')
else:
print('认证失败,不能执行函数')
return auth
return login_auth
@outter('file',1,2,3,4,5,6,) # @login_auth
def index():
print('from index')
18.递归函数
# 1.什么是递归函数:间接或直接调用自己
# 2.python官网介绍默认的递归深度是1000,
import sys
print(sys.getrecursionlimit()) # 修改递归深度
# 3.使用场景:一排学生的年龄,层层相扣
# 4.递归
1.递推:逐层寻找答案
2.回溯:根据最终的答案推导出最原始的答案
3.递归函数必须有结束条件
# 练习题:
lst = [1, [2, [3, [4, [5, [6, [7, ]]]]]]]
def get_lst(l):
for i in l:
if type(i) is int:
print(i)
else:
get_lst(i)
'''
1.递归函数可以借助debug功能更好地观察内部执行的情况
2.无限极分类
'''
19.二分法
# 1.算法:解决问题的高效方法,eg:二分法、冒泡、选择排序
# 2.二分法的使用
# 二分法的使用
eg:l = [1, 22, 44 ,10, 3, 45, 66, 88,101, 20, 30 ,40]
# 判断这个列表中是否有20这个数字
'''二分法的原则:1、 列表中得数字必须要有序,不管是升序还是降序都可以,如果没有顺序就不能使用二分法'''
# 代码实现二分法
target_num = 100
def my_half(target_num, l):
if len(l) == 0:
print('不好依稀,没找到')
return
middle_index = len(l) // 2 # 小数 # 6
if target_num > l[middle_index]:
l_right=l[middle_index+1:] # l[7]
print(l_right)
my_half(target_num, l_right)
elif target_num < l[middle_index]:
l_left=l[:middle_index]
print(l_left)
my_half(target_num, l_left)
else:
print('找到了')
my_half(target_num, l)
20.三元表达式
def my_max(a, b):
if a > b:
return a
else:
return b
'''三元表达式实现上述功能'''
def my_max(a, b):
return a if a > b else b
"""
语法结构:
条件成立之后的结果 if 条件 else 条件不成功之后的结果
使用场景:结果二选一的情况
"""
a = 1
b = 10
c = 10
d = 20
res=a if a > b else (c if c > d else ( 'bbb' if d > c else 'aaa'))
print(res)
# is_beautiful=True
# res = '漂亮' if is_beautiful else '不漂亮'
# print(res)
cmd = input('请选择是否输入:(y/n)')
res='继续' if cmd == 'y' else '不继续'
print(res)
21.列表、字典、集合生成式
name_list = ['kevin', 'jack', 'ly', 'tony']
# 需求是:把列表中得名字都添加一个后缀:_NB
1. 传统做法:
new_list = []
for name in name_list:
res='%s_NB' % name
new_list.append(res)
print(new_list)
# 需求:除了jack不加,其他都加,如果是jack直接去掉
name_list = ['kevin', 'jack', 'ly', 'tony']
# new_list = []
# for name in name_list:
# if name == 'jack':
# continue
# else:
# res = '%s_NB' % name
# new_list.append(res)
# print(new_list)
# 列表生成式的使用
# res = ['%s_NB' % name for name in name_list if name != 'jack']
'''特殊用法'''
res = ['%s_NB' % name if name != 'jack' else '666' for name in name_list ]
print(res)
"""
语法格式:
res=[变量 for 变量 in 可迭代对象]
res=[变量 for 变量 in 可迭代对象 if 条件]
res=[变量 if 条件 else 666 for 变量 in 可迭代对象 ]
"""
'''
1.循环后面加了if后不可以加else,因为这样就不知道是用于for还是if,也不能加括号
2.把if写在前面,循环写在后面的话可以用else,变相是三元表达式
'''
'''补充:'''
# count=0
# for i in l1:
# print(count, i)
# count+=1
# 记忆
"""
enumerate:使用for循环的时候,可以解压赋值出来两个值,一个是索引,一个是元素
start:控制的是起始位置,默认是从0开始
"""
# for i, j in enumerate(l1, start=2):
# print(i ,j)
# 2. 字典生成式
# res = {i:j for i, j in enumerate(l1)}
# print(res)
# 集合
# res = {i for i in l1}
# print(res)
# 元组
# 迭代器
res = (i for i in l1)
print(res) # generator
22.匿名函数
# 1.没有名字的函数
def index():
pass
"""
语法格式:
lambda 形参:返回值
lambda x:x**2
匿名函数一般不单独使用,会配合其他函数使用,res = lambda 形参:返回值,res是一个内存地址,加括号也能调用
"""
# 2.map函数
l = [1,2,3,4,5,6,7,8,9]
# def index(x):
# return x**2
# res=list(map(index, l)) # <map object at 0x0000017D935721F0>
res=list(map(lambda x:x**2, l)) # <map object at 0x0000017D935721F0>
print(res) # [1, 4, 9, 16, 25, 36, 49, 64, 81]
'''
1.map(函数名,要遍历的数据),map底层有一个for循环
2.l中元素分别平方后放入map
3.res = list(map(lambda x:x**2,l)) 循环完后没有打印,想要结果list转换
'''
# 3.zip拉链
l = [11, 22, 33, 44, 55, 66]
ll1 = ['name', 'age', 'hobby', 'aaa', 'b', 'ccc', 'ddd', 'fff']
ll2 = ['nam2e', 'age1', 'hobby1', 'aaa1', 'b', 'ccc', 'ddd', 'fff']
ll3 = ['name1', 'age2', 'hobby2', 'aaa2', ]
# d1 = {'username': 'tony'}
# d2 = {'username1': 'kevin'}
# [(11,'name'), (22, 'age'), (33, 'hobby')]
# lst = []
# for i in range(len(l)):
# lst.append((l[i], ll1[i]))
# print(lst)
res = zip(l, ll1, ll2, ll3) # <zip object at 0x000001646C22FE00> [(11, 'name'), (22, 'age'), (33, 'hobby')]
print(list(res))
'''
zip(可迭代对象),zip函数中可以放多个可迭代对象,并且以最短的为主准,将索引相同的数据以元组的形式组装起来,也需要用list转一下,当可迭代对象为字典时,只取暴露在外界的key值
'''
# 4.max()求最大值、min()求最小值
# l = [1, 2, 10, 30, 5, 6, 7, 8]
# 求出列表中最大值
# print(max(l))
# 求出最小值
# print(min(l))
#
d = {
'Aevin': 10000,
'zack': 2000,
'zony': 30000,
'Fank': 5000000000
}
'''
A-Z:65-90
a:97
'''
'''如果是字典,比较的是key,说白了就是你暴露什么,就按照什么比较'''
'''还可以进行字符串的比较,内部是按照ASCII码对应十进制数比较'''
def index(key):
return d[key]
'''如果传了key参数,就是返回什么值就按照什么值比较'''
print(max(d, key=index))
print(max(d, key=lambda key:d[key]))
print(min(d, key=index))
print(min(d, key=lambda key:d[key]))
# 5.filter 过滤器
l = [1, 10, 20, 55, 66, 77]
# ll = []
# for i in l:
# if i > 20:
# ll.append(i)
# print(ll)
def index(x):
return x > 20
# res=filter(index, l)
res=filter(lambda x:x>20, l)
print(list(res)) # [55, 66, 77]
'''
将符合的数据留存下来,不符合的数据去除
'''
23.可迭代对象
# 1.迭代:每一次的结果必须依赖于上一次的结果
# 2.可迭代对象:
内置有__iter__方法的对象都是可迭代对象
'''内置的意思是python自带的,解释器中已经存在的,我们可以直接使用的'''
# 目前我所学的数据类型中,有哪些是可迭代对象, 都支持for循环
str, list, dict, tuple, set, 文件对象
print(c)
print(c.__iter__()) # <str_iterator object at 0x0000017E0C21C610>
print(iter(c)) # <str_iterator object at 0x000001B18D4DC610>
# print(c.__len__()) # 5
# print(len(c))
'''一般双下滑先开头的方法都有一个简便的写法,就是函数名()'''
24.迭代器对象
# 1.迭代器对象
既有__iter__方法, 也含有__next__方法
'''1.文件对象即是可迭代对象又是迭代器对象
2.迭代器一定是可迭代对象,可迭代对象不一定是迭代器
'''
# 2.如何生成迭代器对象
可迭代对象调用__iter__方法
注意:
迭代给我们提供了一种不依赖索引取值的方法
# 练习题:hello
res=c.__iter__()
res.__next__()
res.__next__()
res.__next__()
res.__next__()
print(c.__iter__().__next__())
print(c.__iter__().__next__())
print(c.__iter__().__next__())
print(c.__iter__().__next__())
print(c.__iter__().__next__())
'''当元素被取完的时候,再去利用__next__取值,会直接报错的'''
25.for循环内部原理
l = [1, 2, 3, 4, 5, 6, 7]
# 要求:循环打印出列表中每个元素,但是,不能使用for循环,__next__ next()
# 1. 可迭代对象要转为迭代器
# res = l.__iter__()
#
# while True:
# print(res.__next__())
# for i in l:
# print(i)
'''for循环内部其实也报错了,只不过错误没让我们看见,内部处理了'''
"""
for循环内部执行流程:(补充:内部有一个while循环)
1. 把关键字in后面的数据类型转为了迭代器 __iter__
2. 循环next取值
3. next取值完毕之后也报错了,自动处理错误并且结束while循环
"""
26.异常捕捉
# 1. 什么是异常?
# 异常就是错误发生的信号,如果此信号不做处理,那么,从本行开始之后的代码都不能正常执行了
# 2. 异常
2.1 Traceback
2.2 XXXError
# 错误的类型
2.3 XXXError冒号后面的内容,报错的详细原因,我们主要看的也是这部分,大致定位错误的原因
# 3. 异常的种类
1. 语法错误
# 是坚决不允许的,遇到之后要立刻改正,否则,代码不能运行
2. 逻辑错误
# 是可以被允许的,但是,我们写逻辑的时候要尽可能的避免逻辑错误的发生
# 4. 常见的错误类型
NameError
IndexError
KeyError
ValueError
ZeroDivisionError
...
# 5. 如何捕捉异常
try:
被监测的代码
except 错误的类型1 as e:
错误处理,e:错误的原因
except 错误的类型2 as e:
错误处理,e:错误的原因
except 错误的类型3 as e:
错误处理,e:错误的原因
except 错误的类型4 as e:
错误处理,e:错误的原因
'''万能异常'''
try:
# print(username)
# print(1/ 0)
# l = [1,2,3,4]
# print(l[6])
d = {'a':1, 'b':2}
print(d['c']) #KeyError
except ZeroDivisionError as e:
print('')
except NameError as e:
print(123)
except IndexError as e:
print(123)
except Exception as e:
print(e) # name 'username' is not defined
# 6.else:
当被监测的代码没有报错的时候执行else语句
'''try 和 else 不能单独使用'''
# 7.finally:
不管检测的代码有没有错误,都会走finally语句
"""
try except异常捕捉需要注意
1. try里面被监测的代码尽量少
2. 在明显没有错误的代码不要被捕捉
"""
27.生成器对象
# range()
'''生成器的作用:节省空间了'''
# 生成器就是迭代器的一种
def index():
print('from index')
print('hello world')
yield 123
print('second')
print('second')
print('second')
print('second')
print('second')
yield 222
print('three')
""""
函数中如果存在yield关键字,在调用函数之前,还是一个普通函数,一旦调用函数,就把函数变成了生成器(迭代器)
****************
生成器一定是迭代器
迭代器不一定是生成器
***************
"""
'''next取值我们称之为迭代取值,另外还有索引取值'''
迭代取值
1.只能从前往后挨个取值,不能倒回去,除非重新生成一个新的迭代器
2.支持所有数据类型
索引取值
1.重复取值
2.不支持所有的数据类型,支持可以索引取值(列表、元组、字符串)的数据类型
res=index() # 此时就是生成器
ret=res.__next__() # 代码遇到yield关键字,会被冻结
ret=res.__next__() # 再次执行next(),代码从上一次被冻结的位置继续往下执行
ret=res.__next__()
# print(ret)
#与迭代器的区别:
1.生成器一定是迭代器,迭代器不一定是生成器
2.迭代器具备iter()和next()方法
3.如果让一个函数变成生成器,它也具备iter()和next()方法
4.生成器具备一个yield关键字,代码遇到yield关键字,会被冻结,再次执行next(),代码从上一次被冻结的位置继续往下执行
28.生成器的案例:实现range方法
'''
当生成器函数中含有return时,return不会返回任何值,会直接终止当前生成器,对yield的作用没有影响,当函数执行到return时候,调用next()来执行生成器则会报错,如果使用for循环遍历,for循环会自动捕获该异常,直接停止遍历
'''
range(1, 10)
for i in range(1, 10):
print(i)
for i in my_range(1, 10):
print(i)
def my_range(start, stop=None, step=1):
if not stop:
stop = start
start=0
while start < stop: # 0<stop
yield start
start += step
# for i in my_range(1, 10):
29.yield传值(了解)
def eat():
print('开始干饭')
while True:
food = yield
print('开始吃%s' % food)
res=eat() # 只是把函数变成了生成器
res.__next__() # 取值,取到第一次遇到yield,然后冻结
# 1. 调用了__next__ 2. 传参数
res.send('臭豆腐') #
res.send('臭豆腐1')
res.send('臭豆腐2')
res.send('臭豆腐3')
res.send('臭豆腐4')
30.yield与return的对比
yield
1. 可以有返回值
2. 函数遇到yield不会结束,只会'冻结'
3. yield关键字把函数变成了生成器,支持迭代取值了
return
1. 可以有返回值
2. 遇到return关键字直接结束函数运行
31.生成器表达式
# 笔试题:
def add(n, i):
return n + i
def test():
for i in range(4):
yield i
g = test()
for n in [1, 10, 11]:
g = (add(n, i) for i in g)
"""
第一次循环:
g = (add(1, i) for i in g)
第二次循环:
g = (add(n, i) for i in (add(n, i) for i in g))
"""
res = list(g)
print(res)
# A. res=[10,11,12,13]
# B. res=[11,12,13,14]
# C. res=[20,21,22,23]
# D. res=[21,22,23,24]
32.常见内置函数
# 1.eval 识别简单的python代码
# 2.exec 识别较复杂代码,可以包括eval
# 3.isinstance 判断数据类型isinstance(123,int)相当于 type(123) is int
# 4.chr 根据asci码表,填入对应的十进制,返回对应的字符
# 5.ord 根据ASCII码表,填入对应的字符,返回对应的十进制
# 6.sum 求和
# 7.pow 求幂 pow(4,3)
# 8.bytes 字符转字节,相当于编码encode;str,字节转字符串,相当于解码decode
# 9.callable 查看是否能够被调用,返回布尔值
# 10.round 四舍五入
# 12.abs 绝对值
# 13.all 所有的值是真才是真,返回布尔值
# 14.any 只要有一个值为真就是真,返回布尔值
# 15.divmod 第一个参数是商,第二个参数是余数,以元组的形式返回,可以解压赋值,用于分页功能
# 16.locals 返回当前所有局部变量。它是一个字典
# 17.globals 以字典类型返回当前位置的全部全局变量
# 18.其他已学
dict()\int()\float()\tuple()\list()\set()\str()\bool()
help()\next()\iter()\id()\input()\open()\print()\type()
hex()\bin()\oct()
enumerate()\min()\max()\filter()\format()\len()\range()\map()