python函数

发布于:2024-06-11 ⋅ 阅读:(13) ⋅ 点赞:(0)


一、函数定义

Python中的函数是组织好的、可重复使用的代码段,用于实现单一或相关联的功能;在Python编程中,函数起着至关重要的作用,它们不仅能够提高应用的模块性,还能增加代码的重用率。

  • 定义结构:一个典型的Python函数以def关键字开始,后跟函数名和圆括号()。函数的参数(如果存在)需要在圆括号中列出,函数体由冒号(:)起始并相应缩进。可选的return语句用于结束函数,并返回值给调用者。

  • 参数传递:Python中的参数传递包括必需参数、关键字参数、默认参数、不定长参数等类型。其中,函数参数可以是不同类型的对象,如列表、字典等。对于不可变类型(如整数、字符串、元组),参数传递类似于值传递;而对于可变类型(如列表、字典),则类似于引用传递。

  • 文档字符串:为了增加函数的可读性和可维护性,可以在函数体的开始处添加文档字符串,即位于第一行函数说明的字符串,用于存放函数说明。

  • 返回值:函数可以通过return语句返回结果。如果不使用return或者return后面不接表达式,则相当于返回None。在某些情况下,函数可能不需要返回任何值。

  • 调用方式:定义好的函数可以通过其名称以及所需的参数来调用执行。函数可以在不同的上下文中被多次调用,每次调用时都可以按照需要传入不同的参数值。

  • 递归函数:Python支持函数递归,即函数可以调用自身。递归是一种强大的编程技术,但需要谨慎使用以避免造成无限循环或不必要的资源消耗。

示例题:
已知多边形各条边的长度,计算多边形的面积。
在这里插入图片描述
解析过程:
可通过计算1、2、3三个三角形的面积之和求得多边形的面积,又已知每个三角形的三边,因此使用三次海伦公式完成计算。

程序代码:

import math
a,b,c,d,e,f,g = 3,3,5,4,5,6,4
p1 = (a +b +c) / 2
s1 = math.sqrt(p1 * (p1 - a) * (p1 -b) * (p1 - c))
p2 = (c + d + e) / 2
s2 = math.sqrt(p2 * (p2 - c) * (p2 - d) * (p2 - e))
p3 = (e + f +g) / 2
s3 = math.sqrt(p3 * (p3 - e) * (p3 - f) * (p3 - g))
print(s1 + s2 + s3)

D:\pythonLED\python.exe E:/pythonProject/1.py
23.232499794348143

以上述代码可以看出,上面的代码确实可以实现例题要求的功能,但是也存在不足,计算三角形面积的代码被书写了三次,因此这三次计算中的量不是规律变化的,所以也不能使用循环机构来避免重复。

需要重复使用能完成某个特定功能的多条语句时,就可以考虑将这些语句做成用户自定义函数,每次就像使用python自带的函数那样直接调用,这就就可以避免重复书写代码。

1.1、函数的功能

  • 实现结构化程序设计,通过把程序分割为不同的功能模块,可以实现自顶向下的结构化程序设计。
  • 降低程序的复杂度,使用函数有利简化程序的结构,提高程序的可阅读性。
  • 实现代码的复用,函数可以一次定义多次调用。
  • 提高代码的质量,实现分割后,子任务的代码相对简单,易于开发、调试、修改和维护。
  • 协作开发,将大型项目分割成不同的子任务后,团队可以分工合作。

1.2、函数的定义

语法格式:

def 函数名(<参数列表>):
<函数体>
	return<返回值列表>

def是函数定义的关键字、表示函数的框架从这里开始。

函数的命名规则与变量的命名规则相同。

函数内用到的需要从函数外得到值的变量称为参数,其名称需要写到参数列表中,如果没有变量需要从函数外得到值。

函数体部分是实现特定功能的语句组。

return后面是执行完函数体后需要传送到函数外的计算结果,如果没有需要传送到函数外的计算结果,这部分可以省略;如果有需要传送到函数外的计算结果,这个就是函数的返回值,需要在函数中使用return语句;return语句有两个功能,一个结束函数,另一个就是将返回值传递到调用函数的地方;如果只出现return语句,则表示返回值为None。

def phw():
    print("hello world")

1.3、函数定义步骤

1.搭建框架:def 函数名():

def tri_area():

2.函数体:完成功能的语句。

