# 函数的参数分为两种:
# 形参 # 在定义阶段,括号内指定的参数 # 相当于变量名
# 实参 # 在调用阶段括号内传入的值 # 相当于值
# def foo(x,y): # 形参 # 形参在定义阶段不占用内存空间,变量名没有赋值,不占用内存空间
# print(x,y)
# foo(1,2) # 实参
# 在调用阶段,实参的值会绑定给形参,在调用结束后解除绑定
# 在python中,参数的分类
# 位置参数:按照位置从左到右,依次定义的参数
# 位置形参:必须被传值,多一个少一个都不行
# 位置实参:与形参一一对应传值
# def foo(x,y):
# print(x,y)
# foo(1,2)
# 关键字参数:在函数调用阶段,按照key=value的形式调用的实参
# 特点:指名道姓的给形参传值,不再依赖位置
# def foo(x,y):
# print(x,y)
# foo(y=1,x=2)
# 注意:关键字参数可以和位置实参一块使用,但是关键字参数必须放在位置实参的后面
# def foo(x,y,z):
# print(x,y,z)
# foo(3,y=1,z=2)
# # 默认参数:在函数定义阶段,就已经为形参赋值了,调用阶段可以不用传值
# def foo(x,y=1):
# print(x,y)
# foo(1,2) # 1 2
# foo(100) # 100 1
# 位置参数通常用于经常变化的参数,而默认参数通常用于大多数情况下不变的参数
# def students(name,age,gender='male'): # 默认参数必须放到位置形参的后面
# print(name,age,gender)
# students('OBOS',18)
# students('Love',18,'female')
'''
OBOS 18 male
Love 18 female
'''
# 默认参数的值,只在定义时被赋值一次,之后不受影响
# res=1
# def foo(x,y=res):
# print(x,y)
#
# res=10
# foo(100) # 100 1
# 默认参数的值通常应该是不可变类型
# 可变长参数:在调用函数时,实参值的个数不固定
# 实参的形式有,位置实参和关键字实参
# 形参的解决方案:* 和 **
# def foo(x,y,*z): # def foo(x,y,*args)
# print(x,y)
# print(z)
# foo(1,2,3,4,5,6,7)
'''
1 2
(3, 4, 5, 6, 7) # 溢出的部分被*接受,以元组的形式,赋值给z # *args
'''
# foo(1,2,*[3,4,5,6,7]) # 遇到*,就要想到是位置参数,直接打回原形foo(1,2,3,4,5,6,7) # *args
'''
1 2
(3, 4, 5, 6, 7)
'''
# foo(1,*[2,3,4,5,6,7]) # foo(1,2,3,4,5,6,7) # *args
'''
1 2
(3, 4, 5, 6, 7)
'''
# def foo(x,y):
# print(x,y)
#
# foo(*(1,2)) # 1 2 # *args
# **kwargs
# def foo(x,y,**kwargs):
# print(x,y)
# print(kwargs)
# foo(y=1,x=2,a=3,b=4,c=5)
'''
2 1
{'a': 3, 'b': 4, 'c': 5}
'''
# foo(y=1,x=2,**{'a': 3, 'b': 4, 'c': 5})
'''
2 1
{'a': 3, 'b': 4, 'c': 5}
'''
# def foo(name,age):
# print(name,age)
#
# foo(**{'name':'OBOS','age':18}) # OBOS 18
# def wrapper(*args,**kwargs): # 关键字参数必须放到位置参数的后面
# print(args,kwargs)
#
# wrapper(1,2,3,a=1,y=2,c=3) # {'a': 1, 'y': 2, 'c': 3}
# def bar(x,y,z):
# print(x,y,z)
# def wrapper(*args,**kwargs): # args=(1, 2, 3) kwargs= {'a': 1, 'y': 2, 'c': 3}
# bar(*args,**kwargs) # bar(*(1, 2, 3),**{'a': 1, 'y': 2, 'c': 3}) # bar(1,2,3,a=1,y=2,c=3)
#
# wrapper(1,2,3,a=1,y=2,c=3) 报错
# def bar(x,y,z):
# print(x,y,z)
# def wrapper(*args,**kwargs): # args=(1, 2, 3)
# bar(*args,**kwargs) # bar(*(1, 2, 3))
#
# wrapper(1,2,3) # 1 2 3
# 命名关键字参数,指的是定义在*后的参数,该参数必须被传值(除非它有默认值),并且必须是key=value的形式
# def foo(x,y,*,m,n):
# print(x,y)
# print(m,n)
# foo(1,2,3,4) # 报错
# foo(1,2,m=3,n=4)
'''
1 2
3 4
'''
# def foo(x,y,*args,m,n):
# print(x,y)
# print(m,n)
#
# foo(1,2,m=3,n=4)
'''
1 2
3 4
'''
# def foo(x,y,*args,m,n):
# print(x,y)
# print(args)
# print(m,n)
#
# foo(1,2,3,m=3,n=4)
'''
1 2
(3,)
3 4
'''
# def foo(x,y,*args,m=100,n):
# print(x,y)
# print(args)
# print(m,n)
#
# foo(1,2,3,n=4)
'''
1 2
(3,)
100 4
'''
# 函数是第一类对象:指的是函数可以当作数据传递
# 可以被引用
# def foo(x,y):
# print(x,y)
# f=foo
# f(1,2) # 1 2
# 可以当作函数的参数传入
# def foo():
# print('from foo')
# def bar(func):
# print(func) # 得到内存地址 # <function foo at 0x0000020748B64B88>
# func()# 加括号,调用 # from foo
# bar(foo)
# 可以当作函数的返回值
# def foo():
# print('from foo')
# def bar():
# return foo
# f=bar()
# f() # from foo
# 可以当作容器类型的元素
# def foo():
# print('from foo')
# def bar():
# return foo
# l=[foo,bar]
# print(l) # [<function foo at 0x0000022FCE0B4B88>, <function bar at 0x0000022FCE0B4C18>]
# l[0]() # from foo
# 函数嵌套
# 函数的嵌套调用
# def my_max(x,y):
# if x >= y:
# return x
# else:
# return y
# def my_max(a,b,c,d):
# res1=my_max(a,b)
# res2=my_max(res1,c)
# res3=my_max(res2,d)
# return res3
# 函数的嵌套定义:在一个函数的内部又定义了一个函数
# 定义的函数只能在内部使用