# 昨日内容复习
'''
函数
什么是函数
def 是定义函数的关键字
函数名 命名规范与变量名的命名规范一致
1.不能与关键字冲突
2.尽量做到见名知意
参数
分为两大类
形参:在函数定义阶段括号内写的变量名 称之为形参
实参:在函数调用阶段括号内传入的具体的值 称之为实参
形参与实参的关系
形参就是变量名
实参就是变量名指向的值
只有在调用函数的时候两者才有关系,一旦函数运行结束 关系自动解除
函数的注释:推荐你写上
1.用来描述你这个函数的具体功能
2.诠释你写的函数的形参都表示什么意思
3.还可以诠释你这个函数的返回值有什么特点
函数体代码:你这个函数到底能干嘛
函数的返回值:关键字return
1.返回给调用者函数体代码执行之后得到的结果
2.只要函数体代码执行到return,整个函数立即结束
def 函数名(参数1,参数2,参数3...):
"""
函数的注释
参数的解释
返回值的解释
"""
函数体代码1
函数体代码2
函数体代码3
return 函数的返回值
函数的返回值
1.不写return
python所有的函数都有返回值,不写return的情况下默认返回None
2.写return返回一个值
1.return
你想主动结束整个函数的运行
2.return None(与上面的只写return是等价的)
你想主动结束整个函数的运行
3.return 值
这个值可以是python任意数据类型
3.写return返回多个值
1.return 值1,值2,值3...
return会自动将多个值组织成一个元组返回给调用者
def func():
return 'a','b','c'
x,y,z = func()
x,_,_ = func()
x,*_ = func() # _是一个元组类型
2.return [值1,值2,值3...]
你也可以自己的手动指定返回数据类型
函数的参数详解
1.位置参数
在定义函数的时候按照位置从左到右依次书写的变量名叫做位置形参
位置形参在调用的时候必须为其传值
在调用函数的时候,按照位置书写的实参 会一一对应的传给位置形参
2.默认值参数
在函数定义阶段就已经给形参赋值了
注意如果默认值参数是可变类型的情况下,需要细心
3.可变长参数(动态参数)
*
**
* 站在形参的角度 可以接收多余的位置参数 将他们组织成一个元组 交给*后面的变量名
* 站在实参的角度 可以将列表 元组 集合 字符串这些支持for循环的容器类型打散成位置参数
** 站在形参的角度 可以接收多余的关键字参数(什么=什么) 将他们组织成一个字典 交给**后面的变量名
** 站在实参的角度 可以将字典打散成key=value的形式 按照关键字参数传给函数
函数可以接收调用者传入的任意个数的参数
def func(*args,**kwargs):
print(args)
print(kwargs)
定义函数的三种方式
1.空函数:可以快速帮助你构建项目框架 使项目架构清晰明了
应用频率非常高
购物车功能
def register():
pass
def login():
pass
def shopping():
pass
def pay():
pass
def func():
pass
2.无参函数
def func():
print('from func')
3.有参函数
def func(x,y,*args,**kwargs):
pass
'''
#
# 今日内容
# 函数对象
# 函数的嵌套调用与定义
# 名称空间
# 作用域
# # 命名关键字参数: 在函数定义阶段 写在*与**可变长参数之间的形参
# # 在给命名关键字参数传值的时候 只能用 关键字 为其传值
# # 在定义阶段 给你感觉好像是z是默认值参数 放在了m这个位置参数的前面了 应该报错
# # 其实z和m都是命名关键字参数 不是默认值参数和位置参数
# # 案例 :
# def func(x,y=1,*args,z=3,m,**kwargs):
# print(x,y)
# print(args)
# print(z,m)
# print(kwargs)
# func(1,2,1,2,3,4,5,6,7,78,8,9,0,z=69,m=999,o=666999,l = 999666)
# 函数是第一类对象: 函数名指向的值可以被当作参数传递
# 即函数名可以被当作参数传递,函数名不包括括号, 函数名加括号直接就调用执行函数,传递的是return不是函数名了
# # 1.函数名可以被传递
# name = 'xiao' # 定义一个变量,指向的值为xiao字符串类型
# x = name # 这个name是变量名,指向的值为 xiao这个字符串
# print(x) # 执行结果为 xiao
# print(id(x)) # 查看其内存地址 2597199860152
# def func(): # 定义一个函数 func
# print('from func') # 函数体为 打印字符串 from func 用单引号引起来
# print(func) # 打印函数名结果为 存放函数代码的内存地址 <function func at 0x0000020CC7DA88C8>
# print(id(func)) # 同样可以查看函数名的内存地址 2253915850952
# f = func
# func() # 直接调用函数 会 打印字符串 from func 用单引号引起来
# print(f) # 上面定义了 f = func 打印f就是打印函数名结果为函数名指向存放函数代码的内存地址
# f() # 其实指向的也是函数func指向函数体代码的内存地址,加括号就可以直接执行定义的函数 func
# # 2.函数名可以被当做参数传递给其他函数
# def func():
# print('from func')
#
# def index(args): # 定义一个函数,带有位置形参 args
# print(args) # 打印这个位置形参
# print('from index') # 打印字符串 'from index'
# index(1) # 执行index函数并传位置实参=1,则 打印1 打印字符串 'from index'
# index(func) # 执行index函数并传位置实参为第一个函数名func,函数名没有加括号,加括号就执行了
# # 结果为 打印这个函数名,结果为该函数名指向存放函数代码的内存地址,打印字符串 'from index'
# # 3.函数名可以被当做函数的返回值
# def index(): # 定义一个函数 index
# print('index') # 打印字符串 'index'
# def func(): # 定义一个函数 func
# print('func') # 打印字符串 'func'
# return index # 返回 函数名 index,因为没有加引号,加引号就是返回字符串。return后直接跟返回内容,不用加括号
# res = func() # 用变量接住 func这个函数的返回值,或者说将func这个函数的返回值赋值给 res
# print(res) # 打印res,就是打印函数名index,因为返回值是函数名,打印函数名结果为函数名指向存放函数代码的内存地址
# res() # 可以直接用res调用 res所代表的函数名的函数,等同于 index()
# # 4.函数名可以被当做容器类型的参数
# def func():
# print('func')
# print(func()) # 这里会返回两行内容 第一行为执行函数打印的字符串'func' 第二行为打印执行函数的返回值,不写return返回 None
# # func None 打印执行函数,就是打印执行函数后的返回值,执行函数如果有打印的内容,也一样会打印出来
# l = [1,2,func,func()] # 将函数名,执行函数当作列表的元素
# print(l) # [1,2,<function func at 0x000001F7D79899D8>,None]
# # 打印列表的结果可以看到 函数名为函数名指向存放函数代码的内存地址,打印函数是直接打印该函数的返回值,不写return返回 None
# 循环打印项目功能提示信息 供用户选择 用户选择谁就执行谁
# 购物车答题框架
'''
先定义对应哥哥功能的函数,后面调用执行即可
定义一个字符串,提供给客户选择操作的列表
定义一个字典,key为操作列表的序号,value为各个功能的函数名
写一个大循环,因为需要循环让客户选择操作while Ture
循环下第一步打印给客户选择操作的列表字符串
用变量choice承接客户input输入的操作选项.左右去空格
if控制语句筛选条件 输入选项是否在字典中(在字典的key中)
则执行 字典.get(选项key)() '字典.get(选项key)'这个直接就是字典中的value函数名,函数名加括号直接触发调用
else 打印如果输入的不在字典中(字典的key中),打印该功能还没有
解释:用字典定义客户选择的列表,key对应客户输入的选择,value对应相应的函数名,
客户输入后直接拿客户输入的key取值value得到函数名,直接加括号调用,省去了以下冗长的代码
方便以后扩展功能,直接 1.定义新的功能函数 2.将序号做key,函数名做value,加入字典即可
如果在 choice 如果 == 1 :执行什么功能函数(上面定义好的,直接调用)
如果在 choice 如果 == 1 :执行什么功能函数(上面定义好的,直接调用)
...
'''
# def register():
# username = input('username>>>:').strip()
# pwd = input('password>>>:').strip()
# print(username,pwd)
# print('register ...')
# def login():
# print('login ...')
# def transfer():
# print('transfer ...')
# def shopping():
# print('shopping...')
# def pay():
# print('pay ...')
#
# msg = """
# 1 注册
# 2 登陆
# 3 转账
# 4 购物
# 5 支付
# """
# func_dict = {
# '1':register,
# '2':login,
# '3':transfer,
# '4':shopping,
# '5':pay,
# }
# while True:
# print(msg)
# choice = input('请现在你想要执行的功能>>>:').strip()
# if choice in func_dict:
# func_dict.get(choice)() # 函数名()
#
# # if choice == '1':
# # register()
# # elif choice == '2':
# # login()
# # elif choice == '3':
# # transfer()
# # elif choice == '4':
# # shopping()
# # elif choice == '5':
# # pay()
# else:
# print('你输入的功能暂时没有')
# 函数的嵌套调用
# 在函数内部调用其他函数,可以将复杂的逻辑简单化
# def index():
# func()
# print('index')
# def func():
# # index()
# print('func')
# index() # 结果为 func index
# # 第一个func的结果是调用index函数中的第一个操作就是调用func,第二个index的结果是调用index函数中的第二个操作就是打印index字符串
# # 计算比较大小写的函数,打印较大的
# # 以下第一段函数只能比较两个数的大小写,然后打印较大的
# # 需求变为四个数比较大小写,打印最大的哪个数
# # 思路就是定义一个函数比较四个数的大小写
# # 第一步先调用比较两个数大小的函数,比较前两个数,输出较大值
# # 将结果输入到第二步再次调用,跟第三个数比较
# # 将结果输入到第三步再次调用,跟第四个数比较 得出结果 即函数内调用函数,函数的嵌套使用
# def my_max(x,y):
# if x > y:
# return x
# return y
#
# def my_max4(a,b,c,d):
# res1 = my_max(a,b)
# res2 = my_max(res1,c)
# res3 = my_max(res2,d)
# return res3
# print(my_max4(1,2,10,4))
# # 函数内定义函数 上面是函数内调用函数
# 函数内定义函数应用场景
"""
写一个函数
该函数用户可以通过传参的不同,控制函数执行不同的功能
"""
# def outer(): # 定义一个函数,定义阶段只检查语法,不执行函数
# x = 1 # 函数内定义变量x = 1 函数内第一步
# print('outer') # 打印字符串'outer' 函数内第二步
# def inner(): # 函数内定义一个函数inner 函数内第三步 定义阶段只检查语法,不执行函数
# print('inner') # 打印字符串'inner' 函数内定义的函数的第一步
# print(inner) # 打印函数名 函数内第四步
# return inner # 结束外层函数,返回内层函数的函数名 函数内第五步
# res = outer() # 用变量res 接执行函数outer()的返回值,即inner的函数名,返回inner函数对应的内存地址
# # <function outer.<locals>.inner at 0x0000017899C58950>
# print(res) # 直接打印res,也是打印inner函数名,inner函数对应的内存地址
# # <function outer.<locals>.inner at 0x0000017899C58950>
# res() # res()相当于inner()函数名加括号直接调用,即会打印 字符串'inner'
# 名称空间是什么?
# 就是放名字的地方
# 详细解释:存放的是变量名与变量值的内存地址得绑定关系的地方
# 要想访问一个变量的值 必须先去名称空间中拿到对应的名字 才能够访问变量的值
# name = 'xiao' # 在内存中存入 xiao字符串,用变量名name接 这个name变量存在哪里,还有这个指向关系存在哪里
# print(name) # 打印name变量可以直接得到变量对应的值
"""
名称空间的分类
1.内置名称空间:python解释器提前给你定义好的名字(已经存放到内置名称空间中了)
len
max
min
2.全局名称空间:文件级别的代码,定义的位置在全局,不在某个定义的函数之内
x = 1
if 1 ==1 :
y = 2
print(y)
while True:
z = 3
x,y,z都会放到全局名称空间
if for while 无论嵌套多少层 它们内部所创建的名字都是全局名称空间的
3.局部名称空间:函数体内创建的名字都属于局部名称空间,在哪个函数体内创建的就在哪个函数体
username
生命周期:
内置名称空间:只要python解释器已启动立马创建 关闭python解释器的时候内置名称空间自动销毁
全局名称空间:只要你右键运行py文件会自动创建 py文件程序运行结束自动销毁
局部名称空间:函数被调用的时候自动创建 函数指向结束立即销毁(动态创建动态销毁)
名字的查找顺序!!!
"""
#
# len = '我是全局名称空间的len'
# def func():
# len = '我是局部名称空间的len'
# print(len) # 结果是打印 '我是全局名称空间的len'
# # len = '我是全局名称空间的len'
# def func():
# len = '我是局部名称空间的len'
# print(len) # 结果是打印 <built-in function len> 内置函数的len
# def func():
# len = '我是局部名称空间的len'
# print(len) # 我现在站在的是全局的位置 同上 一样,打印内置函数 <built-in function len>
# def index():
# x = 'xxx'
#
# def index2():
# # print(x)
# # 会报错,定义函数检查语法时,这里打印x变量,语法检查会先看是否定义这个变量,检查到没有定义,就会报语法错误,未定义先调用
# y = 666
# # print(x)
# # 会报错,在这里打印x,位置是站在全局,首先会看全局变量是否有x,没有会在内置名称空间内找,没有招到即报错,未定义先调用
# index()
# # print(x)
# # 会报错,在这里打印x,首先会看全局变量是否有x,虽然运行了index函数,在函数内定义了x = 'xxx',但是这个是在函数内的局部名称空间定义的
# index2()
# # print(y)
# # 会报错,在这里打印x,首先会看全局变量是否有x,虽然运行了index函数,在函数内定义了y = 666,但是这个是在函数内的局部名称空间定义的
"""
名字的查找顺序 (******)
1.需要先确定你当前在哪(大前提)
1.站在全局: 全局 >>> 内置
2.站在局部: 局部 >>> 全局 >>> 内置
"""
# x = 111 # 全局命名空间 定义x = 111 全局-1
# def f1(): # 定义函数 f1 产生f1的局部命名空间 全局-2
# x = 222 # 函数 f1 中在f1的局部命名空间 定义了 x = 222 1-1
# def f2(): # 定义函数 f2 产生f2的局部命名空间 1-2
# x = 333 # 函数 f2 中在f2的局部命名空间 定义了 x = 333 2-1
# def f3(): # 定义函数 f3 产生f3的局部命名空间 2-2
# x = 444 # 函数 f3 中在f3的局部命名空间 定义了 x = 444 3-1
# def f4(): # 定义函数 f4 产生f4的局部命名空间 3-2
# # x = 555 # 函数 f4 中在f4的局部命名空间 定义了 x = 555 4-1
# print(x) # 函数 f4 中在f4的局部命名空间 打印 x 4-2
# x = 777 # 纯粹为了教学演示 # 函数 f3 中在f3的局部命名空间中定义 x = 777 3-3
# f4() # 函数 f3 中在f3的局部命名空间 中调用f4 3-4
# # x = 777 # 纯粹为了教学演示 # 函数 f3 中在f3的局部命名空间中定义 x = 777 3-5
# f3() # 调用执行函数 f3 2-3
# f2() # 调用执行函数 f2 1-3
# f1() # 调用执行函数 f1 全局-3
'''
总结: 寻找变量值的顺序: f4的名称空间如果没有,就会去f3的局部名称空间去找;
f3的名称空间如果没有,就会去f2的局部名称空间去找;
f2的名称空间如果没有,就会去f1的局部名称空间去找;
f1的名称空间如果没有,就会去全局名称空间去找;
全局名称空间如果没有,就会去内置名称空间去找;找不到则报错
注释3-5,解注释3-3,结果是777,执行顺序:
全局定义x = 111(全局名称空间定义 全局 x = 111)
执行定义函数f1,定义赋值x = 222(在f1的局部命名空间 定义了 x = 222),定义函数f2,检查语法不执行,调用执行定义函数f2、
执行定义函数f2,定义赋值x = 333(在f1的局部命名空间 定义了 x = 333),定义函数f3,检查语法不执行,调用执行定义函数f3、
执行定义函数f3,定义赋值x = 444(在f1的局部命名空间 定义了 x = 444),定义函数f4,检查语法不执行,定义赋值x = 777,调用执行定义函数f4、
执行定义函数f4,打印x,到4-2会打印x,寻找x值的顺序:
f4的局部命名空间 x = 555被注释了,在f4的局部命名空间没有找到,就会去f3的局部名称空间去找,
f3这一层定义函数中,被f2调用后执行定义函数f3的顺序为从上到下:
3-1 赋值x = 444、3-2定义函数f4,检查语法不执行、3-3 重新赋值x = 777、调用函数f4,所以 x = 777,f4执行时在上一级f3的局部空间找到定义,即打印x = 777
解注释3-5,注释3-3和3-1,f1()的执行结果:
报错;NameError: free variable 'x' referenced before assignment in enclosing scope 4-2报错
NameError:在封闭范围中赋值之前引用的自由变量'x'
执行顺序为;
全局定义x = 111(全局名称空间定义 全局 x = 111)
执行定义函数f1,定义赋值x = 222(在f1的局部命名空间 定义了 x = 222),定义函数f2,检查语法不执行,调用执行定义函数f2、
执行定义函数f2,定义赋值x = 333(在f1的局部命名空间 定义了 x = 333),定义函数f3,检查语法不执行,调用执行定义函数f3、
执行定义函数f3,(在f1的局部命名空间 定义了 x = 444),定义函数f4,检查语法不执行,调用执行定义函数f4,还没有执行定义赋值x = 777,
执行定义函数f4,打印x,到4-2会打印x,寻找x值的顺序:
f4的局部命名空间 x = 555被注释了,在f4的局部命名空间没有找到,就会去f3的局部名称空间去找,
f3这一层定义函数中,被f2调用后执行定义函数f3的顺序为从上到下:
3-2定义函数f4,检查语法不执行、3-3 、调用函数f4、重新赋值x = 777,
因为在f3函数中执行顺序是从上到下,定义函数f4函数之后,直接执行f4,执行f4时候,在f4的局部命名空间没有找到,就会去f3的局部名称空间去找,
f3中的重新赋值x = 777,还没有执行,x还没有被定义就已经在引用执行了,即执行报错,局部空间中先引用后定义了
'''
"""
函数在定义阶段查找名字的顺序就已经固定了 不会因为函数的调用位置变化而改变(******)
"""
# # 案例:
# def func(): # 定义一个函数 func(),检查语法不执行
# x = 1 # 函数 func() 局部名称空间中 定义x = 1
# def index(): # 函数 func() 局部名称空间中 定义函数 index(),检查语法不执行
# print(x) # 获取全局找x # 打印x
# return index # 跳出函数func,并返回index函数名
# res = func() # 用res接 func函数的返回值,返回值为index函数名
# x = 999 # 全局定义 x = 999
# res() # res 为func函数的返回值,即index的函数名,加括号执行 index 打印x
# # 执行顺序从上到下
# # 1 定义函数func()检查语法不执行
# # 2 用res接 func函数的返回值,返回值为index函数名
# # 3 全局定义 x = 999
# # 4 res 为func函数的返回值,即index的函数名,加括号执行 index 打印x
# # 打印x时寻找值的顺序:
# # 先在当前index的局部名称空间中找,没有
# # 再去上一级函数func的局部名称空间找,func函数的执行顺序从上到下:
# # 定义x = 1,定义函数index,检查语法不执行,退出函数,返回index函数名
# # 再func函数的局部名称空间找到 x = 1
# # 执行打印
# # 为什么不是999,函数在定义阶段查找名字的顺序就已经固定了 不会因为函数的调用位置变化而改变,局部名称空间找到就不会去全局找
"""
函数在定义阶段查找名字的顺序就已经固定了 不会因为函数的调用位置变化而改变(******)
"""
# x=111 # 全局定义变量 x = 111
# def outer(): # 定义函数outer,检查语法不执行
# def inner(): # 定义函数inner,检查函数不执行
# print('from inner',x) # 打印字符串'from inner' 和 变量x
# return inner # 返回函数名 inner
# f=outer() # 用f接收outer函数的返回值 inner函数名
# x = 222 # 全局定义 x = 222
# f() # 执行函数f(),即执行inner()
# # 执行结果为 from inner 222
# # 执行顺序 从上到下
# # 1. 先全局定义变量 x = 111
# # 2. 定义函数outer,检查语法不执行
# # (1 # 定义函数inner,检查函数不执行(1. # 打印字符串'from inner' 和 变量x)、2 # 返回函数名 inner )
# # 3. 用f接收outer函数的返回值 inner函数名
# # 4. 全局定义 x = 222
# # 5. 执行函数f(),即执行inner()
# # 6. 执行打印字符串,打印变量x
# # 7. 在inner函数局部名称空间寻找变量x,未找到
# # 8. 在outer函数局部名称空间寻找变量x,未找到
# # 9. 在全局名称空间寻找变量x,因为第五步执行函数时,全局变量x,已经被重新赋值 x = 222,所以找到x = 222,即打印
# # 执行顺序 # 打印x找值顺序
# x=111 # 第1步 # 第13步 全局名称空间找到 x = 111 打印
# def outer(): # 第2步 # 第12步 未找到 outer局部名称空间
# def inner(): # 第4步 # 第11步 未找到 inner局部名称空间
# print('from inner',x) # 第10步
# return inner # 第5步
# f=outer() # 第3步
# def func(): # 第6步
# x=333 # 第8步
# f() # 第9步
# func() # 第7步
# # 结果为 from inner 111
# # # 执行顺序 # 打印x找值顺序
# x=111 # 第1步
# def outer(): # 第2步
# def inner(): # 第4步 # 第9步 inner局部名称空间,执行发现先调用后定义,即报错
# print('from inner',x) # 第7步
# x = 66666666 # 第8步
# return inner # 第5步
# f=outer() # 第3步
# f() # 第6步
# # 结果报错 UnboundLocalError: local variable 'x' referenced before assignment
# 作用域
# 全局作用域
# 全局有效: 内置名称空间 全局名称空间
# 局部作用域
# 局部有效 局部作用域
# global nonlocal
"""
1.在局部修改全局的变量
"""
# # global 在局部修改全局的不可变数据类型
# # 执行顺序
# x = 1 # 不可变类型 # 1
# # x = [] # 因为列表是可变类型 # 1
# username = 'jason' # # 2
# def func(): # 定义函数检查语法不执行 # 3
# # x.append('嘿嘿嘿') # 针对x为列表,修改列表 # 5
# global x,username # 声明修改全局变量 而不是创建局部名称空间 # 5
# x = 999 # 定义 修改 全局部名称空间内x = 999 # 6
# username = 'xiao' # 定义 修改 全局部名称空间内 username = 'egon' # 6
# func() # 执行函数 # 4
# print(x) # 打印x 结果为新的值 999 # 8
# print(username) # 打印变量名username 结果为新的值 xiao # 9
# # 定义函数中,在局部名称空间内修改了全局变量,调用函数即修改,再打印即是修改后的值
# # nonlocal : 局部修改局部 执行顺序
# def func(): # 定义函数func检查语法不执行 # 1
# x = 1 # 在func函数内局部名称空间定义 x = 1 # 3
# def index(): # func函数内局部名称空间定义函数index # 4
# nonlocal x # 在index局部名称空间修改func局部名称空间的变量x 声明 # 6
# x = 2 # 在index局部名称空间修改func局部名称空间的变量x x = 2 修改 # 7
# index() # 在func函数内局部名称空间调用index函数 # 5
# print(x) # 在func函数内局部名称空间打印变量x # 8
# func() # 调用funx函数 # 2
# # 修改后,第八步打印的应该是修改后的变量值
"""
global:局部修改全局 如果想修改多个 逗号隔开
nonlocal:局部修局部 如果想修改多个 逗号隔开
"""