p = (a + b + c) / 2
s = (p * (p - a) * (p - b) * (p - c)) ** 0.5

3.确定函数:需要从函数外得到值的变量。

(a,b,c)

4.确定返回值:需要传送到函数外的计算结果。

return s

二、函数调用

函数仅仅定义了换不能发挥作用,必须通过函数调用才能被执行,调用一个函数需要知道函数的名称和函数的参数。

语法格式:

函数名(<参数列表>)

2.1、两种调用方式

根据被调用函数是否有返回值,有两种函数调用方式。

有返回值函数的调用方式

  • 当调用的函数有返回值时,函数相当于表达式,需要放在赋值表达式中,print()函数中或其他可以使用表达式的地方。
def p_name(name):
    str1 = "Hello " + name
    return str1
print(p_name("小明"))

D:\pythonLED\python.exe E:/pythonProject/1.py
Hello 小明

无返回值函数的调用方式

def p_name(name):
    print('Hello',name)
p_name('小明')

D:\pythonLED\python.exe E:/pythonProject/1.py
Hello 小明

2.2、别名调用

函数名其实就是指向一个函数对象的引用,可以把函数名赋值给一个变量,这相当于给这个函数起了一个别名。

hd = {315,404,501,601,701,801,1001}
length_hd = len
num = length_hd(hd)
print('hd集合的元素个数为:',num)

D:\pythonLED\python.exe E:/pythonProject/1.py
hd集合的元素个数为: 7

2.3、参数传递

参数的含义

参数的名称不同,作用也不同,定义函数时括号里的参数叫形式参数,简称为形参,形参本身没有值,调用函数时括号里的参数叫实际参数,简称为实参。

参数传递的方向

参数传递只有一个方向,就是从实参传递到形参。

参数传递的方式

python程序中,根据实参的类型不同,函数参数的传递方式分为值传递和地址传递,当实参为不可变对象(包括常量、数值类型变量、字符串变量和元组变量)时,传递方式为值传递,当实参为可变对象(包括列表变量、字典变量等)时,传递方式为地址传递。

值传递

  • 值传递方式下,形参在函数的存储空间中单独开辟空间存储实参传递过来的值;这个时候,形参和实参各自使用自己的空间,互不影响;如果在函数中更改了形参的值,不会对实参产生影响。
def swap(a,b):  #值传递,形参是局部变量
    #下面代码实现变量a、b的值交换
    a,b = b,a
    print("swap()函数中,a的值是",a,';变量b的值是',b)
a = 5
b = 8
swap(a,b)
print("主程序中,变量a的值是",a,';变量b的值是',b)

D:\pythonLED\python.exe E:/pythonProject/1.py
swap()函数中,a的值是 8 ;变量b的值是 5
主程序中,变量a的值是 5 ;变量b的值是 8

地址传递

  • 地址传递方式下,实参将自己的空间地址传递给形参,让形参与自己共同一个空间,如果在函数中更改了形参的值,实参的值也就被修改了。
def swap(dw):  #地址传递,共用一个空间
    #下面代码实现dw的a、b两个元素的值交换
    dw['a'],dw['b'] = dw['b'],dw['a']
    print("swap()函数中,a的值是",dw['a'],';变量b的值是',dw['b'])
dw = {'a':5,'b':8}
swap(dw)
print("主程序中,变量a的值是",dw['a'],';变量b的值是',dw['b'])

D:\pythonLED\python.exe E:/pythonProject/1.py
swap()函数中,a的值是 8 ;变量b的值是 5
主程序中,变量a的值是 8 ;变量b的值是 5

参数类别

必备参数**

  • 函数定义中允许有多个形参,因此调用函数时括号里可能有多个实参;在普通情况下,实参和形参按位置顺序对应,一个实参对应一个形参,不能省略。
# 定义一个函数,输出宠物叫声
def bark(pet1,pet2):
    print(pet1+"汪汪叫",pet2+"喵喵叫")
#调用函数,并传入两个参数
bark('dog','cat')

D:\pythonLED\python.exe E:/pythonProject/1.py
dog汪汪叫 cat喵喵叫

关键参数

  • 在调用函数时将形参的名称和实参的值关联起来,实参按指定名称传递,这样的参数称为关键字参数;使用关键字参数允许调用函数时参数的顺序与定义时不一致,因为python解释器能够用参数名匹配参数值。
#定义一个函数,输出成武叫声
def bark(pet1,pet2):
    print(pet1 + "汪汪叫", pet2 + "喵喵叫")
