7 Python函数

函数是组织好、可重复使用、用来实现单一或相关联功能的代码块。可以说函数是模块化的一种体现。定义好函数后,放在函数库中,等到需要用的时候直接调用,不仅方便重复使用,提高编码效率,还可以提高代码的简洁性和逻辑性。

7.1 如何定义一个函数

类似于C语言和Java的函数或方法的定义,定义Python函数有以下几个步骤:

  • 函数代码块以def关键字开头,后接函数标识符名称和小括号();
  • 任何传入的参数和自变量必须放在小括号内,小括号之间可以用于定义参数,且参数可以是任意类型;
  • 函数的第一行语句可以选择性地使用文档字符串——用于存放函数说明,增加代码可读性;
  • 函数内容以冒号起始,并且需要缩进;
  • return [表达式]结束函数,选择性地返回一个值给调用方,不带表达式的return相当于返回none
# 1.创建函数格式:def function_name([参数1],[参数2]... ):
def function_1():
    print("Hello")  # 函数创建后需要调用才会被执行
# 2.调用函数
function_1()  # 结果为:Hello
# 创建有参数的函数
def function_2(a):
    print(a)
# 调用有参数的函数
function_2("Hello")  # 结果为:Hello

7.2 函数的参数

Python中的函数参数具有灵活性,可以接受各种形式的参数。函数中的pass关键字与第6章节的作用是一致的,都是为了保证程序代码的完整性。

  • 位置参数:在对函数进行调用的时候,有几个位置参数(坑)就需要传递几个参数(萝卜),否则会触发异常,并且传入的参数与函数参数列表是一一对应的。
def plus(a,b):
    print(a + b)
plus(20,60)  # 结果为30,如果传递三个参数,就会报错。参数需要一一对应
  • 默认参数:默认参数即带有默认值的参数,在对该函数进行调用时,可以不不显示传递参数给函数。当不传递参数时,函数将使用默认值。默认值只能会执行一次,这条规则在默认值为可变对象时非常重要,所以建议默认参数使用不可变对象,因为可变对象会存储在后续调用中传递给它的参数。
def plus_default(a=1,b=2):
    print(a + b)
plus_default()  # 结果为:3
plus_default(600)  # 结果为:602默认传递给a(按顺序赋值)
plus_default(600, 400)  # 结果为:1000
plus_default(b=400)  # 结果为:401,指定默认参数传值
# 第二个参数为可变对象时
def plus_default_1(a, b=[]):
    b.append(a)
    print(b)
plus_default_1(1)  # 结果为:[1]
# 第二次调用时候,第一次存储的数据一直在列表中,不会消失
plus_default_1(2)  # 期待为:[2],但结果为:[1, 2]
plus_default_1(3)  # 期待为:[3],但结果为:[1, 2, 3]
def plus_default_2(a, b=None):
    if b is None:
        b = []
    b.append(a)
    print(b)
plus_default_2(1)  # 结果为:[1]
plus_default_2(2)  # 结果为:[2]
def function_3(a, b=4, c):  # 默认参数后面必须也是默认参数
    print(a)
    print(b)
    print(c)
function_3(1, 2, 3)  # 会报错
def function_3(a, b=4, c=3):
    print(a)
    print(b)
    print(c)
function_3(1, 2, 3)  # 结果为:1 2 3(空格代表回车),并且可以换b,c的位置:function_3(1, c=4, b=3)
  • 关键字参数:函数调用时,指定参数名称,成为关键字参数。在函数调用时,关键字参数必须在普通参数后面。
def function_key(a=1, b=2):  # 这是默认参数,在函数定义时
    print(a + b)
function_key(a=3, b=4)  # 这是关键字参数,在函数调用时
function_key(2, b=6)  # 关键字参数必须在普通参数后面,不然会报错,结果为:8
  • 限定关键字形参(命名关键字参数):必须使用关键字方式传递参数。限定关键字形参为了限制后面几个参数只能按关键字传递,这往往是因为后面几个形参名具有十分明显的含义,显式写出有利于可读性,或者后面几个形参随着版本更迭可能会发生变化,强制关键字形式有利于保证跨版本兼容性。
def function_4(a, *, c, d):  # 星号是占位
    print(a, c, d)
