美文网首页Python
Python函数基础

Python函数基础

作者: xilifeng | 来源:发表于2020-08-17 17:01 被阅读0次

    一. 函数: 先定义, 后调用

    1. 定义函数的语法: 实质上也是申请内存空间,代码块放入内存空间,内存地址绑定给函数名,形似定义变量

    def 函数名(参数1, 参数2, 参数3, ...):  # 函数名命名规则同变量名,小写加_,参数可无
        """
        文档注释,可无
        """
        代码1  # 定义阶段, 只检测语法, 不执行代码
        代码2
        代码3
        ...
        return 返回值  # 可无,是否要返回值,依据为代码运行的结果是否要作进一步后续处理
    

    2. 参数后可加类型提示, 通常省略, 加或不加均不影响函数本身的执行

    def add(x: "数字", y: int, z: (int, float)) -> int:  # ->表示返回值的形式
        return x + y + z
    

    二. 定义函数的三种形式

    1. 无参函数 def func():

    2. 有参函数,函数体代码需要外部传参数x,y,z,则def func(x, y, z):

    3. 空函数

    def func():
        pass
    

    三. 调用函数的语法: 通过函数名找到函数的内存地址,()触发内存空间里代码的运行,才会发现逻辑错误

    函数名(值1, 值2, 值3, ...)  # 定义了有参函数, 调用的时候一定要传值
    

    四. 调用函数的三种形式

    1. 语句形式: 没有返回值的函数, 不能赋值, 单纯调用

    def max(x, y):
        if x > y:
            print(x)
        else:
            print(y)
    
    
    max(11, 22)
    

    2. 表达式形式: 有返回值的, 可用来赋值表达式, 或算数运算

    def max(x, y):
        if x > y:
            return x
        else:
            return y
    
    
    res = max(11, 22)
    

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

    def max(x, y):
        if x > y:
            return x
        else:
            return y
    
    
    max(max(11, 22), 33)
    

    五. 函数返回值return

    1. return是函数结束的标志,函数内可有多个return,可用来结束函数内while循环

    2. return值,可以没有或只有return,返回None,可以返回一个值,也可以值1,值2,...返回一个元组,内含多个值

    def func():
        print("Hello1")  # 本来print就有返回值,故不需要返回.但数字,运算结果如不return,就没返回值
        return 1, 2.2, [1, 2, 3]  # 只要执行一次,整个函数就终止,return的结果作为本次调用的返回值
        print("前面return 1 其实已终止,这段不会打印")
        return 2
    
    
    func()  # 打印结果为Hello1
    print(func())  # 打印结果为Hello1和(1, 2.2, [1, 2, 3])
    

    六. 函数的参数: 形参与实参

    1. 形参: 函数定义时, def func(变量名):括号内的参数, 叫形式参数,形参

    2. 实参: 函数调用时, func(变量值)括号内传入的值, 叫实际参数,实参

    3. 位置参数: 按位置参数分为 位置形参, 位置实参

    3.1 位置形参: 函数定义时,从左到右依次定义的形参def func(x, y):,必须被传值,多或少一个都不可

    3.2 位置实参: 函数调用时,从左到右依次传入的值,位置与位置形参一一对应

    4. 关键字实参: 函数调用时,按key=value的形式传值def func(y=2, x=1):,显式赋值,不管参数x,y顺序

    def func(x, y):
        print(x, y)
    
    
    func(11, y=2)  # 位置实参可以和关键字实参混用
    func(y=2, 11)  # 报错, 位置实参必须放在前面
    func(11, x=22, y=33)  # 报错, 不能为同一形参重复赋值
    

    5. 默认形参: 函数定义时,已为形参赋值,称为默认形参.以下示例不推荐,y=m容易和外部耦合,最好显式赋值y=22

    m = 22  # 但如果此处是m=[],同时后面不是m=33,而是m.append(44),打印结果为y=[44],因为m内存地址没变
    
    
    def func(x, y=m):  # 可以混用位置形参和默认形参,位置形参必在前面,(y=22,x)报错
        print(x, y)  # 打印结果y=22,默认形参的值只在定义时赋值一次,因为上句y拿到的是m的内存地址
    
    
    m = 33
    
    func(11)  # 函数调用时, 默认形参x可以不用传值
    func(11, 33)  # 函数调用时传值, 则用传入的值
    
    def func(name, hobby, hobbies=None):  # 若hobbies=[],结果会叠加,故为每次调用都独立,默认形参必须不可变类型
        if hobbies is None:  # 因为默认形参的值只在定义时赋值一次,故定义首行不能用列表,而是调用时判断赋值
            hobbies = []
        hobbies.append(hobby)
        print("%s 的爱好是 %s" % (name, hobbies))
    
    
    func("u1", "cs")
    func("u2", "mv")  # 若hobbies=[],没有if判断,def func()只运行一次,而func()运行两次,u2的爱好是['cs','mv']
    

    6. *与**在形参中接收溢出位置的实参, 汇总: 可变长的实参在函数调用时, 传入的值的个数不固定

    6.1 *在形参中, 把溢出的位置实参存成元组的形式

    def func(x, *args):  # x=1 args=(2, 3)
        print(x, args)
    
    
    func(1, 2, 3)
    

    6.2 **在形参中, 把溢出的关键字实参存成字典的形式

    def func(x, **kwargs):  # x=1 kwargs={'a': 2, 'b': 3, 'c': 4}
        print(x, kwargs)
    
    
    func(x=1, a=2, b=3, c=4)
    

    7. *与**在实参中, 解压操作, 实参个数要和形参个数一样

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

    7.1 *在实参中, 把能被for循环的实参值解压成位置实参

    func(*[1, 2, 3])  # func(1, 2, 3),实参个数要和形参个数一样
    

    7.2 **在实参中, 把字典格式的实参值解压成关键字实参

    func(**{"x": 1, "y": 2, "z": 3})  # key要和形参对应
    

    8. *与**混用: *在前,**在后

    def wrapper(*args, **kwargs):  # 可以接受所有长度的形参个数, args=(1,2) kwargs={"a":1,"b":2}
        index(*args, **kwargs)  # wrapper传的值一摸一样地给了index,index(*(1,2),**{"a":1,"b":2})
    
    
    wrapper(1, 2, a=1, b=2)  # index(1,2,a=1,b=2)
    

    七. 函数对象: 函数可以当变量去用

    def func():  # func=函数的内存地址
        print("from func")
    

    1. 可以被赋值

    f = func
    f()  # 调用函数,得到执行结果形式一定是函数名(), from func
    

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

    def foo(f):  # 注意,以下不同使用函数名,得到的3种执行结果
        print(f)  # 取函数名的内存地址的形式,print(函数名)
        f()  # 典型的调用函数,得到执行结果的形式, from func
    
    
    foo(func)  # 区别另一种,函数名(函数名())则是调用返回值的形式,None
    

    3. 可以当作函数的返回值

    def foo(f):
        return f
    
    
    print(foo(func))  # 打印函数名的内存地址
    

    4. 可以当作容器类型的元素

    l = [func, ]
    print(l)  # 打印列表中此函数名的内存地址,[<function func at 内存地址>]
    l[0]()  # 通过列表调用函数,得到执行结果,形式类似func()
    

    4.1 示例

    def login():
        print("登录...")
    
    
    def register():
        print("注册...")
    
    
    def tranfer():
        print("转账...")
    
    
    def withdraw():
        print("提现...")
    
    
    func_dic = {
        "1": ["登录", login],
        "2": ["注册", register],
        "3": ["转账", tranfer],
        "4": ["提现", withdraw]
    }
    
    while True:
        for k, v in func_dic.items():
            print(k, v[0])
        choice = input("请输入您的命令编号,输入0退出:").strip()
        if choice == "0":
            break
        if choice in func_dic:
            func_dic[choice][1]()
        else:
            print("输入的指令错误")
    

    八. 函数嵌套: 嵌套定义, 嵌套调用

    1. 函数的嵌套调用: 在调用一个函数的过程中又调用了其他函数, 也可以调用自己

    def max2(x, y):
        if x > y:
            return x
        else:
            return y
    
    
    def max4(a, b, c, d):
        res1 = max2(a, b)
        res2 = max2(res1, c)
        res3 = max2(res2, d)
        return res3
    
    
    print(max4(1, 2, 3, 4))
    

    2. 函数的嵌套定义: 在一个函数内部又定义了其他函数

    2.1 定义在函数内的函数, 只能函数内部使用, 一种封闭的效果

    def f1():
        def f2():
            print('from f2')
    
        x = 111
        print(x)
        f2()
    
    
    f1()
    

    2.2 封闭效果应用示例

    from math import pi
    
    
    def circle(radius, action=1):
        def perimeter(radius):
            return 2 * pi * radius
    
        def area(radius):
            return pi * (radius * radius)
    
        if action == 1:
            return perimeter(radius)
        elif action == 2:
            return area(radius)
    
    
    print(circle(10, 1))
    print(circle(10, 2))
    

    3. 函数的嵌套定义 + 函数对象

    def f1():
        def f2():  # 把f2封闭在f1内
            print('from f2')
    
        return f2  # 打破封闭层级限制
    
    
    res = f1()  # f1()执行结果显示为空,实际只有返回f2内存地址,res=f2
    print(res)  # 打印结果为返回值f2的内存地址
    res()  # 执行f2内存地址中的代码块,打印from f2
    

    九. 递归调用: 基于函数, 实现循环的方式

    1. 定义: 在调用一个函数的过程中, 又直接或者间接地调用函数自己

    def foo():
        print('from foo')
        foo()  # 调用函数的过程中,直接调用自己
    
    
    foo()  # Python没有伪递归优化,会一直递归下去,内存地址不会回收
    
    import sys
    
    print(sys.getrecursionlimit())  # 递归的最大层级限制1000层
    sys.setrecursionlimit(2000)  # 改递归层级限制保护
    
    def foo():
        print('from foo')
        bar()  # 调用函数的过程中,间接地调用自己
    
    
    def bar():
        print('from bar')
        foo()
    
    
    foo()
    

    2. 递归调用有两个阶段

    2.1 回溯: 一层一层地递归调用下去. 回溯阶段内存一直被占用

    2.2 递推: 在某一层结束递归调用, 开始向上一层一层地返回, 内存开始一层一层回收.

    """
    # age(3) = age(2) + 10  # age(3)没有值,则找age(2),如此自上而下叫回溯.等到递推后,age(2)拿到值然后+10
    # age(2) = age(1) + 10  # age(2)没有值,则找age(1),回溯占用内存.
    # age(1) = 18  # age(1)拿到值后,开始自下而上,递推,age(2),age(3)...自此开始回收内存.
    """
    
    
    def age(n):
        if n == 1:
            return 18
        return age(n - 1) + 10  # 递推后age(2)拿到值+10后,这行age(3)才算运行完,内存才能回收
    
    
    res = age(3)
    print(res)
    

    3. 递归调用思路: 基于函数,重复某段代码,控制结束条件,在某个点结束递归调用

    3.1 应用场景: 取出每个列表中的每一个元素

    nums = [1, [2, [3, [4, [5, [6, [7, [8, [9]]]]]]]]]
    
    
    def func(l):
        for item in l:
            if type(item) is list:
                func(item)  # for item2 in item这个是要传入的参数:if type(item2) is list:...
            else:
                print(item)
    
    
    func(nums)
    

    3.2 应用场景2: 算法之二分法, 此算法用来查询, 模拟实现in关键字

    nums = [-3, 11, 13, 25, 37, 39, 43, 52, 77, 84, 91]  # 此列表必须有序,从大到小或从小到大
    
    
    def search(list1, find_num):
        print(list1)  # 每次调用的时候, 可以打印看下每次列表被切成的样子
        if len(list1) == 0:
            print('not exists')
            return
    
        mid_index = len(list1) // 2
        if find_num > list1[mid_index]:  # on the right
            search(list1[mid_index + 1:], find_num)
        elif find_num < list1[mid_index]:  # on the left
            search(list1[:mid_index], find_num)
        else:
            print('find it')
    
    
    search(nums, 84)
    

    十. 匿名函数

    1. 定义: 没有名字的函数,故只能调用一次就被回收,只适用于临时调用一次的场景

    res = (lambda x, y: x + y)(1, 2)  # 形参不加括号,无默认,可变长参数,自带return,故不写
    print(res)
    

    2. 匿名函数应用示例

    salaries = {
        "egon": 3000,
        "alex": 5000,
        "zhangsan": 1000,
    }
    
    print(max([11, 10, 44, 9]))  # max方法可以打印最大值44
    print(max(salaries))  # 打印zhangsan,max迭代取值key,返回必是key,z字母最大,不能取value最大值
    
    def func(k):  # 取薪资value最大的key
        return salaries[k]
    
    
    res = max(salaries, key=func)  # func没有(),key是max内置的比较依据,但返回还是key
    
    res = max(salaries, key=lambda k: salaries[k])  # 等同上面func
    print(res)
    
    res = min(salaries, key=lambda k: salaries[k])  # min方法取最小值
    print(res)
    
    res = sorted([11, 10, 44, 9], reverse=True)  # sorted方法默认从小到大排序
    print(res)  # reverse是反向,从大到小,打印[44, 11, 10, 9]
    
    res = sorted(salaries, key=lambda k: salaries[k])  # sorted按薪资排序
    print(res)
    

    十一. 三元表达式

    res = 条件成立时的返回值或表达式 if 条件 else 条件不成立时的返回值或表达式

    res = x if x > y else y  # 自带return,故表达式会返回运行结果
    print(res)
    
    def max2(x, y):  # 等同上面的三元表达式
        if x > y:
            return x
        else:
            return y
    

    十二. 面向过程编程

    1. 这是一种编程范式,编程的思想,或编程的套路,面向过程编程不等于用函数编程

    2. 核心是过程二字,面向过程指以过程为核心,过程即做事的步骤,即先干什么,再干什么,然后干什么,比如脚本

    3. 基于该思想写程序就好比是在设计一条条的流水线,一条流水线就是一个功能

    4. 过程式的思想是把大的问题分解成多个子过程去实现,然后依次调用

    5. 优点:复杂问题流程化、进而简单化

    6. 缺点:扩展性差,某一环节变了,前后有关联的环节都要跟着变

    7. 演示示例: 写一个数据远程备份程序, 分三步: 本地数据打包,上传至云服务器,检测备份文件可用性

    import os, time
    
    
    def data_backup(folder):  # 第一步,本地数据打包
        print("找到备份目录: %s" % folder)
        print('正在备份...')
        zip_file = '/tmp/backup_%s.zip' % time.strftime('%Y%m%d')
        print('备份成功,备份文件为: %s' % zip_file)
        return zip_file
    
    
    def cloud_upload(file):  # 第二步,上传至云服务器
        print("\nconnecting cloud storage center...")
        print("cloud storage connected")
        print("upload [%s] to cloud..." % file)
        link = 'https://www.xxx.cn/bak/%s' % os.path.basename(file)
        print('close connection')
        return link
    
    
    def data_backup_check(link):  # 第三步,检测备份文件可用性
        print("\n下载文件: %s , 验证文件是否无损..." % link)
    
    
    zip_file = data_backup(r"/Users/test")  # 第一步调用,本地数据打包
    link = cloud_upload(zip_file)  # 第二步调用,上传至云服务器
    data_backup_check(link)  # 第三步调用,检测备份文件的可用性
    

    相关文章

      网友评论

        本文标题:Python函数基础

        本文链接:https://www.haomeiwen.com/subject/ocvqjktx.html