#调用函数,并传入两个参数
bark(pet1='dog',pet2='cat')

D:\pythonLED\python.exe E:/pythonProject/1.py
dog汪汪叫 cat喵喵叫

带默认值参数

  • 定义函数的时候,可以给每个形参指定一个默认值,当调用函数时,如果没有传入实参,就使用形参的默认值;如果传入了实参,就使用传入的实参。
#定义一个函数,输出成武叫声
def bark(pet1,pet2='cat'):
    print(pet1 + "汪汪叫", pet2 + "喵喵叫")
#调用函数,并传入一个参数
bark('dog')

D:\pythonLED\python.exe E:/pythonProject/1.py
dog汪汪叫 cat喵喵叫

不定长参数

  • 如果函数需要处理的参数个数不确定,则可以使用不定长参数。
def test(a,b,c,*tup_args,**dict_args):
    print(a)
    print(b)
    print(c)
    print(tup_args)
    print(dict_args)
test(1,2,3,'a1','a2','a3',name='小明',age='18')

D:\pythonLED\python.exe E:/pythonProject/1.py
1
2
3
('a1', 'a2', 'a3')
{'name': '小明', 'age': '18'}

函数调用步骤

在以下代码中,通过三个步骤完成函数的调用

def tri_area(a,b,c):
    p = (a + b + c) / 2
    s = (p * (p - a) * (p - b) * (p - c)) ** 0.5
    return s

确定调用方式

  • 根据函数是否有返回值,确定函数的调用方式;当前函数有返回值,因此考虑将该函数调用放到赋值表达式中。
s1 = tri_area()
s2 = tri_area()
s3 = tri_area()

确定参数

s1 = tri_area(a,b,c)
s2 = tri_area(b,a,c)
s3 = tri_area(e,f,g)

确定参数传递方式(完整代码)

def tri_area(a,b,c):
    p = (a + b + c) / 2
    s = (p * (p - a) * (p - b) * (p - c)) ** 0.5
    return s
a,b,c,d,e,f,g = 3,3,5,4,5,6,4
s1 = tri_area(a,b,c)
s2 = tri_area(b,a,c)
s3 = tri_area(e,f,g)
print(s1 + s2 + s3)

D:\pythonLED\python.exe E:/pythonProject/1.py
18.213129392380715

三、变量的作用域

作用域就是变量的有效范围,决定变量可以在那个范围内被使用;变量的作用域由变量的定义位置决定,在不同位置定义的变量,其作用域是不一样的;从作用域的角度,变量分为局部变量和全局变量;定义在函数内部的变量称为局部变量,拥有在函数内的局部作用域;定义在函数外部的变量称为全局变量,拥有全局作用域。

3.1、局部变量

局部变量,就是在函数内部定义的变量,当函数被执行时,python会为其分配一块临时的存储空间,所有在函数内部定义的变量,都会存储在这块空间中;不同的函数,可以定义相同的名字的局部变量,相互之间不会影响。

def test01():
    a = 10
    print('test01修改前的a={}'.format(a))
    print('test01修改前{}的存储地址{}'.format(a,id(a)))
    a = 20
    print('test01修改前的a={}'.format(a))
    print('test01修改前{}的存储地址{}'.format(a, id(a)))
def test02():
    a = 40
    print('test02的a={}'.format(a))
    print('test02中{}的存储地址{}'.format(a, id(a)))
test01()
test02()

D:\pythonLED\python.exe E:/pythonProject/1.py
test01修改前的a=10
test01修改前10的存储地址140728528128728
test01修改前的a=20
test01修改前20的存储地址140728528129048
test02的a=40
test02中40的存储地址140728528129688

这段代码定义了两个函数:test01() 和 test02()。

在 test01() 函数中,首先定义了一个变量 a,并将其赋值为 10。然后使用 print() 函数输出变量 a 的值以及它的存储地址(通过 id() 函数获取)。接着将变量 a 的值修改为 20,并再次输出变量 a 的值以及它的存储地址。

在 test02() 函数中,定义了一个变量 a,并将其赋值为 40。然后使用 print() 函数输出变量 a 的值以及它的存储地址。

最后,依次调用这两个函数。

3.2、全局变量

全局变量是定义在函数外部的变量,拥有全局作用域。