function_4(1, c=3, d=4)  # c,d必须使用关键字传参,结果为:1 3 4
  • 可变参数:①*参数:最常见的变量名是args,看到该变量名,就知道变量args指向一个tuple对象。自动收集所有未匹配的位置参数到一个tuple对象中,变量名args指向了此tuple对象。②**参数:最常见的变量名是kwargs,看到该变量名,就知道变量kwargs指向一个dict对象。它会自动收集所有未匹配的关键字参数到一个dict对象中,变量名kwargs指向此dict对象。
# ------------一个*号------------
def function_5(a, b):
    print(a, b)
#function_4(1)  会报错,如何解决,我向传递一个参数,但是不会报错->利用星号
def function_6(a, *b):
    print(a, b)
function_6(1)  # 结果为:1 (),b为元组
function_6(1, 2)  # 结果为:1 (2,)
function_6(1, 2, 3, 4, 5)  # 结果为:1 (2, 3, 4, 5)
# 一般星号的b参数后面换成args参数,默认的,形成习惯了,看到args就知道作用是什么!
# ------------两个**号------------
def function_7(a, **b):
    print(a, b)  # b指向空字典{}
function_7(1)  # 结果为:1 {}
function_7(1, 2)  # 会报错
function_7(1, x=2, y=3)  # 结果为:1 {'x': 2, 'y': 3}
# 一般星号星号的b参数后面换成kwargs参数,默认的,形成习惯了,看到args就知道作用是什么!

函数的参数总结:

序号参数的类型

  函数的定义(形式参数)

函数的调用(实际参数i)备注
1位置实参
将列表中的每个元素都转换为位置实参使用*
2关键字实参
将字典中的每个键值对都转换为关键字实参使用**
3默认值形参
4关键字形参使用*
5个数可变的位置形参使用*
6个数可变的关键字形参使用**

7.3 参数排列的位置

参数排列位置的注意事项:

  • 可变参数,必须定义在普通参数以及默认值参数后面
  • 函数定义时,二者同时存在,需要将*args放在**kwargs之前
def fucntion_name(普通参数,默认参数s="",*参数,**参数):
    pass

例子:

def function_eg(a, b="learn", *args, **kwargs):
    print(a, b, args, kwargs)  # 结果为:1 Emily (1, 2, 3, 4) {'x': 1, 'y': 2, 'z': 3}
    for i in args:
        print(i, end=" ")  # 结果为:1 2 3 4
    for key, value in kwargs.items():
        print(key, end=" ")
        print(value, end=" ")  # 结果为:x 1 y 2 z 3 
function_eg(1, "Emily", 1, 2, 3, 4,x=1,y=2,z=3)

7.4 参数解包(拆包)

解包意义:将传递给函数的一个列表,元组,字典,拆分成独立的多个元素然后赋值给函数中的形参变量。(变量数量 = 元素数量,会进行逐一赋值,比如a, b, c = [1, 2, 3],结果为a=1 b=2 c=3)

解包有两种解法:一种用*解的只有key,一种用**解的有key、value。但是这个方法**只能在函数定义中使用。传递实参时,可以在序列类型的参数前添加*(星号),这样他会自动将序列中的元素依次作为参数传递。参数数据类型为:字符串/列表/元组/集合/字典的时候可以解包。

s = "123"
list_1 = [1, 2, 3]
tuple_1 = (4, 5, 6)
set_1 = {7, 8, 9}
dict_1 = {"a": "Emily",
          "b": 18,
          "c": "Python"}
def function_8(a ,b ,c):
    print(a, b, c)
function_8(*s)  # 结果为:1 2 3,如果s="123456"会报错,长度得于参数长度一致,多于少于都不行
function_8(*list_1)  # 结果为:1 2 3,如果list_1=[1,2,3,4]会报错,长度得于参数长度一致,多于少于都不行
function_8(*tuple_1)  # 结果为:4 5 6
function_8(*set_1)  #结果为:8 9 7
function_8(*dict_1)  # 结果为:a b c
function_8(**dict_1)  # 结果为:Emily 18 Python
# 在使用两个星号得到值时,拆包的形参和实参必须对应,也就是说字典的键名和函数的参数一致!!!
"""
function_8(**dict_1)也可以这样写:
function_8(dict_1['a'], dict_1['b'], dict_1['c'])  # 因为这样写很复杂,所以使用**
这里就可以理解为什么拆包的形参和实参必须对应(字典的键名和函数的参数一致)
"""

Python的参数解包和可变参数一起使用,**参数只能收集未匹配的关键字参数(字典)

def function_9(a, *args):
    print(a, args)
