函数

函数的语法结构

"""
def 函数名(参数1,参数2)
    '''函数注释''
    函数代码体
    return 返回值
"""

  1、def(必须的)

    是定义函数的关键字

  2、函数名(必须的)

    是函数的名字,相当于变量名;函数的命名规范与风格遵循变量名

  3、()括号

    括号定义参数

  4、参数1,参数2(可选的)

    参数可以没有也可以有多个;表示在使用函数之前需要满足的一些条件

  5、:冒号

    括号后要加冒号,然后在下一行开始进行编写函数体的代码

  6、函数注释(可选的)

    类似于产品说明书;主要用于介绍函数功能、参数使用以及其他情况

  7、函数代码体(必须的)

    函数核心的代码逻辑

  8、return返回值(可选)

    使用函数之后返回给使用者的结果,可以有也可以没有

函数的定义与调用

  一、需注意的点

    1、函数必须先定义后调用(顺序不能乱)

    2、函数在定义阶段只检测语法不执行代码

    3、函数在调用阶段才会执行函数体代码

      如何调用函数:函数名加括号,如果函数在定义阶段有参数,则在调用阶段也需要加上参数

  二、函数在定义与调用阶段底层原理

    1、在内存空间中申请一块空间储存函数代码体

    2、将函数代码体所在的内存空间地址绑定给函数名

    3、函数名加括号就可以调用函数代码体

函数的分类

  1、内置函数

      python解释器自带的函数,已经提前定义好的,直接就可以

  2、自定义函数(程序员自己写的函数)

      2.1、无参数函数

      2.2、有参数函数

      2.3、空函数

# 无参函数:在函数定义阶段括号内没有加参数
def my_func():
    print('无参函数')

# 有参函数:在函数定义阶段括号内加了参数
def my_func(a, b):
    print('有参函数')

# 空函数,空函数本身没有含义,主要作用是可以提前规定好编写代码的思路
def my_func():
    pass

  空函数的实际应用案例

def register():
    pass


def login():
    pass


func_dic = {'1': register, '2': login}
while True:
    print("""
    1.注册
    2.登录
    """)
    choice = input('please>>>:').strip()
    if choice in func_dic:
        func_name = func_dic.get(choice)
        func_name()
    else:
        print('功能编号不存在')

函数的返回值

# 如何获取函数的返回值
# res = len([1, 2, 3, 4, 5])

def my_func():
    print('123')
    print('木头人')
    print('123')
    # return 123, 456, 789
    return 123, 456, 789
# res = my_func()  # 将函数my_func执行之后的反馈结果赋值给变量res
# 1.函数体代码没有return关键字的时候 默认返回None
# print(res)  # None
# 2.函数体代码如果只有一个return那么也返回None
# print(res)  # None
# 3.函数体代码遇到return会立刻结束函数的运行
# 4.函数体代码有return 返回值就是return后面跟的数据(单个数据)
# print(res)  # 123
# 5.函数体代码有return 并且后面跟了多个数据 那么会自动组织成元组的形式返回
# print(res)  # (123, 456, 789)
"""
函数的返回值如果是容器类型 那么直接支持解压赋值
"""

函数参数

  一、函数参数的两大分类

    1、形式参数:在函数定义阶段括号内所填的参数。简称“形参” 

 def func(a, b):
     pass
 # a和b就是函数func的形参

    2、实际参数:在函数调用阶段括号内传入的参数。简称“实参”

def func(a, b):
    print(a, b)

def func1():
    return 111
def func2():
    return 222
# 1.直接传入值
# func(1, 2)
# 2.借助于变量名间接传入
# m = 111
# n = 222
# func(m, n)
# 3.其他方法或者函数的返回值
# func(int('123'), int('111'))
func(func1(), func2())

    3、形参和实参的关系

      1、我们可以将形参看成是变量名,实参看成是变量值

      2、两者在函数调用阶段临时绑定,函数运行结束断开

      3、形参是表现形式只有一种就是变量名;实参的表现形式有很多种(但是把握核心,就是数据值)

  二、位置参数

      1、位置参数:按照从左往右的顺序依次填入的参数

      2、位置参数分类

        2.1、位置形参:在函数定义阶段括号内按照从左往右的顺序依次填入的变量名

        2.2、位置实参:在函数调用阶段括号内按照从左往右的顺序依次填入的数据值

      3、关键字实参(可以打破位置顺序):在函数调用阶段通过形参名=数据值的形式指名道姓的传值

        4、 特点:

        4.1、位置形参与位置实参在函数调用阶段,按照位置一一对应绑定

        4.2、位置参数在绑定的时候多一个不行少一个也不行

     小技巧:格式越简单的越靠前,格式越复杂的越靠后