a = 50
def test01():
    a = 10
    print('我是test01修改前的a={}'.format(a))
    print(id(a))
    a = 20
    print('我是test01修改前的a={}'.format(a))
    print(id(a))
def test02():
    a = 40
    print('我是test02的a={}'.format(a))
print( id(a))
test01()
test02()
print('我是全局变量a={}'.format(a))
print(id(a))

D:\pythonLED\python.exe E:/pythonProject/1.py
140728517447640
我是test01修改前的a=10
140728517446360
我是test01修改前的a=20
140728517446680
我是test02的a=40
我是全局变量a=50
140728517447640

这段代码定义了一个全局变量a,并赋值为50。然后定义了两个函数test01()和test02()。

在test01()函数中,首先定义了一个局部变量a,并将其赋值为10。然后使用print()函数输出该变量的值以及它的存储地址(通过id()函数获取)。接着将变量a的值修改为20,并再次输出变量a的值以及它的存储地址。

在test02()函数中,定义了一个局部变量a,并将其赋值为40。然后使用print()函数输出该变量的值以及它的存储地址。

最后,依次调用这两个函数,并在全局范围内输出全局变量a的值和存储地址。

3.3、关键字global

如果需要再函数内部修改全局变量,可以使用关键字global。

a = 50
print('初始全局变量a = {}'.format(a))
print('初始全局变量a的存储地址{}'.format(id(a)))
def test01():
    global a
    a = 100
    print('在test01内修改后的a={}'.format(a))
    print('函数内全局变量a的存储地址{}'.format(id(a)))
test01()
print('函数调用后的全局变量a={}'.format(a))
print('函数调用后全局变量a的存储地址{}'.format(id(a)))

D:\pythonLED\python.exe E:/pythonProject/1.py
初始全局变量a = 50
初始全局变量a的存储地址140728517447640
在test01内修改后的a=100
函数内全局变量a的存储地址140728517449240
函数调用后的全局变量a=100
函数调用后全局变量a的存储地址140728517449240

这段代码定义了一个全局变量a,并赋值为50。然后使用print()函数输出该变量的值和存储地址。

接着定义了一个名为test01的函数,在该函数内部使用了global关键字声明了a为全局变量,并将其值修改为100。然后使用print()函数输出该变量的值和存储地址。

最后在全局范围内调用test01函数,并再次输出全局变量a的值和存储地址。

需要注意的是,在函数内部修改全局变量时需要使用global关键字进行声明,否则会被认为是局部变量。

四、特殊函数

4.1、匿名函数

在定义函数的过程中没有给定名称的函数叫做匿名函数,python程序中使用lambda表达式来创建匿名函数。

lambda创建匿名函数的规则

  • lambda只是一个表达式,函数体比用def定义函数简单的多。
  • lambda的主体是一个表达式,而不是一个代码块,所以不能包含过于复杂的逻辑。
  • lambda表达式拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。
  • lambda定义的函数的返回值就是表达式的返回值,不需要return语句。
  • lambda表达式的主要应用场景是赋值给变量、将其他函数作为参数传入。

lambda表达式适用于定义简单的、能够在一行内表示的函数,返回一个函数类型。

f = lambda x,y:x+y
print(type(f))
print(f(2,3))

D:\pythonLED\python.exe E:/pythonProject/1.py
<class 'function'>
5

4.2、嵌套函数

嵌套函数指的是程序调用函数1时,在函数1中又在调用函数2,这个时候就形成了嵌套函数。

在这里插入图片描述

def fact(x):
    p = 1
    for i in range(1,x+1):
        p = p * i
    return p
def comb(n,m):
    c = fact(n) / (fact(m) * fact(n - m))
    return c
n = eval(input('请输入组合问题的n值:'))
m = eval(input('请输入组合问题的m值:'))
print(comb(n,m))

D:\pythonLED\python.exe E:/pythonProject/1.py
请输入组合问题的n值:5
请输入组合问题的m值:6
0.16666666666666666

4.3、递归函数

递归就是子程序(或函数)直接调用自己或通过一系列调用语句间接调用自己,是一种描述问题和解决问题的基本方法。

def factorial(n):
    if n == 0:
        return 1
    else:
        return n * factorial(n-1)

num = int(input("请输入一个整数: "))
result = factorial(num)
print(f"{num}的阶乘是: {result}")

D:\pythonLED\python.exe E:/pythonProject/1.py
请输入一个整数: 15
15的阶乘是: 1307674368000