六、函数的基本使用

一、认识函数

1 什么是函数
    函数就是具备某一功能的工具


2 为什么要用函数
    1  程序的组织结构不清晰,可读性差
    2  代码冗余
    3  可扩展性差

3 如何用函数
    函数的使用必须遵循的原则:先定义,后调用
        修理工事先准备工具的过程即函数的定义
        修理工遇到应用场景拿来工具就用即函数的调用

    语法:
        def 函数名(参数1,参数2,...):
            """
            文档注释
            """
            code1
            code2
            code3
            ......
            return 返回值

        def:定义函数的关键字
        函数名: 就相当于一个变量名,指向函数的内存地址,
                注意:函数的内存地址()就可以出发函数体代码的执行

        参数: 参数是函数的调用者为函数体代码传值的媒介,在python中函数的参数无需声明类型
        """文档注释""" : 推荐写上
        代码块:就是函数体功能的具体实现
        return 返回值 :函数体代码块运行的成果


    函数的使用分为两个阶段:
        定义阶段: 只检测语法,不执行代码
        调用阶段:运行函数体代码
            def foo():
                xxx
                print(

# 先定义

def foo():
    print("from foo")

# 后调用

# 定义时无参,意味着调用时也无需传入参数

print(foo)
foo()

# 先定义

def bar(x,y):
    print(x)
    print(y)

# 后调用

# 定义时无参,意味着调用时也必须传入参数

bar('a',2)

# 定义无参函数:当函数体的代码逻辑不依赖任何传入的值就能执行,就不需要定义参数

def print_msg():
    print('='*50)
    print('welecome.....'.center(50,' '))
    print('='*50)
print_msg()
print_msg()
-----------------------------------------------------------------
==================================================
                  welecome.....                   
==================================================
==================================================
                  welecome.....                   
==================================================

#定义有参函数:当函数体的代码逻辑依赖于外部调用者传入的值才能执行,必须定义参数用来接收外部传入的值

def max2(x,y):
    # x=1
    # y=3
    if x > y:
        print(x)
    else:
        print(y)
max2(1,4)
---------------------------------
4

# 定义阶段

def foo():
    print('from foo')
    bar()
def bar():
    print('from bar')

# 调用阶段

foo()

# 定义阶段

def foo():
    print('from foo')
    bar()

# 调用阶段

foo()
def bar():
    print('from bar')

二、定义函数的三种形式

1 无参函数

def foo():
    print('from foo')
foo()

2 有参函数

def bar(x,y):
    print(x,y)
bar(1,2)

3 空函数

def func():
    pass

三、调用函数的三种形式

1 #语句形式

def foo():
    print('from foo')
foo()

2 表达式形式

def foo(x,y):
    res = x + y
    return res

res=foo(1,2) #表达式形式
res1=foo(1,2)*100
print(res1)

3 可以当作参数传给另外一个函数

def max2(x,y):
    if x > y:
        return x
    else:
        return y
res=max2(max2(1,2),3)
print(res)

四、函数的返回值

#一 函数的返回值需要注意:
#1 返回值没有类型限制
#2 返回值没有个数限制
#  返回1个值:调用函数拿到的结果就是一个值
#  返回多个值:调用函数拿到的结果就是一个元组
#  返回0个值,或者不写return:调用函数拿到的结果就是None

#二 return关键字:return是函数结束的标志,函数内可以有多个return,但只要执行一次,整个函数就结束

def f1():
    print('first')
    return 1
    print('second')
    return 2
    print('third')
    return 3
res=f1()
print(res)
----------------------------------------
first
1

def foo():
    count=1
    while True:
        print(count)
        if count == 3:
            return
        count+=1
foo()
------------------------------------------------------
1
2
3

def bar():
    pass
def foo():
    return [1,2],1,1.3,{'x':1},bar
res=foo()
print(res)
----------------------------------------------------------------
([1, 2], 1, 1.3, {'x': 1}, <function bar at 0x000002478D872EA0>)

def func():
    print('from foo')
    # return

res=func()
print(res)
----------------------------------------------------------------------------
from foo
None

五、函数参数的使用

#函数的参数分为两大类:
#1 形参: 指的是在定义函数阶段括号内指定变量名,即形参本质就是"变量名"

#2 实参: 指的是在调用函数阶段括号内传入的值,即实参本质就是"值"

# 形参与实参的关系:在调用函数时,会将实参(值)赋值(绑定)给形参(变量名),
# 这种绑定关系在函数调用时临时生效,在调用结束后就失效了

def foo(x,y): # x=1 y=2
    # x=1
    # y=2
    print(x,y)
foo(1,2)

# 形参与实参的具体分类
# 一 位置参数
# 1.1 位置形参: 在定义函数阶段按照从左到右的顺序依次定义的形参,称之为位置形参
# 注意:但凡按照位置定义的形参,必须被传值,多一个不行,少一个也不行(一一对应)

def foo(x,y):
    print(x,y)
foo(1,2)

# 1.2 位置实参: 在调用函数阶段按照从左到右的顺序依次传入的值,称之为位置实参
# 注意:但凡按照位置定义的实参,会与形参一一对应

二 关键字参数
#关键字实参: 在调用函数阶段,按照key=value的形式指名道姓地为形参传值
#注意:
#1. 可以完全打乱顺序,但仍然能指名道姓为指定的形参传值
#2. 可以混合使用位置实参与关键字实参,但是必须注意:
#    2.1 位置实参必须放到关键字实参前面
#    2.2 不能对一个形参重复赋值

def foo(name,age):
    print(name,age)
foo('egon',18)
foo(18,'egon')
foo(age=18,name='egon')
foo('egon',age=18)

# 三 默认参数
#默认参数:指的是在定义函数阶段,就已经为某个形参赋值了,改形参称之为有默认值的形参,简称默认形参
#注意:
#1. 在定义阶段就已经被赋值,意味着在调用阶段可以不用为其赋值
#2. 位置形参应该放到默认形参前面
#3. 默认参数的值在函数定义阶段就已经固定死了
#4. 默认参数的值通常应该是不可变类型

def foo(x,y=2):
    print(x,y)
foo(1)
foo(1,3)
foo(y=3,x=1)
----------------------------
1 2
1 3
1 3

-

m=10              ## 必须要放在上面才可以被赋值到
def foo(x,y=m):
    print(x,y)

m=20                 #定义时不能定义在函数后面,否则会报 m 没有定义
foo(1)
-------------------------
1 10
def register(name,hobby,l=[]):
    l.append(hobby)
    print('%s 的爱好为 %s' %(name,l))

register('yxx','不洗澡')
register('egon','read')
-----------------------------
yxx 的爱好为 ['不洗澡']
egon 的爱好为 ['不洗澡', 'read']

def register(name, hobby, l=None):
    if l is None:
        l=[]
    l.append(hobby)
    print('%s 的爱好为 %s' % (name, l))

register('yxx', '不洗澡',[])
register('egon', 'read',[])
--------------------------------------------------
yxx 的爱好为 ['不洗澡']
egon 的爱好为 ['read']

# 位置形参vs默认形参
# 对于大多情况下传的值都不相同的,应该定义成位置形参
# 对于大多情况下传的值都相同的,应该定义成默认形参

def register(name,age,sex='男'):
    print(name,age,sex)
register('李铁蛋',18,)
register('刘二丫',19,'女')

# 四 可变长度的参数
# 站在实参的角度,参数长度可变指的是在调用函数时,传入的实参值的个数不固定
#而实参的定义方式无法两种:位置实参,关键字实参,对应着形参也必须有两种解决方案*与**,类分别应对溢出的位置实参与关键字实参
 
#1. 在形参中带*:会将调用函数时溢出位置实参保存成元组的形式,然后赋值*后的变量名

def foo(x,y,*z): #z=(3,4,5,6)
    print(x,y,z)
foo(1,2,3,4,5,6)

# 2. 在实参中带*: 但凡在实参中带*星的,在传值前都先将其打散成位置实参,再进行赋值

def foo(x,y,*z): #z=(3,4,5,6)
    print(x,y,z)
foo(1,*[2,3,4,5,6]) # foo(1,2,3,4,5,6)
#
def foo(x,y,z):
    print(x,y,z)
foo(*(1,2,3)) #foo(1,2,3)
foo(*'abc')  #foo('a','b','c')

# 3. 在形参中带**:会将调用函数时溢出关键字实参保存成字典的形式,然后赋值**后的变量名

def foo(x,y,**z): #z={'z':3,'a':1,'b':2}
    print(x,y,z)
foo(1,y=2,a=1,b=2,c=3)
foo(1,2,**{"r":4,'g':9}) # 正确的
------------------------------------------
1 2 {'a': 1, 'b': 2, 'c': 3}
1 2 {'r': 4, 'g': 9}
# 错误方式:
# foo(1,2,{"r":4,'g':9})  # 错误的  #不能直接接收以字典的形式,可以是以关键字传入例如:(a=1,b=2),或是将字典的形式打散 例如: **{"a":1,'b':2}

# 4. 在实参中带**: 但凡在实参中带**星的,在传值前都先将其打散成关键字实参,再进行赋值

def foo(x,y,**z): #z={'a':100,'b':200}
    print(x,y,z)
foo(1,**{'a':100,'b':200,'y':111}) #foo(1,b=200,a=100,y=111)
---------------------------
1 111 {'a': 100, 'b': 200}

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

#5. 规范: 在形参中带*与**的,*后的变量名应该为args,**后跟的变量名应该时kwargs

def foo(*args,**kwargs): #args=(1,2,3,4,5) kwargs={'a':1,'b':2,'c':3}
    print(args)
    print(kwargs)
foo(1,2,3,4,5,a=1,b=2,c=3)
------------------------------------
(1, 2, 3, 4, 5)
{'a': 1, 'b': 2, 'c': 3}

注意:

!!!!!!!!!!!当我们想要将传给一个函数的参数格式原方不动地转嫁给其内部的一个函数,应该使用下面这种形式

def bar(x,y,z):
    print(x,y,z)

def wrapper(*args,**kwargs): #args=(1,2) kwargs={'z':3}
    bar(*args,**kwargs)
    #bar(*(1,2),**{'z':3})  #bar(1,2,z=3)
wrapper(1,2,z=3) # 虽然调用的是wrapper,但是要遵循的确是bar的参数标准
---------------------------------
1 2 3

五 命名关键字参数: 放到*与**之间的参数称之为命名关键字参数
# 注意: 命名关键字参数必须按照key=value的形式传值

def foo(x,y,*args,m,n,**kwargs): #args=(3,4,5,6,7,8)
    print(x,y) # 1,2
    print(args) #(3,4,5,6,7,8)
    print(m,n) #222,333
    print(kwargs)
foo(1,2,3,4,5,6,7,8,n=333,m=222,a=1,b=2)
--------------------------------
1 2
(3, 4, 5, 6, 7, 8)
222 333
{'a': 1, 'b': 2}

def foo(*,x=1,y):
    print(x)
    print(y)
foo(y=2222,x=1111)
foo(y=2222)
-----------------------------------
1111
2222
1
2222

def foo(x,y=1,*args,m,**kwargs):
    print(x)
    print(y)
    print(args)
    print(m)
    print(kwargs)
foo('from x',ars='tuple',m='from m',kw='from kw',ar='args')
-----------------------------------------
from x
1
()
from m
{'ars': 'tuple', 'kw': 'from kw', 'ar': 'args'}

作业:

默写:
    函数中参数的分类 及其作用  位置 关键字  形参 实参 可变长度参数
分类:形参,实参
作用:
位置:位置形参,位置实参
关键字:关键字实参: 在调用函数阶段,按照key=value的形式指名道姓地为形参传值

形参:指的是在定义函数阶段括号内指定变量名,即形参本质就是"变量名"
实参:指的是在调用函数阶段括号内传入的值,即实参本质就是"值"
可变长度参数:
站在实参的角度,参数长度可变指的是在调用函数时,传入的实参值的个数不固定,而实参的定义方式无法两种:位置实参,关键字实参,对应着形参也必须有两种解决方案*与**,类分别应对溢出的位置实参与关键字实参

练习题:
    1.使用函数新的知识点继续完善,优化购物车

    2.使用函数完成以下功能,数据格式如下
    [
        {“name”:”张无忌”,”number”,”sh01”,”math”:90,”english”:87,”chinese”:56},
        {“name”:”武则天”,”number”,”sh02”,”math”:40,”english”:97,”chinese”:67}....

    ]
    提供以下功能函数
        获取指定学生的成绩
        获取指定学号的成绩
        根据学生的学号修改姓名
        根据姓名修改指定学科的成绩
        删除指定学生及其成绩

    3.博客作业 http://www.cnblogs.com/linhaifeng/articles/7531972.html#_label5

拓展:
    ATM 参考博客






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章