day11 函数

一、函数基础

"""
1 什么是函数
    函数是盛放代码的容器:把实现某一功能的代码放到一个函数内就制造一个工具
2 为何要用函数
    没有用函数之前程序的问题:
        1、代码冗余、程序的可读性差

        2、可拓展性差
3 如何用函数
    函数-》实现某一功能的工具
    函数定义-》事先准备工具的过程
    函数调用-》遇到应用场景,拿来就用
    函数的使用原则:先定义、后调用
"""
一 定义函数
语法
def 函数名(参数1,参数2,参数3,...):
     """函数注释"""
     代码1
     代码2
     代码3
     return 返回值

 定义函数发生的事情:
 (1)申请内存空间,把函数体代码存起来
 (2)将函数的内存地址绑定函数名
    def register():
         inp_user = input("请输入您的账号:").strip()
         inp_pwd = input("请输入您的密码:").strip()
        inp_money = input("请充值:").strip()

        with open('db.txt', mode='at', encoding='utf-8') as f:
            f.write('%s:%s:%s\n' % (inp_user, inp_pwd, inp_money))

    x = 10
    print(x)
    print(register)

二 调用:
(1) 根据函数名函数的内存地址
(2) 函数的内存地址()触发函数体代码的运行
register()
register()
register()
三 函数定义阶段:只检测语法不执行代码
    def func():
        print('hello1')
        # print('hello2'
        x
        print('hello3')
    func()
    四 函数调用阶段:才会执行函数体代码
    def foo():
        print('from foo')
        bar()
    def bar():
        print('from bar')
    foo()

二、函数的定义与调用

函数定义三种形式
1、有参函数
    def foo(x,y):
        print(x,y)
    foo(1,2)
2、无参函数
    def foo():
        print('hello')
    foo()
3、空函数
    def foo():
        pass
# 储备知识:函数返回值
def max2(x,y):
    if x > y:
        return x
    else:
        return y
res = max2(10,20)
print(res * 12)

# 注意:函数体内可以有多个return,但是只要执行一次整个函数就会立即终止并且将其后之当做本次的结果返回
def foo():
    print('hello1')
    return 111
    print('hello2')
    return 2222
    print('hello3')
    return 3333

res = foo()
print(res)
# return有三种形式
1、return 值:返回一个值
2、return 值1,值2,值3:返回一个元组
3、没有return、return、return None:默认返回None
def foo():
    # return 1,"aa",[1,2,3]
    pass

res = foo()
print(res)
# 函数调用的三种形式
def foo(x,y):
    return x + y

# 语句形式
foo(1,2)

# 表达式
res = foo(1,2)
res = foo(1,2) * 10
print(res)

# 函数的调用可以当做一个参数传给另外一个函数
res = foo(foo(1,2),3)
print(res)

三、函数参数

函数的参数分为两大类
    1、形参: 在函数定义阶段括号内指定的参数(变量名),称之为形式参数,简称形参
    2、实参: 在函数调用阶段括号内指定的参数(变量值),称之为实际参数,简称实参

一、位置形参:在函数定义阶段,按照从左到右的顺序依次定义的“变量名”
    特点:必须被赋值,多一个不行少一个也不行
    def foo(x,y):
    	print(x,y)
	foo(1,2)

二、默认形参:在函数定义阶段,就已经为某个形参赋值了,该形参称之为默认形参
     特点:调用阶段可以不用为其赋值
    def foo(x,y=100):
        print(x,y)
    foo(111)  # 不用传第二个值,因为默认有值
    
三、位置实参:在函数调用阶段,按照从左到右的顺序依次传入的“变量值”
      特点:按照顺序传值
    def foo(x,y):
         print(x,y)

     foo(1,2)
     foo(2,1)

四 关键字实参:在函数调用阶段,按照key=value的形式赋值
       特点:可以打乱顺序,但是仍然能够为指定的形参赋值
     def foo(x,y):
         print(x,y)

     foo(y=2,x=1)
 注意:
     可以混用位置实参与关键字实参,但是
     1、关键字实参必须在后
     2、不能给同一个形参重复赋值
    def foo(x,y):
    	print(x,y)

    foo(1,y=2)
    foo(y=2,1)
    foo(1,2,y=3)
五:*args与**kwargs用在形参中:汇总行为
1.*用在形参中: *会将溢出的位置实参存成元组然后赋值给紧跟其后的形参名
例子1:
    def foo(x,*y):
        print(x)
        print(y)

    foo(1,2,3,4,5,6,7)
    foo(1)
2.**用在形参中:**会将溢出的关键字实参存成字典然后赋值给紧跟其后的形参名

def foo(x,**y):  # y = {'y': 2, 'z': 3, 'a': 111, 'b': 222}
    print(x)
    print(y)
foo(1,y=2,z=3,a=111,b=222)
六:*与**用在实参中:打撒
1.*用在实参中: *会将紧跟其后值打撒成位置实参
    def foo(x,y,z):
        print(x,y,z)

    foo(*[111,222,333])  # foo(111,222,333)
    foo(*"hello")  # foo('h','e','l','l','o')
2.**用在实参中: **后只能跟字典,**会将紧跟其后字典打撒成关键实参
    def foo(x,y,z):	
        print(x,y,z)

    foo(**{'x':111,'y':222,'z':333})  # foo(x=111,z=333,y=222)