def my_max(a, b):  # a,b  位置形参
    print(a, b)
    if a > b:
        return a
    else:
        return b
# res = my_max(111, 222)  # 111,222  位置实参
# res = my_max(111)  # 111,222  位置实参
# res = my_max(111,222,333)  # 111,222  位置实参
# print(res)、

# res = my_max(b=123,a=222)  # 指名道姓的传
# res = my_max(111,b=222)  # 可以
# res = my_max(111,a=222)  # 不可以 111会按照位置传给形参a 222会按照关键字参数也传给形参a  这种情况不允许出现
# res = my_max(b=222,111)  # 不可以 位置参数必须要在关键字参数的前面
# res = my_max(a=222,111)  # 不可以 位置参数必须要在关键字参数的前面

  三、默认参数

    1、默认参数就是默认形参

    2、默认形参:函数在定义阶段就可以给形参赋值了

    3、默认形参的特征:

      1、该形参在函数调用阶段如果不给值,则使用默认的

      2、该形参在函数调用阶段也可以继续给值,则使用你给的

    4、位置形参与默认值形参在定义的时候,位置形参在默认值形参的前面

    小技巧:格式越简单的越靠前,格式越复杂的越靠后

  默认参数实际案例

def register(name, age, gender='male'):
    print('%s:%s:%s' % (name, age, gender))

register('jason', 18)
register('tony', 28)
register('kevin', 38)
register('lili', 18, 'female')
register('lili', 18, gender='female')

  注意案例

# 1、默认形参如果绑定的是一个列表 那么指向的是固定的一个地址
def func(name, age, hobby=[]):
    hobby.append(age)
    print('%s:%s:%s' % (name, age, hobby))

func('jason', 18)  # jason:18:[18]
func('kevin', 28)  # kevin:28:[18, 28]
func('tony', 38)  # tony:38:[18, 28, 38]

func('jason', 18, [])  # jason:18:[18]
func('kevin', 28, [])  # kevin:28:[28]
func('tony', 38, [])  # tony:38:[38]


# 2、
m = 200
def func(a, b, c=m):
    print(a, b, c)
m = 400
func(1, 2)  # 200

  四、可变长参数

    1、函数无论传入多少位置参数都可以正常运行

def func(x, y, *a):
    print(x, y, a)


func()  # ()
func(1)  # (1,)
func(1, 2, 3, 4, 5, 6, 7)  # (1, 2, 3, 4, 5, 6, 7)
func(1, 2)  # 1 2 ()
func(1, 2, 3, 4, 5, 6, 7, 8, 9)  # 1 2 (3, 4, 5, 6, 7, 8, 9)
func(1, 2)  # 1 2 (3, 4, 5, 6, 7, 8, 9)
"""
*号在形参中的使用
    用于接收多余的位置参数 并组织成元组的形式赋值给*号后面的变量名
"""

    2、函数无论传入多少关键字参数都可以正常运行

def index(x, y, **b):
    print(x, y, b)


index()  # {}
index(a=1, b=2, c=3, d=4)  # {'a': 1, 'b': 2, 'c': 3, 'd': 4}
index(y=2, x=1)  # 1 2 {}
index(y=2, x=1, u=222, k=111, l=444)  # 1 2 {'u': 222, 'k': 111, 'l': 444}
"""
**号在形参中的使用
    用于接收多余的关键字参数 并组织成字典的形式赋值给**号后面的变量名
"""

    3、定义一个函数无论传入多少位置参数和关键字都可以正常运行

def index(*a,**b):
    print(a,b)