function_9(1)  # 结果为:100 ()
function_9(1, (1, 2, 3))  # 结果为:1 ((1, 2, 3),)
function_9(1, *(1, 2, 3))  # 结果为:1 (1, 2, 3),解包后:(1, 2, 3)成为一个元素,不是元组内的元素了

dict_2 = {"name": "Emily",
          "age": 18,
          "skill": "Python"}
def function_10(a, **kwargs):
    print(a, kwargs)
function_10(1)  # 结果为:1 {}
function_10(1, b=2, c=3)  # 结果为:1 {'b': 2, 'c': 3}
function_10(1, **dict_2)  # 结果为:1 {'name': 'Emily', 'age': 18, 'skill': 'Python'}

function_10(1, **dict_2)  # 结果为:1 {'name': 'Emily', 'age': 18, 'skill': 'Python'}

7.5 变量的作用域

变量的作用域:程序代码能访问该变量的区域,根据变量的有效范围可分为:

  • 局部变量:在函数内定义并使用的变量,只在函数内部有效,局部变量使用global声明,这个变量就转变成全局变量;
  • 全局变量:函数体外定义的变量,可作用于函数内外;
def function_vary(a, b):
    c = a + b  # c是在函数体内定义的变量,为局部变量。而a b是函数的形参,作用范围也是函数内部,相当于局部变量
    print(c)
name = "Emily"  # name的作用范围为函数内部外部都可以使用->>>全局变量
print(name)
def function_vary2():
    print(name)
function_vary2()  # 结果为:Emily
def function_vary3():
    global age  # 函数内部定义的变量使用global声明时,这个变量实际上就变成了全局变量
    age = 20
    print(age)
function_vary3()
print(age)  # 结果为:20

7.6 函数的返回值

在Python中,函数可以使用return返回数据,也可以不用return返回,默认返回“None”。在函数执行时,return关键字用来帮助返回处理好的数据。

def function_11():
    print("Hello")
function_11()  # 函数调用的返回值,可以用变量接收
r = function_11()
print(r)  # 返回值为None
def function_12(a):
    return a + 1
res = function_12(1)
print(res)  # 返回值为2
def function_13(a, b, c):
    return a + 100, b + 100, c + 100
res1 = function_13(100, 100, 100)
print(res1)  # 结果为:(200, 200, 200)
print(type(res1))  # 结果为:<class 'tuple'>,返回值是一个元组数据类型
x, y, z = res1  # 依次解包元组
print(x, y, z)  # 结果为:200 200 200

7.7 函数返回函数

函数里面嵌套函数且函数的返回值是函数

def function_14():
    def function_15():
        return [1, 2, 3]
    return function_15
res2 = function_14()
print(res2)  # 接收的是xyz这个函数,而不是函数的返回值,所以结果为:<function function_14.<locals>.function_15 at 0x000001CB923525E0>
res3 = res2()
print(res3)  # 结果为:[1, 2, 3]
# 其实还可以这样写
def function_16():
    def function_17():
        return [1, 2, 3]
    return function_17()
res4 = function_16()
print(res4)  # 结果为:[1, 2, 3]

7.8 递归函数

递归函数:函数直接或间接调用函数本身,则该函数称为递归函数,通俗的来说就是自己调用自己。Python中的递归调用和Java、C语言的递归调用没有很大差别!

递归函数的组成部分:

  • 递归调用
  • 递归出口
def factorial(n):
    if n == 1:  # 递归出口
        return 1
    else:
        return n * factorial(n-1)  # 递归调用
print(factorial(10))  # 结果为:3628800
# 调用的过程为:
factorial(6)                             # 第 1 次调用 使用 6
6 * factorial(5)                         # 第 2 次调用 使用 5
6 * (5 * factorial(4))                   # 第 3 次调用 使用 4
6 * (5 * (4 * factorial(3)))             # 第 4 次调用 使用 3
6 * (5 * (4 * (3 * factorial(2))))       # 第 5 次调用 使用 2
6 * (5 * (4 * (3 * (2 * factorial(1))))) # 第 6 次调用 使用 1
6 * (5 * (4 * (3 * (2 * 1))))            # 第 6 次调用 返回
6 * (5 * (4 * (3 *2)))                   # 第 5 次调用 返回
6 * (5 * (4 * 6))                        # 第 4 次调用 返回
6 * (5 * 24)                             # 第 3 次调用 返回
6 * 120                                  # 第 2 次调用 返回
720                                      # 第 1 次调用 返回
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秃头少女Emily

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值