函数的定义 什么是函数 函数就是一种具备某一功能的工具,事先将工具准备好就是函数的定义,遇到场景拿来就用。
怎么使用函数 1 2 3 4 5 ef 函数名(等同于变量)(): """对函数的描述""" 代码块 函数名()
注册功能函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 def register (): """注册功能""" count = 0 while count < 3 : username_inp = input ('请输入你的用户名:' ).strip() pwd_inp = input ('请输入你的密码:' ).strip() re_pwd_inp = input ('请再次确认你的密码:' ).strip() if re_pwd_inp != pwd_inp: print ('两次密码输入不一致!' ) count += 1 continue with open ('userinfo.txt' , 'a' , encoding='utf-8' ) as fa: fa.write(f'{username_inp} :{pwd_inp} \n' ) print ('注册成功' ) break register()
登录功能函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def login (): """登录功能""" username_inp = input ('请输入你的用户名:' ).strip() pwd_inp = input ('请输入你的密码:' ).strip() user_info = f'{username_inp} :{pwd_inp} ' with open ('userinfo.txt' , 'r' , encoding='utf-8' ) as fr: data = fr.read() user_info_list = data.split('\n' ) if user_info in user_info_list: print ('登录成功' ) else : print ('登陆失败' ) login()
函数的定义的三种形式 空函数 定义了一个函数,但啥都没有
有参函数 1 2 3 4 5 def add (x, y ): """有参函数""" print (int (x) + int (y)) add(1 , 2 )
无参函数 1 2 def func (): print ('hello world' )
函数的调用 使用函数名()
的形式就可以调用函数了
1 2 3 4 5 6 7 8 9 10 11 12 13 def func (x, y ): """给定两个数, 打印较大的数""" if x > y: print (x) else : print (y) print (func)func(10 , 20 ) <function func at 0x00000253DFEF0950 > 20
函数的返回值
1 2 3 4 5 6 7 8 9 10 def add (x, y ): return x + y res = add(1 , 2 ) print (res)3
1 2 3 4 5 6 7 8 9 10 11 12 def add (x, y ): print (x, y) res = add(1 , 2 ) print (res)1 2 None
return可以返回多个值,可以返回任意数据类型,默认用元组形式返回
1 2 3 4 5 6 7 8 9 10 11 def add (x, y ): print (2 ) return x, y, x + y res = add(1 , 2 ) print (res)2 (1 , 2 , 3 )
return会终止函数,不运行下面的代码,即使有多个return,只会执行第一个return,不会执行下一个
1 2 3 4 5 6 7 8 9 10 11 12 13 def add (x, y ): print (2 ) return x, y, x + y print ('hello world' ) return x res = add(1 , 2 ) print (res)2 (1 , 2 , 3 )
函数的参数 形参和实参 形参 在函数定义阶段括号内定义的参数,称之为形式参数,简称形参,本质上就是变量名
1 2 3 def func (x, y ): print (x) print (y)
实参 在函数调用阶段括号内传入的参数,称之为实参
位置参数 位置形参 在函数定义阶段,按照从左往右的顺序依次定义的参数,称之为位置形参
1 2 3 def func (x, y ): print (x) print (y)
位置实参 在函数调用阶段,按照从左往右的顺序定义的参数,称之为位置实参,依次传值给位置形参
默认形参 在函数定义阶段,就已经被赋值
1 2 3 4 5 def func (x, y=10 ): print (x) print (y) func(2 )
在定义阶段就已经赋值,在调用时可以不用传值;如果传值,就使用传的值
默认形参必须在位置形参之后
关键字实参 在调用函数时,按照位置形参名传值
关键字实参必须在位置实参后面
可变长参数 可变长形参之* 形参中的会将溢出的位置实参全部接收,然后存储元组的形式,然后把元组赋值给 后的参数。需要注意的是:*后的参数名约定俗成为args。
1 2 3 4 5 6 7 8 def f1 (*args ): print ('args:' , args) f1(1 , 23 , 4 ) args: (1 , 23 , 4 )
可变长形参之** 1 2 3 4 5 6 7 8 9 10 11 12 ''' 形参中的**会将溢出的关键字实参全部接收,然后存储字典的形式,然后把字典赋值给**后的参数。需要注意的是:**后的参数名约定俗成为kwargs。 ''' def f2 (a,**kwargs ): print ('kwargs:' , kwargs) f2(x=12 , a=10 , b=9 ) kwargs: {'x' : 12 , 'b' : 9 }
可变长实参之* 1 2 3 4 5 def func1 (a,b,c,d ): print (a,b,c,d) lt = [1 ,2 ,3 ,4 ] func1(*lt)
可变实参之** 1 2 3 4 5 6 def func (a, b ): print (a, b) dic = {'a' : 1 , 'b' : 2 } func(**dic)
函数对象的四大功能 在python 中一切皆对象
引用 1 2 3 4 5 6 7 8 9 10 def f1 (): print ('from f1' ) func = f1 print ('f1:' , f1)print ('func' , func)f1: <function f1 at 0x000002110991D268 > func <function f1 at 0x000002110991D268 >
作为函数参数 1 2 3 4 5 6 7 8 9 10 11 12 13 def f1 (): print ('from f1' ) def f2 (f2_f1 ): print ('f2_f1:' , f2_f1) f2(f1) print ('f1:' , f1)f2_f1: <function f1 at 0x000001E47029D268 > f1: <function f1 at 0x000001E47029D268 >
作为函数返回值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 def f1 (): print ('from f1' ) def f2 (f2_f1 ): return f2_f1 res = f2(f1) print ('res:' , res)print ('f1:' , f1)res: <function f1 at 0x0000019F13E7D268 > f1: <function f1 at 0x0000019F13E7D268 >
作为容器类元素 1 2 3 4 5 6 def f1 (): print ('from f1' ) lt = [f1, 12 , 3 , 4 , 5 ] lt[0 ]()
小练习 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 def pay (): print ('支付1e成功' ) def withdraw (): print ('提现2e成功' ) dic = { '1' : pay, '2' : withdraw } while True : msg = ''' '1': 支付, '2': 提现, '3': 退出, ''' print (msg) choice = input ('>>: ' ).strip() if choice == '3' : break elif choice in dic: dic[choice]()
函数的嵌套 函数里面嵌套函数
1 2 3 4 5 6 7 8 def f1 (): print ('from f1' ) def f2 (): print ('from f2' ) f2() f1()
名称空间和作用域 名称空间 内置名称空间 存储了内置方法的空间
数据类型内置方法;python解释器自带的方法(print / len / list / str / dict)
全局名称空间 除了内置和局部都叫全局
局部名称空间 函数内部定义的都叫局部
名称空间的执行(生成)的顺序
内置名称空间:python解释器启动的时候就有了
全局名称空间:执行文件代码的时候才会有全局
局部名称空间:函数调用的时候才会有局部
搜索顺序 从当前位置查找,找不到按照这种顺序,不会逆向寻找:局部 > 全局 > 内置 > 报错
作用域 全局作用域 内置名称空间 +全局名称空间 —> 全局作用域
局部作用域 局部名称空间 —> 局部作用域
全局作用域的 x 和局部作用域 x 没有任何关系
局部作用域1 的 x 和局部作用域2 的 x没有任何关系,即使局部作用域1和局部作用域2在同一个局部作用域下
global关键字 1 2 3 4 5 6 7 x = 10 def func (): global x x = 20 func() print (x)
nonlocal关键字 1 2 3 4 5 6 7 8 9 10 11 12 13 x = 10 def f1 (): x = 2 def f2 (): nonlocal x x = 30 f2() print (x) f1()
注意点 所有可变数据类型均可打破上述一切规则
1 2 3 4 5 6 7 8 9 10 lt = [10 ] def f1 (): lt.append(20 ) f1() print (lt)[10 ,20 ]
闭包函数 什么是闭包函数 闭包函数把 闭包函数内的变量 + 闭包函数内部的函数, 这两者包裹起来,然后通过返回值的形式返回出来。
定义在函数的内函数
该函数体代码包含对该函数外层作用域中变量的引用
函数外层指的不是全局作用域
1 2 3 4 5 6 7 8 9 10 11 12 13 def outter (): x = 10 def inner (): print (x) return inner f = outter() f() print (f)10 <function outter.<locals >.inner at 0x00000201011A7840 >
上述代码中,f是一个全局的名字,但f拿到了inner的内存地址。将一个定义在内部的函数返回出来,在全局拿到f,这个f是全局变量,这样就打破了函数的层级限制,能在任意位置使用内部的函数
闭包函数的应用 以参数的方式传值 1 2 3 4 5 6 7 import requestsdef get (url ): response = requests.get(url) print (response.text) get('https://www.baidu.com' )
这里写了一个爬虫函数,爬取百度的首页。但这样的问题就是每次想爬百度,或者其他网站都要传一堆网址,比较麻烦,所以可以用闭包函数解决。
传值另一方式: 包给函数 1 2 3 4 5 6 7 8 9 10 11 12 13 import requestsdef spider (url ): def get (): response = requests.get(url) print (response.text) return get baidu = spider('https://www.baidu.com' ) baidu() taobao = spider('https://www.taobao.com' ) taobao()
这样就很方便,以后调baidu,直接baidu()就行了
装饰器 什么是装饰器 装饰器就是 为需要装饰的函数新增了一个额外的功能,装饰器的本质就是一个 给函数增加功能的函数。
为什么要装饰器 装饰器,增加功能需要注意以下几点:
使用无参装饰器 1 2 3 4 5 6 7 8 import timedef index (): '''被装饰函数''' time.sleep(1 ) print ('welcome to index' ) index()
需要为上面的函数新增加一个功能,能够统计函数运行的时间
在原代码上修改 1 2 3 4 5 6 7 8 9 10 import timedef index (): start = time.time() time.sleep(1 ) print ('welcome to index' ) end = time.time() print (f'run time is {end - start} ' ) index()
这样就违反了不能修改原代码这一原则
1 2 3 4 5 6 7 8 9 10 import timedef index (): time.sleep(1 ) print ('welcome to index' ) start = time.time() index() end = time.time() print (f'run time is {end - start} ' )
这样写就不是装饰器,因为装饰器是一个函数
利用函数传参方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import timedef index (): '''被装饰函数''' time.sleep(1 ) print ('welcome to index' ) def time_count (func ): start = time.time() func() end = time.time() print (f'run time is {end - start} ' ) time_count(index)
虽然实现了,但改变了函数调用方式
利用闭包 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import timedef index (): '''被装饰函数''' time.sleep(1 ) print ('welcome to index' ) def deco (func ): def time_count (): start = time.time() func() end = time.time() print (f'run time is {end - start} ' ) return time_count index = deco(index) index()
这样就简单实现了一个装饰器函数,调用index不是调用最初的index了,而是调用time_count函数,但用户不知道,看起来就和原来使用一样
装饰器完善 上述的装饰器,最后调用index()的时候,其实是在调用time_count(),因此如果原始的index()有返回值的时候,time_count()函数的返回值应该和index()的返回值相同,也就是说,我们需要同步原始的index()和time_count()方法的返回值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import timedef index (): '''被装饰函数''' time.sleep(1 ) print ('welcome to index' ) return 1234 def deco (func ): def time_count (): start = time.time() res = func() end = time.time() print (f'run time is {end - start} ' ) return res return time_count res = index() print (res)
给原始index传参
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import timedef index (x ): '''被装饰函数''' time.sleep(1 ) print ('welcome to index' ) return 1234 def deco (func ): def time_count (*args,**kwargs ): start = time.time() res = func(*args,**kwargs) end = time.time() print (f'run time is {end - start} ' ) return res return time_count index = deco(index) index(10 )
使用装饰器语法糖 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import timedef deco (func ): def time_count (*args, **kwargs ): start = time.time() res = func(*args, **kwargs) end = time.time() print (f'run time is {end - start} ' ) return res return time_count @deco def index (x ): '''被装饰函数''' time.sleep(1 ) print ('welcome to index' ) return 1234 index(10 )
装饰器模板 1 2 3 4 5 6 7 def deco (func ): def wrapper (*args,**kwargs ): res = func(*args,**kwargs) return res return wrapper
装饰器小练习 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 username_list = [] def guess (age ): print ('welcome to guess age' ) age_inp = input ('请猜年龄' ).strip() age_inp = int (age_inp) if age_inp == age: print ('bingo' ) elif age_inp < age: print ('猜小了' ) else : print ('猜大了' ) def login (func ): def wrapper (*args,**kwargs ): if username_list: print ('已登录,请勿重复登录' ) res = func(*args, **kwargs) return res username_inp = input ('请输入用户名:' ).strip() pwd_inp = input ('请输入密码:' ).strip() with open ('user_info.txt' , 'r' , encoding='utf-8' ) as fr: for user_info in fr: user_info = user_info.strip() username, pwd = user_info.split(':' ) if username_inp == username and pwd_inp == pwd: print ('登录成功' ) username_list.append(username_inp) res = func(*args, **kwargs) return res else : print ('登录失败' ) res = func(*args,**kwargs) return res return wrapper guess = login(guess) guess(19 )
有参装饰器 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 import timedef outter (age ): def deco (func ): def wrapper (*args,**kwargs ): if age >= 18 : print ('成年了' ) else : print ('未成年' ) start = time.time() res = func(*args,**kwargs) end = time.time() print (f'run time is {end - start} ' ) return res return wrapper return deco @outter(19 ) def index (): '''被装饰函数''' time.sleep(1 ) print ('welcome to index' ) index()
迭代器 可迭代对象 python中一切皆对象
凡是有__iter__
方法的对象,都是可迭代对象
可迭代的对象:Python内置str、list、tuple、dict、set、file都是可迭代对象。
1 2 3 4 5 lt = [1 ,2 ,3 ,4 ] print (lt.__iter__())<list_iterator object at 0x00000211EB7565C0 >
迭代器对象 含有__iter__
和__next__
方法的对象就是迭代器对象
为什么要有迭代器对象:提供了 不依赖索引取值的手段
1 2 3 4 5 dic = {'a' :1 , 'b' :2 , 'c' :3 } dic_iter = dic.__iter__() print (dic_iter.__next__())print (dic_iter.__next__())print (dic_iter.__next__())
如果值取干净了,就会报错StopIteration
总结:
迭代器对象:执行可迭代对象的__iter__
方法,拿到的返回值就是迭代器对象。
特点:
内置__next__
方法,执行该方法会拿到迭代器对象中的一个值
内置有__iter__
方法,执行该方法会拿到迭代器本身
文件本身就是迭代器对象。
缺点:
取值麻烦,只能一个一个取,并且只能往后取,值取了就没了
无法使用len()方法获取长度
for循环原理 for循环称为迭代器循环,in后面必须是可迭代对象
1 2 3 4 5 6 7 dic = {'a' :1 , 'b' :2 , 'c' :3 } dic_iter = dic.__iter__() while True : try : print (dic_iter.__next__()) except Exception: break
总结:
含有__iter__
方法的就是可迭代对象,除了数字类型,其它都是可迭代对象。可迭代对象使用__iter__
就会变成迭代器。
含有__next__
方法的就是迭代器对象,只有文件是迭代器对象。迭代器使用__iter__
依然是迭代器
其他推导式 三元表达式 语法:条件成立时的返回值 if 条件 else 条件不成立时的返回值
1 2 3 4 5 6 7 8 9 10 11 x = 10 y = 20 if x > y: print (x) else : print (y) print (x if x > y else y)
列表推导式 1 2 lt = [i for i in range (10 )] print (lt)
字典生成式 1 2 dic = {i:i for i in range (10 )} print (dic)
zip()方法 1 2 3 4 5 6 7 8 9 res = zip ([1 ,2 ,3 ],['a' ,'b' ,'c' ]) print (res.__next__())print (res.__next__())print (res.__next__())(1 , 'a' ) (2 , 'b' ) (3 , 'c' )
利用两个列表快速生成一个字典
1 2 3 4 5 6 7 8 lt1 = ['a' , 'b' , 'c' ] lt2 = [1 , 2 , 3 ] res = zip (lt1, lt2) dic = {k: v for k, v in res} print (dic){'a' : 1 , 'b' : 2 , 'c' : 3 }
生成器 生成器:
含有yield关键字的函数叫生成器。
生成器本质上就是一个自定义的迭代器
1 2 3 4 5 6 7 def f (): yield 1 yield 2 f = f() print (f.__next__())print (f.__next__())
生成器表达式 1 2 3 f = (i for i in range (10 )) for i in f: print (i)
生成器表达式节省内存,能一个个取出值—-> 相当于老母鸡下蛋
列表推导式,一下子就取出——> 相当于一筐鸡蛋
yield与return的比较:
yield可以暂停函数,通过next取值
return可以终止函数,通过调用函数拿到值
递归 函数f内部直接或间接调用函数f本身
1 2 3 4 5 def f (): a = 1 print (a) f() f()
每一次递归,不会结束函数,并且每一次递归都会开辟内存空间,如果一直开辟内存空间,内存就炸掉了,最多递归1000次。
真正的递归必须要有退出条件
1 2 3 4 5 6 7 8 9 10 count = 0 def func (): global count count += 1 print (count) if count == 100 : return func() func()
总结:递归必须要有两个明确的阶段
递推:一层一层递归调用下去,进入下一层递归的问题规模都将会减小
回溯:递归必须要有一个明确的结束条件,在满足该条件开始一层一层回溯。
递归的精髓在于通过不断地重复逼近一个最终的结果。
匿名函数 有名函数 1 2 3 4 def func (): print ('from func' ) func()
这是一个有名函数,func就是它的名字
匿名函数
匿名函数没有名字,也不能调用函数,一般与内置方法联用
与内置函数联用 max()方法 1 2 3 4 5 6 salary_dict = { 'nick' : 3000 , 'jason' : 100000 , 'tank' : 5000 , 'sean' : 2000 }
如果想取上述薪资最多的名字,可以
1 2 print (max (salary_dict))
这里是按照字典的key比较大小,但我们要的是value比较大小,返回key
1 2 3 4 5 6 def func (name ): return salary_dict[name] print (max (salary_dict, key=func))
用匿名函数
1 print (max (salary_dict, key=lambda name: salary_dict[name]))
sorted() 对薪资进行排序, 可以用sorted方法
sorted()工作原理:
首先将可迭代对象变成迭代器对象
res=next(迭代器对象),将res当做参数传给第一个参数指定的函数,然后将该函数的返回值当做判断依据。
1 2 3 4 5 6 def func (item ): return salary_dict[item] print (sorted (salary_dict, key=func, reverse=True ))
匿名函数:
1 print (sorted (salary_dict, key=lambda name: salary_dict[name]))
map() map()工作原理:
首先将可迭代对象变成迭代器对象
res=next(迭代器对象),将res当做参数传给第一个参数指定的函数,然后将该函数的返回值作为map()方法的结果之一。
map()方法 就是一种映射,可以给可迭代对象一种对应关系
1 2 3 4 res = map (lambda x: x + 1 , [1 , 2 , 3 ]) print (list (res))
filter() filter()工作原理:
首先将可迭代对象变成迭代器对象
res=next(迭代器对象),将res当做参数传给第一个参数指定的函数,然后filter会判断函数的返回值的真假,如果为真则留下。
filter可以删选
1 2 3 4 res = filter (lambda x: x > 3 , [1 , 2 , 3 , 4 , 45 , 5 , 0 ]) print (list (res))
内置函数
掌握
方法
用法
bytes()
解码字符:print(bytes('你好', encoding='utf-8'))
chr() / ord()
chr()参考ASCII码表将数字转成对应字符;ord()将字符转换成对应的数字
divmod()
print(divmod(10, 3))
打印结果:(3, 1)
enumerate()
带索引的迭代
eval()
把字符串的引号去掉,留下来的是什么就是什么
hash()
是否哈希
了解
方法
作用
abs
绝对值
all
如果全为真则为True,否则为False
any
只有有一个为真,则为真,否则为假
bin
转换为二进制
oct
八进制
hex
十六进制
dir
列出模块所有方法
frozenset
不可变集合
globals/loals
列出所有全局变量/当前位置所有变量
pow
幂
round
四舍五入
slice
切片
sum
求和
__import__
通过字符串导入模块