目录
函数 装饰器,迭代器,面向过程编程
1、什么是函数?
def 函数名()
参数:
参数:
在函数的定义阶段,写在括号中变量名就是形参
实参:
在函数的调用阶段,写在括号中的具体的值就是实参
是在调用函数的时候生效,函数执行结束关系解除
注释
1、要写当前函数具体的功能
2、解释当前函数参数作用
3、解释当前函数返回值的特点
函数体代码:函数的具体功能
函数的返回值:
1、不写返回值
ython中所有的函数都有返回值,不写默认为None
2、写return,返回一个值
1、return
函数体代码结束的标识,默认None
2、return None
函数体代码结束的标识,默认None
3、return 值
可以是python的任意数据类型
3、写return,返回多个值
return 值1,值2,值3...
以逗号隔开多个值,可以返回多个任意类型的值,最后以元组的形式返回给调用者
return [值1,值2,值3...]
自己指定返回的数据类型
def index(x,y,z):
return x,y,z
a,*_ = index(1,2,3)
print(a,*_)
4、参数的详细描述
1、位置参数
1、位置参数
在函数定义阶段按照顺序从左到右书写的变量名就叫位置形参
在函数调用阶段按照顺序从左到右书写的具体的值就叫位置实参
位置参数定义之后一定要传递参数
2、关键字参数
在函数调用阶段,以key=value形式进行,关键子参数
3、默认值参数
在函数定义阶段提前给形参赋值的操作就叫默认值参数
4、可变长参数
*
**
* 在函数定义阶段:接收所有溢出的位置参数,将接受的值以元组的形式传入* 后面的变量中
* 在函数调用阶段:将列表、元组、字符串、集合等可以使用的for循环的容器类型打散成位位置参数
** 在函数定义阶段:接收所有溢出的关键字参数,将接受的值以字典的形式传入** 后面的变量中
** 在函数调用阶段:将字典打散成关键字参数传入形参
5、定义函数的三种形式
1、无参函数:
def index():
print("from index")
2、有参函数:
def func(x,y):
print(x,y)
3、空函数
def register():
pass
def login():
pass
。。。
命名关键字参数
# 定义在* 和**之间
# 在给命名关键字传值的时候一定要以关键字形式传递
def index(x, y, z, *args, a=1, b, **kwargs):
print(x, y, z)
print(args)
print(a, b)
print(kwargs)
index(1, 2, 3, 354353, 4342, 3213123, a=111, b=222, c=333, d=444)
函数对象
1.函数对象什么?
函数的名字就是函数对象,函数名指向的是函数的内存地址。
函数对象四大特征:
1.函数名可以被的引用
def index()
print('from index')
a = index
a() #直接加括号调用
from index
2.可以当作参数传给一个函数
def func():
print('123')
def func1(new):
new()
func1(func)
123
3.可以当作一个返回值。
def func():
print('123')
return func
msg = func()
print(msg)
msg()
123
<function func at 0x000002B054691F78>
123
4.可以当作容器类型的元素。
dic = {}
def abc():
print('oldboy')
dic['a'] = abc
print(dic)
res= dic['a']
res()
{'a': <function abc at 0x00000284A3D11EE8>}
oldboy
列:
def register():
print('register')
def login():
print('login')
def shopping():
print('shopping')
def pay():
print('pay')
func_dic = {
'1': register,
'2': login,
'3': shopping,
'4': pay
}
def main():
while True:
print("""
1、注册
2、登录
3、购物
4、付款
5、退出
""")
choice = input("请输入对应的编号:").strip()
if choice == '5':
break
if choice not in func_dic:
continue
else:
func_dic[choice]()
main()
函数对象的应用:
补充--》可以优雅地取代if分支
函数的嵌套
函数嵌套定义: 让内层函数封闭起来,不让外部直接调用。
函数的嵌套调用:在函数内调用函数
def f1():
def f2():
print('from f2')
f2()
f1()
from f2
# 函数的嵌套定义:
def index():
def home():
print("from home")
home()
index()
名称空间
什么是名称空间?
用来存放名字的,名称空间是一个在内存中的空间。
名称空间的分类?
1.内置名称空间:
python提前给你的定义完的名字,就是存在内置名称空间, 简称:存放内置方法
2.全局名称空间
除了内置和局部就是全局
存放于文件级别的名字,就是全局名称空间
if while for 内部定义的名字执行之后都存放于全局名称空间
3.局部名称空间
函数内部的定义的变量/函数
函数内部定义的所有名字都是存放与当前函数的内置名称空间
生命周期:
1、内置名称空间
在python解释器启动的时候生效,关闭解释器的时候失效
2、全局名称空间
当你启动当前这个py文件的时候生效,当前页面代码执行结束之后失效
3、局部名称空间
当你调用当前函数时生效,函数体最后一行代码执行结束就失效名称空间的查找顺序:
名称空间的查找顺序:内置 --》 全局 --》 局部
局部:局部 > 全局 > 内置
全局:全局 > 内置 # 内置再找不到就报错
函数内部使用的名字,在定义阶段已经规定死了,与你的调用位置无关
作用域的分类
全局作用域
全局可以调用的名字就存在于全局作用域
内置名称空间+全局名称空间
局部作用域
局部可以调用的名字就存放与局部作用域局部名称空间
需要注意的是:作用域关系在函数定义阶段就固定死了,与函数的调用无关。
global
局部的可以修改全局的
修改全局作用域中的变量。
x = 1
def f1():
x = 2
def f2():
# global x # 修改全局
x = 3
f2()
f1()
print(x)
# 1
只有可变类型可以在局部修改外部变量的值
nonlocal
局部的修改外层局部的
x = 1
def f1():
x = 2
def f2():
# nonlocal x
x = 3
f2()
print(x)
f1()
2
x = 1
def f1():
x = 2
def f2():
nonlocal x
x = 3
f2()
print(x)
f1()
3
命名关键字参数
定义在* 和**之间# 在给命名关键字传值的时候一定要以关键字形式传递# 关键字参数一定不能放在位置参数前面
1.可变长参数
可变长参数:在调用函数时,参入的参数个数可以不固定。
调用函数时,传值的方式莫非两种,一种是位置实参,另一种是关键字实参,因此形参也必须的有两种解决方式,以此来分别接收溢出的位置实参(*)也关键字实参(**)
一.可变长形参之*
形参中的会将溢出的位置实参全部接收,然后存储元组的形式,然后把元组赋值给后的参数。需要注意的是:*后的参数名约定俗成为args。
二 .可变长实参之*
实参中的, 会将后参数的值循环取出,达三成位置实参。以后但凡碰到实参中带的,他就是位置实参,应该马上打散成位置实参去看。
三. 可变长实参之**
形参中的** 会将溢出的关键字实参全部接收,然后存储字典的形式,然后把字典赋值给** 后的参数。需要注意的是:**后的参数名约定俗成为kwargs。
def func(**kwargs):
print(kwargs)
func(a=5) #{"a":5}
四 .可变长实参之**
实参中的,会将** 后参数的值循环取出,打散成关键字实参。以后但凡碰到实参中带**的,它就是关键字实参,应该马上打散成关键字实参去看。
五. 关键字形参
现在有一个需求,函数的使用者必须按照关键字实参传。
def register(x, y, **kwargs):
if 'name' not in kwargs or 'age' not in kwargs:
print('用户名和年龄必须使用关键字的形式传值')
return
print(kwargs['name'])
print(kwargs['age'])
register(1, 2, name='liangjing', age=20)
#liangjing
# 20
命名关键字形参:在函数定义阶段,*后面的参数都是命名关键字参数。
特点:在传值时,必须按照key=value的方式传值,并且key必须命名关键字参数的指定的参数名。
闭包函数:
闭包函数是
: 函数对象、函数嵌套、名称空间与作用域的结合体。
注意:
1.必须要在函数内定义
- 2.可以引用外层函数的名字
def outer(x):
def inner():
print(x)
pass
return inner
x = 10
inner = outer(x)
inner()
闭包函数的作用
- 闭包函数的作用:
1.为了装饰器作准备的。
2.减少代码冗余
装饰器:
1.什么是装饰器?
在不修改被装饰对象的源代码与调用方式的前提下,为其添加新的功能。
2.定义装饰器:
- 不修改被装饰对象的源代码
- 不修改被装饰对象的调用方式
- 被装饰对象 ---》 需要添加新功能的 函数
- 装饰器 ---> 为需要添加新功能的函数添加功能 函数
# 模板
def wrapper(func): # func函数对象 ---> 被装饰对象
# *args, **kwargs用于接收被装饰对象的参数
def inner(*args, **kwargs):
# 在调用被装饰对象前 添加新功能
res = func(*args, **kwargs)
# 在调用被装饰对象后 添加新功能
return res
return inner
3.统计时间认证
import time
def download_movie():
print('开始下载')
time.sleep(5)
print('下载结束')
return 'cang老师.mp4'
def time_record(func):
def inner(*args, **kwargs):
start_time = time.time() # 获取当前时间戳
res = func(*args, **kwargs) # func --> download_movie
end_time = time.time()
print(end_time - start_time)
return res
return inner
4.装饰器的语法糖
语法糖是python内置的,可以引用所有的装饰器
@: 就是语法糖
- 如何使用:
@装饰器
def 被装饰对象():
pass
注意: 使用语法糖必须遵循,装饰器的定义必须要在被装饰对象之上。
有参装饰器模板
def user_info(user):
def wrapper(func):
def inner(*args,**kwargs):
res = func(*args,**kwargs)
return res
return inner
return wrapper
无参装饰器模板
def wrapper(func):
def inner(*args,**kwargs):
res = func(*args,**kwargs)
# 在被装饰对象前调用添加功能
return res
return inner
1.叠加装饰器
1.叠加装饰器
同一个被装饰对象可以叠加装饰多个装饰器
装饰顺序:
由下往上装饰
执行顺序:
由上往下执行
2.有参装饰器
本质上就是在无参装饰器上套了一个外层函数,
无参装饰器可以引用外层函数的名字。
应用:用户权限的认证
无参装饰器与有参装饰器的使用
@无参装饰器
- @有参装饰器('参数1', '参数2') ---》 调用有参装饰器会得到一个无参装饰器
3.迭代器
迭代
迭代: 重复迭代的过程,每一次都是基于上一次的结果而来的。
迭代器:
迭代取值的工具。
可迭代对象:
凡是内部有__iter__()方法对象。
list, str, tuple, dict, set, f
获取迭代器:
list1 = [1, 2, 3]
# 调用__iter__()会得到一个返回值,该返回值是一个迭代器对象。
iter_list = list1.__iter__()
如何通过迭代器取值
每一次调用__next__()都会从迭代器中取出一个值
iter_list.__next__()
注意: 取到最后一个时,若值没有,则会报错。
捕获异常
while True:
try:
print(iter_list.__next__())
except StopIteration:
break
for循环原理
# in: 会将可迭代对象自动调用__iter__()变成迭代器对象。
for i in 可迭代对象:
# 会自定帮你调用__next__
print(i)
# for循环内部也会有一个捕获异常机制,一旦遇到异常也会停止取值。
迭代器的优缺点:
优点:
1.提供了一种不依赖于索引的取值方式
2.节省内存
缺点:
1.指定取某个值麻烦,每一次取值都要从第一个开始查找补充:
2.不能通过len计算长度
.生成器
生成的工具
生成器是一个自定义的迭代器。
yield:方法
- yield必须在函数内部定义
- yield可以保存函数的暂停状态
yield的效果与return雷同
生成器 ---》 生成器对象
迭代器 ---》 迭代器对象
凡是函数内部有yield,在调用函数时不会执行函数体代码,会返回一个生成器对象,本质上是一个迭代器。
return与yield的区别:
相同点:
都可以返回无限制的值。
不同点:
yield可以返回多次值,return只能返回一次
迭代器对象.__next__() == next(迭代器对象)
.面向过程编程
核心是 “过程” 二字, 过程指的是解决问题的步骤,即先干什么再干什么。
基于该编程思想编写程序,就好在设计一条流水线,一种机械式的思维方式。
# 设计编写程序的步骤:
注册功能: ----> 用户合法性的校验 ----> 拼接用户数据格式---->
保存到文件中。
优缺点
优点:
复杂的流程化,进而简单化
缺点:
牵一发而动全身,扩展性差
.三元表达式
成立返回的结果 if 判断条件 else 不成立返回的结果
列表生成式
- 生成一个列表
# for循环了几次,列表中就有几个值
l = [line for line in 可迭代对象]
[任意的值 for line in 可迭代对象]
print(l) # list
生成器生成式
- 生成一个生成器对象 ---》 生成一个迭代器对象
tuple = ()
(line for line in 可迭代对象)
g = (任意值 for line in 可迭代对象)
print(g) # 生成器对象
列表生成式与生成器生成式的区别
- 列表生成式
优点:
可以依赖于索引取值,取值方便
缺点:
在数据量过大时浪费资源
- 生成器生成式
优点:
在数据量过大时节省资源
缺点:
不依赖于索引取值,取值麻烦。
匿名函数
匿名函数
匿名函数:没有名字的函数:
lambda x: x + x # ---> 内存地址
# def (x):
# return x + x
名字 = lambda x: x + x
名字() # 匿名---》 有名 ---》 还不如直接通过def 来定义。
有名字的函数:
def 名字(x): # 名字 ---> 内存地址
pass
注意
函数名字 + ()调用,执行函数体代码
匿名函数没有名字,不能单独使用。
匿名的应用:
配合内置函数一起使用。
内置函数
max: 获取可迭代对象中最大值
min: 获取可迭代对象中最小值
sorted: 对可迭代对象中的数据进行排序
默认是: 升序
reverse=True: 降序
map,reduce,filter
map: 映射
map(函数地址, 可迭代对象)
将可迭代对象中的值遍历取出,并且按照指定的规则映射出新的map对象。
调用返回的是map对象。
reduce: 合并
reduce(函数地址, 可迭代对象, 初始值)
将可迭代对象中的值两两合并,并且可以设置初始值
return 合并后的值
filter: 过滤
filter(函数地址, 可迭代对象)
将可迭代对象中的值遍历取出,然后通过判断,若条件成立 “过滤获取” 对应的值。
并将获取的值放到一个filter对象中。
return filter对象
函数递归
函数重复 “直接或间接” 调用函数本身,会进入死循环。
缺点:
1.毫无意义
2.内存溢出
有意义的递归:
- 递推:
指的是重复地执行, 每一次执行都要拿到一个更接近于结果的结果,
递推必要有一个终止条件。
- 回溯:
当递推找到一个终止条件后,开始一步一步往上回溯,最终得到一个结果。
age(5) = age(4) + 2
age(4) = age(3) + 2
age(3) = age(2) + 2
age(2) = age(1) + 2
age(1) = 80