文章目录
一、函数定义
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