0225-0303函数
1.函数
函数就类似于一个工具,提前准备好,方便后续使用
函数解决的问题:1.解决代码冗余问题 2.兼容性更强 3.修改更方便
2.函数语法结构
def my_func (a,b ):
'''注释'''
print (123 )
return [1 ,2 ,3 ]
3.函数的分类
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大分类
* 在函数定义阶段,括号中填入的变量名:def my_func (a,b )
* 形参的表现形式————变量名
* 在函数调用阶段,括号中传入的数据值: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 位置形参:在函数定义阶段,括号中从左往右填写的变量名 def index (a,b,c )
1.2 位置实参:在函数调用阶段,括号中从左往右传入的数据值 index(1 ,2 ,3 )
res = my_max(111 ,b=20 )
'''
1.在函数调用阶段,位置实参与位置形参一一对应,且个数要一致
2.位置参数不能放在关键字参数的后面(参数越简单,越靠前放)
'''
8.默认参数[重点]
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' , [])
my_func('kevin1' , '20' , )
my_func('kevin2' , '18' , )
my_func('kevin3' , '39' , )
'''
1.在调用阶段如果你给了数据值就使用你的,如果你不传数据值就使用默认的
2.当有了默认参数,可以传值或者不传值
'''
9.可变长参数[重点]
1.1 *在形参中接受多余的位置参数并组装成元组的形式一一返回
def index (x, y, *a ):
print (x,y)
print (a)
index(1 ,2 ,3 ,4 ,5 ,6 )
def index (a, b, *args ):
print (a, b, args)
index(1 , 2 , 3 )
l = [11 , 22 , 33 ,44 ,55 ]
index(l[0 ], l[1 ], l[2 ])
1.2 **在形参中接收多余的关键字参数并且将其组织成字典的形式
def func ( **a ):
print (a)
func(age=20 , name='kevin' , salary=1000 , gender='male' )
2.1 *把列表、元组内的各个元素打散,然后一一传值
def index (a, b, *args ):
print (a, b, args)
t = (11 , 22 , 33 ,44 ,55 )
index(*t)
print (*t)
2.2 **把字典内的元素打散,然后以关键字的形式一一传入
def index (**kwargs ):
print (kwargs)
index(**dict )
index(**{'username' : 'kevin' , 'age' : '18' , 'gender' : 'male' })
'''
1.不管传入多少个位置参数和关键字参数,函数都可以正常运行
2.python中推荐使用 *args **kwargs
'''
10.其他函数参数的了解
def index (a, b, *, sex, height ):
pass
index(1 , 2 , sex='male' , height='180' )
11.名称空间和作用域
2.1 内置的名称空间:在python解释器中存在
2.2 全局的名称空间:在py文件中,顶格写的代码都在全局名称空间中 查看:print (globals ())
2.3 局部的名称空间:在函数体代码执行完产生的数据 查看:print (locals ())
3.1 内置的:伴随python解释器的启动/关闭而产生/回收
3.2 全局的:伴随python文件的开始执行/执行完毕而产生/回收
3.3 局部的:伴随函数的调用/结束而临时产生/回收
首先确定你所在的位置:
4.1 如果在局部中:
局部 >>> 全局 >>> 内置
4.2 如果在全局中:
全局 >>> 内置
5.1 内置的:在任何阶段任何时间都可以使用 (全局有效)
5.2 全局的:在任何阶段任何时间都可以使用 (全局有效)
5.3 局部的:在函数内部阶段使用 (局部有效)
12.global与nonlocal关键字的使用
1.1 修改的是不可变类型,必须使用
1.2 修改的是可变类型,直接改
2.1 如果是不可变类型,必须使用
2.2 如果是可变类型,不使用
13.函数对象[函数名]
'''函数名不加括号就是函数的内存地址'''
'''函数名只要加括号,就会执行!!!!!!!!!'''
14.函数的嵌套调用
def my_max (a, b ):
if a > b:
return a
return b
def many_max (a, b, c, d ):
res=my_max(a, 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 ):
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' )
17.装饰器[重点]
在不改变被装饰对象的内部代码和原有调用方式的基础上在添加额外的功能
def index ():
pass
index()
import time
time.time()
time.sleep(3 )
17.1装饰器简易版本:统计index函数的执行时间
def outer (func_name ):
def get_time ():
start_time = time.time()
func_name()
end_time = time.time()
print ('执行了%s秒' % (end_time - start_time))
return get_time
index=outer(index)
index()
17.2进阶版本:解决参数问题
def outer (func_name ):
def get_time (*args, **kwargs ):
start_time = time.time()
func_name(*args, **kwargs)
end_time = time.time()
print ('执行了%s秒' % (end_time - start_time))
return get_time
index = outer(index)
index()
login('jack' )
17.3进阶版本:解决返回值问题
def outer (func_name ):
def get_time (*args, **kwargs ):
start_time = time.time()
res=func_name(*args, **kwargs)
end_time = time.time()
print ('执行了%s秒' % (end_time - start_time))
return res
return get_time
home=outer(home)
print (home())
17.4练习题:认证功能
is_login={'is_login' :False }
def login_auth (func_name ):
def auth ():
if is_login.get('is_login' ):
res = func_name()
return res
username = input ('username:' ).strip()
password = input ('password:' ).strip()
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语法糖
def outer (func ):
def inner (*args, **kwargs ):
print ('在函数执行之前需要添加的功能' )
res=func(*args, **kwargs)
print ('在函数执行之后需要添加的功能' )
return res
return inner
@outer
def index ():
print ('from index' )
index()
@outer
def home ():
print ('from home' )
home()
17.7双层语法糖
import time
def outer (func_name ):
def get_time (*args, **kwargs ):
start_time = time.time()
func_name(*args, **kwargs)
end_time = time.time()
print ('执行了%s秒' % (end_time - start_time))
return get_time
def login_auth (func_name ):
def auth ():
username = input ('username:' ).strip()
password = input ('password:' ).strip()
if username == 'kevin' and password == '123' :
res=func_name()
return res
else :
print ('认证失败,不能执行函数' )
return auth
@login_auth
@outer
def index ():
time.sleep(1 )
print ('from index' )
index()
17.8装饰器修复技术
from functools import wraps
'在outer函数里写'
@wraps(func_name )
'再help(index)就查找不到本质,被伪装了'
from functools import wraps
def login_auth (func_name ):
@wraps(func_name )
def auth ():
username = input ('username:' ).strip()
password = input ('password:' ).strip()
if username == 'kevin' and password == '123' :
res=func_name()
return res
else :
print ('认证失败,不能执行函数' )
return auth
17.9有参装饰器
def outter (source_data,a,b,c,d,e,f, *args, **kwargs ):
source_data='file'
def login_auth (func_name ):
def auth (*args, **kwargs ):
username = input ('username:' ).strip()
password = input ('password:' ).strip()
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 , )
def index ():
print ('from index' )
18.递归函数
import sys
print (sys.getrecursionlimit())
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.二分法
eg:l = [1 , 22 , 44 ,10 , 3 , 45 , 66 , 88 ,101 , 20 , 30 ,40 ]
'''二分法的原则:1、 列表中得数字必须要有序,不管是升序还是降序都可以,如果没有顺序就不能使用二分法'''
target_num = 100
def my_half (target_num, l ):
if len (l) == 0 :
print ('不好依稀,没找到' )
return
middle_index = len (l) // 2
if target_num > l[middle_index]:
l_right=l[middle_index+1 :]
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)
cmd = input ('请选择是否输入:(y/n)' )
res='继续' if cmd == 'y' else '不继续'
print (res)
21.列表、字典、集合生成式
name_list = ['kevin' , 'jack' , 'ly' , 'tony' ]
1. 传统做法:
new_list = []
for name in name_list:
res='%s_NB' % name
new_list.append(res)
print (new_list)
name_list = ['kevin' , 'jack' , 'ly' , 'tony' ]
'''特殊用法'''
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,变相是三元表达式
'''
'''补充:'''
"""
enumerate:使用for循环的时候,可以解压赋值出来两个值,一个是索引,一个是元素
start:控制的是起始位置,默认是从0开始
"""
res = (i for i in l1)
print (res)
22.匿名函数
def index ():
pass
"""
语法格式:
lambda 形参:返回值
lambda x:x**2
匿名函数一般不单独使用,会配合其他函数使用,res = lambda 形参:返回值,res是一个内存地址,加括号也能调用
"""
l = [1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ]
res=list (map (lambda x:x**2 , l))
print (res)
'''
1.map(函数名,要遍历的数据),map底层有一个for循环
2.l中元素分别平方后放入map
3.res = list(map(lambda x:x**2,l)) 循环完后没有打印,想要结果list转换
'''
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' , ]
res = zip (l, ll1, ll2, ll3)
print (list (res))
'''
zip(可迭代对象),zip函数中可以放多个可迭代对象,并且以最短的为主准,将索引相同的数据以元组的形式组装起来,也需要用list转一下,当可迭代对象为字典时,只取暴露在外界的key值
'''
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]))
l = [1 , 10 , 20 , 55 , 66 , 77 ]
def index (x ):
return x > 20
res=filter (lambda x:x>20 , l)
print (list (res))
'''
将符合的数据留存下来,不符合的数据去除
'''
23.可迭代对象
内置有__iter__方法的对象都是可迭代对象
'''内置的意思是python自带的,解释器中已经存在的,我们可以直接使用的'''
str , list , dict , tuple , set , 文件对象
print (c)
print (c.__iter__())
print (iter (c))
'''一般双下滑先开头的方法都有一个简便的写法,就是函数名()'''
24.迭代器对象
既有__iter__方法, 也含有__next__方法
'''1.文件对象即是可迭代对象又是迭代器对象
2.迭代器一定是可迭代对象,可迭代对象不一定是迭代器
'''
可迭代对象调用__iter__方法
注意:
迭代给我们提供了一种不依赖索引取值的方法
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循环内部其实也报错了,只不过错误没让我们看见,内部处理了'''
"""
for循环内部执行流程:(补充:内部有一个while循环)
1. 把关键字in后面的数据类型转为了迭代器 __iter__
2. 循环next取值
3. next取值完毕之后也报错了,自动处理错误并且结束while循环
"""
26.异常捕捉
2.1 Traceback
2.2 XXXError
2.3 XXXError冒号后面的内容,报错的详细原因,我们主要看的也是这部分,大致定位错误的原因
1. 语法错误
2. 逻辑错误
NameError
IndexError
KeyError
ValueError
ZeroDivisionError
...
try :
被监测的代码
except 错误的类型1 as e:
错误处理,e:错误的原因
except 错误的类型2 as e:
错误处理,e:错误的原因
except 错误的类型3 as e:
错误处理,e:错误的原因
except 错误的类型4 as e:
错误处理,e:错误的原因
'''万能异常'''
try :
d = {'a' :1 , 'b' :2 }
print (d['c' ])
except ZeroDivisionError as e:
print ('' )
except NameError as e:
print (123 )
except IndexError as e:
print (123 )
except Exception as e:
print (e)
当被监测的代码没有报错的时候执行else 语句
'''try 和 else 不能单独使用'''
不管检测的代码有没有错误,都会走finally 语句
"""
try except异常捕捉需要注意
1. try里面被监测的代码尽量少
2. 在明显没有错误的代码不要被捕捉
"""
27.生成器对象
'''生成器的作用:节省空间了'''
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__()
ret=res.__next__()
ret=res.__next__()
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:
yield start
start += step
29.yield传值(了解)
def eat ():
print ('开始干饭' )
while True :
food = yield
print ('开始吃%s' % food)
res=eat()
res.__next__()
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)
32.常见内置函数
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 ()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)