index()  # () {}
index(1,2,3,4)  # (1, 2, 3, 4) {}
index(a=1,b=2,c=3)  # () {'a': 1, 'b': 2, 'c': 3}
index(1,2,3,4,a=1,b=2,c=3)  # (1, 2, 3, 4) {'a': 1, 'b': 2, 'c': 3}
"""
墨守成规
    可变长形参 *与**后面的变量名其实是可以随便定义的
    但是python中推荐使用
        *args  
        **kwargs 
def index(*args, **kwargs):
    pass
"""

    4、*和**的实际应用

def index(a, b, c):
    print(a,b,c)
new_list = [11,22,33]
index(new_list)  # 肯定不行  列表是一个整体 相当于一个实参
index(new_list[0],new_list[1],new_list[2])  # 可以
'''如果index形参是*args 列表里面有很多元素 如何实现按照位置一一传入'''
def index1(*args):
    print(args)
new_list1 = [11,22,33,44,55,66,77,88,99]
index1(*new_list1)  # index1(11,22,33,44,55,66,77,88,99)
"""
*号在实参中的使用
    会将列表、元组内的元素打散成位置参数的形式一一传值
"""

def index2(**kwargs):
    print(kwargs)
new_dict = {'username': 'jason', 'pwd': 123}
index2(**new_dict)  # index2(username='jason',pwd=123)
{'username': 'jason', 'pwd': 123}
"""
**号在实参中的使用
    会将字典内的键值对打散成关键字参数传入
"""

  五、函数参数补充了解

def register(name, age, *, sex, height):
    pass
register('jason',18,'male',183)
register('lili',18,sex='male',height='1.8m') #正确使用
"""
sex height在传入实参的时候必须以关键字参数的形式

ps:该类型的参数几乎不用 也几乎很少能碰到
"""

函数对象(函数名)

"""函数名遇到括号就会调用!!!"""
# 用法1:函数名可以当做变量名赋值
def index():
    print('from index')
a = index
a()  # 本质就是在调用index函数

# 用法2:函数名还可以当做函数的实参
def index():
    print('from index')
def func(a):
    print(a)
    a()
    print('from func')
func(index)

# 用法3:函数名还可以当做函数返回值
def index():
    print('from index')
def func():
    print('from func')
    return index
res = func()  # 调用func并接受func的返回值
res()

# 用法4:函数名可以当做容器类型(内部可以存放多个数据)的元素
def index():
    print('from index')
l = [111, 222, 333, index()]
print(l)

   案例演示

def register():
    print('注册功能')
def login():
    print('登录功能')
def shopping():
    print('购物功能')
def transfer():
    print('转账功能')
def withdraw():
    print('提现功能')
def check_order():
    print('查看订单')
func_dic = {'1':register,
            '2':login,
            '3':shopping,
            '4':transfer,
            '5':withdraw,
            '6':check_order
            }
while True:
    print("""
    1.注册功能
    2.登录功能
    3.购物功能
    4.转账功能
    5.提现功能
    6.查看订单
    """)
    choice = input('请输入功能编号>>>:').strip()
    # 判断用户输入的编号在不在字典的k中
    if choice in func_dic:
        # 根据键获取值(函数名)
        func_name = func_dic.get(choice)
        # 函数名加括号调用
        func_name()
    else:
        print('功能编号不存在')

函数的嵌套调用

# 嵌套调用:函数内部调用其他函数
def index():
    print('from index')
def func():
    index()
    print('from func')
func()

def my_max(a, b):
    if a > b:
        return a
    return b
def many_max(x,y,z,m):
    res = my_max(x,y)
    res1 = my_max(res,z)
    res2 = my_max(res1,m)
    return res2
ret = many_max(1,2,3,4)
print(ret)

函数的嵌套定义

   函数体内部定义其他函数;将复杂的功能全部隐藏起来,只暴露一个简单的接口

def index():
    name = 'tony'
    def func():
        print('from func')
index()

    案例演示

def all_func(type):
    def register():
        print('注册功能')
    def login():
        print('登录功能')
    def transfer():
        print('转账功能')
    def shopping():
        print('购物功能')
    # 这里仅仅是延时嵌套定义的现象 暂不考虑优化
    if type == '1':
        register()
    elif type == '2':
        login()
    elif type == '3':
        transfer()
    elif type == '4':
        shopping()
    else:
        print('不知道啥功能')

all_func('3')

闭包函数

  闭:定义在函数内部的函数

  包:内部函数使用了外部函数名称空间中的名字

def outer():
    x = 222
    def index():
        print('from index', x)
    return index

  闭包函数其实是给函数传参的第二种方式

# 方式1:函数体代码需要用到数据 直接在括号内定义形参即可
def index(username):
    print(username)
def my_max(a, b):
    if a > b:
        return a
    return b
# 方式2:利用闭包函数
def outer(x,y):
    # x = 2
    # y = 40
    def my_max():
        if x > y:
            return x
        return y
    return my_max
res = outer(2,40)
print(res())
print(res())

递归函数

  1、定义

    递归:函数在运行过程中,直接或者间接的调用了自身

  2、小知识

    官网表示:python默认的最大递归深度为1000次

 

   3、递归分为递推和回溯

      递推:一层层往下推导答案(每次递归之后复制度相较于上一次一定要有所下降)

      回溯:依据最后的结论往后推导出最初需要的答案

      注意:递归一定要有结束条件

  4、演示

def func():
    print('from func')
    index()
def index():
    print('from index')
    func()
index()

  5、案例演示

  某公司四个员工坐在一起,问第四个人薪水,他说比第三个人多1000,问第三个人薪水,第他说比第二个人多1000,问第二个人薪水,他说比第一个人多1000,最后第一人说自己每月5000,请问第四个人的薪水是多少?

   思路解析:

  要知道第四个人的月薪,就必须知道第三个人的,第三个人的又取决于第二个人的,第二个人的又取决于第一个人的,而且每一个员工都比前一个多一千,数学表达式即:

salary(4)=salary(3)+1000 
salary(3)=salary(2)+1000 
salary(2)=salary(1)+1000 
salary(1)=5000
总结为: 
salary(n)=salary(n-1)+1000 (n>1) 
salary(1)=5000 (n=1) 

  很明显这是一个递归的过程,可以将该过程分为两个阶段:回溯和递推。

​   在回溯阶段,要求第n个员工的薪水,需要回溯得到(n-1)个员工的薪水,以此类推,直到得到第一个员工的薪水,此时,salary(1)已知,因而不必再向前回溯了。然后进入递推阶段:从第一个员工的薪水可以推算出第二个员工的薪水(6000),从第二个员工的薪水可以推算出第三个员工的薪水(7000),以此类推,一直推算出第第四个员工的薪水(8000)为止,递归结束。需要注意的一点是,递归一定要有一个结束条件,这里n=1就是结束条件。

 

   代码

def salary(n):
    if n==1:
        return 5000
    return salary(n-1)+1000

s=salary(4)
print(s)
# 结果为8000

  练习题

l = [1,[2,[3,[4,[5,[6,[7,[8,[9,[10,[11,[12,[13,[14,]]]]]]]]]]]]]]
# 打印出列表中每一个元素(列表除外)
# 1.循环该列表 获取列表内每一个元素
# 2.判断该元素是否是数字 如果是数字 则直接打印
# 3.如果是列表 则循环该列表 获取列表内每一个元素
# 4.判断该元素是否是数字 如果是数字 则直接打印
# 5.如果是列表 则循环该列表 获取列表内每一个元素
# 6.判断该元素是否是数字 如果是数字 则直接打印
# 7.如果是列表 则循环该列表 获取列表内每一个元素
def get_num(l):
    for i in l:
        if type(i) is int:
            print(i)
        else:
            # 也是for循环 然后判断
            get_num(i)
get_num(l)

匿名函数

  1、定义

    没有名字的函数

  2、格式

    lambda  形参 :返回值

    匿名函数一般不会单独使用,都是配合其他函数一起使用

  3、案例

      计算二次方

l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
def index(n):
    return n ** 2
print(list(map(lambda x:x**2, l)))
# 其中map()为映射

 

posted @ 2021-11-12 16:25  那就凑个整吧  阅读(129)  评论(0编辑  收藏  举报