目录
五、组合数据类型
前情知识:不可变数据类型和可变数据类型
数据类型分为不可变数据类型和可变数据类型
不可变数据类型vs可变数据类型
以下所有的内容都是基于内存地址来说的。
- 不可变数据类型: 当该数据类型的对应变量的值发生了改变,那么它对应的内存地址也会发生改变,对于这种数据类型,就称不可变数据类型。
可变数据类型:当该数据类型的对应变量的值发生了改变,那么它对应的内存地址不发生改变,对于这种数据类型,就称可变数据类型。
总结:不可变数据类型更改后地址发生改变,可变数据类型更改地址不发生改变
前面讲到Python的数据类型有整型,字符串,元组,集合,列表,字典。其中:
整型、字符串、元组是不可变数据类型
列表、集合、字典是可变数据类型
需要特别说明的是字典中的键Key值只能是不可变数据类型,不能是可变数据类型
1.认识组合数据类型
Python 中的序列类型包括字符串、列表(list)、元组(tuple)、字典(dict)和集合(set)。
列表(list)和元组(tuple)比较相似,它们都按顺序保存元素,元素是有序的,所有的元素占用一块连续的内存,每个元素都有自己的索引,因此列表和元组的元素都可以通过索引(index)来访问。它们的区别在于:列表是可以修改的,而元组是不可修改的。即列表是可变数据类型,元组是不可变数据类型。
字典(dict)和集合(set)存储的数据都是无序的,每份元素占用不同的内存,其中字典元素以 key-value键值对 的形式保存。
序列支持以下几种通用的操作:序列索引、序列切片、序列相加、序列相乘、检查元素是否包含在序列中。但比较特殊的是,集合和字典不支持索引、切片、相加和相乘操作。
(1)序列索引
Python中的序列支持双向索引:正向递增索引和反向递减索引。正向递增索引从左向右依次递增,第一个元素的索引为0,第二个元素的索引为1,以此类推;反向递减索引从右向左依次递减,从右数第一个元素的索引为-1,第二个元素的索引为-2,以此类推。
(2)序列切片
格式:sname[start : end : step]
sname:表示序列的名称;
start:表示切片的开始索引位置(包括该位置),此参数也可以不指定,会默认为 0;
end:表示切片的结束索引位置(不包括该位置),如果不指定,则默认为序列的长度;
step:表示在切片过程中,隔几个存储位置(包含当前位置)取一次元素,也就是说,如果 step 的值大于 1,则在进行切片去序列元素时,会“跳跃式”的取元素。如果省略设置 step 的值,则最后一个冒号就可以省略。
(3)序列相加
Python 中,支持两种类型相同的序列使用“+”运算符做相加操作,它会将两个序列进行连接,但不会去除重复的元素。这里所说的“类型相同”,指的是“+”运算符的两侧序列要么都是列表类型,要么都是元组类型,要么都是字符串。
(4)序列相乘
Python 中,使用数字 n 乘以一个序列会生成新的序列,其内容为原来序列被重复 n 次的结果。
(5)检查元素是否包含在序列中
使用 in 关键字检查某元素是否为序列的成员,格式:value in sequence
value: 表示要检查的元素;
sequence: 表示指定的序列。
另外还有一个not in与in相反
(6)集合
Python集合具备确定性、互异性和无序性三个特性。Python要求放入集合中的元素必须是不可变类型,Python中的整型、浮点型、字符串类型和元组属于不可变类型,列表、字典及集合本身都属于可变的数据类型。
(7)字典
映射类型以键值对的形式存储元素,键值对中的键与值之间存在映射关系。字典(dict)是Python唯一的内置映射类型,字典的键必须遵守以下两个原则:
2.列表
(1)介绍
从形式上看,列表会将所有元素都放在一对中括号[ ]里面,相邻元素之间用逗号 , 分隔,如下所示:
[element1, element2, element3, ..., elementn]
格式中,element1 ~ elementn 表示列表中的元素,个数没有限制,只要是 Python 支持的数据类型就可以。
从内容上看,列表可以存储整数、小数、字符串、列表、元组等任何类型的数据,并且同一个列表中元素的类型也可以不同。
注意,在使用列表时,虽然可以将不同类型的数据放入到同一个列表中,但通常情况下不这么做,同一列表中只放入同一类型的数据,这样可以提高程序的可读性。
(2)创建列表
可以直接使用中括号“[]”创建,也可以使用内置的list()函数快速创建。
list_one = [] # 使用[]创建空列表
li_two = list() # 使用list()创建空列表
①中括号“[]”创建
num = [1, 2, 3, 4, 5, 6, 7]
program = ["C语言", "Python", "Java"]
②使用list函数创建
Python 还提供了一个内置的函数 list(),使用它可以将其它数据类型转换为列表类型。
#将字符串转换成列表
list1 = list("hello")
print(list1)
#将元组转换成列表
tuple1 = ('Python', 'Java', 'C++', 'JavaScript')
list2 = list(tuple1)
print(list2)
#将字典转换成列表,(键值作为列表的内容)
dict1 = {'a':100, 'b':42, 'c':9}
list3 = list(dict1)
print(list3)
#将区间转换成列表
range1 = range(1, 6)
list4 = list(range1)
print(list4)
③列表推导式创建列表
[表达式 for 变量 in 列表]
print([i**2 for i in range(1,11)])
print([0 for i in range(1, 11)])
print([x*y for x in [1,2,3] for y in [1,2,3]])-->这里的两个for不是并列关系,是嵌套关系
[表达式 for 变量 in 列表 if 条件]
[i for i in range(1,101) if i % 2 == 0]
[(x, y) for x in range(10) if x % 2 if x > 3 for y in range(10) if y > 7 if y != 8 ]
[表达式1 if 条件 else 表达式2 for变量 in 列表]
[i if i%2==0 else 'py' for i in range(10)]
[i for i in range(10) if i%2==0 else ‘py’] 错误
(3)访问列表元素
列表中的元素可以通过索引或切片这两种方式进行访问,也可以在循环中依次访问。
list_one = ["Java", "C#", "Python", "PHP"]
#索引
print(list_one[1])
#切片
print(list_one[-3:-1])
#循环
for li in list_one:
print(li, end=' ')
(4)添加列表元素
向列表中添加元素是非常常见的一种列表操作,Python提供了append()、extend()和insert()这几个方法。
append()方法,
将数据添加到末尾
格式:listname.append(obj)
listname 表示要添加元素的列表;
obj 表示到添加到列表末尾的数据,它可以是单个元素,也可以是列表、元组等。
当给append() 方法传递列表或者元组时,此方法会将它们视为一个整体,作为一个元素添加到列表中,从而形成包含列表和元组的新列表
extend()方法,
添加到列表末尾的数据,它可以是单个元素,也可以是列表、元组等,但不能是单个的数字。extend() 和 append() 的不同之处在于:extend() 不会把字符串、列表或者元组视为一个整体,而是把它们包含的元素逐个添加到列表中; append末尾添加的数据可以是单个的数据
格式:listname.extend(obj)
insert()方法,
append() 和 extend() 方法只能在列表末尾插入元素,如果希望在列表中间某个位置插入元素,那么可以使用 insert() 方法。
格式:listname.insert(index , obj)
index 表示指定位置的索引值,insert() 会将 obj 插入到 listname 列表第 index 个元素的位置。
当插入列表或者元组时,insert() 也会将它们视为一个整体,作为一个元素插入到列表中,这一点和 append() 是一样的。
(5)元素排序
列表的排序是将元素按照某种规定进行排列。列表中常用的排序方法有sort()、reverse()、sorted()。
li_one = [6, 2, 5, 3]
#有序的元素会覆盖原来的列表元素,不产生新列表
list_one.sort()
#产生排序后的新列表,排序操作不会对原列表产生影响
li_two = sorted(li_one)
#逆置列表,即把原列表中的元素从右至左依次排列存放
li_one.reverse()
sort(key,reverse),key是排序规则,reverse反转默认是reverse=False,即升序排序
(6)删除列表元素
删除列表元素的常用方式有del语句、remove()方法、pop()方法和clear()方法。pop()和del根据索引值删除元素(pop还会返回被删除的数据,del还可以删除整个列表)。remove():根据元素值进行删除
li_one = [6, 2, 5, 3, 3]
#移除列表中的某个元素,括号中填索引值,若未指定具体元素,则移除列表中的最后一个元素,
pop_ele = li_one.pop()
#移除列表中匹配到的第一个元素,根据元素值进行删除
li_one.remove(3)
#清空列表
li_one.clear()
#删除列表中指定位置的元素,可以是单个元素,也可以是一段连续元素
del li_one[0]
#删除整个列表
del li_one
注意clear()清空列表后,列表还存在,其变为空列表,而del删除列表,列表已不存在
(7)修改列表元素
修改单个元素
直接对元素赋值即可
nums = [40, 36, 89, 2, 36, 100, 7]
nums[2] = -26 #使用正数索引
nums[-3] = -66.2 #使用负数索引
print(nums)
[40, 36, -26, 2, -66.2, 100, 7]
修改一组元素
通过切片给一组元素赋值
nums = [40, 36, 89, 2, 36, 100, 7]
#修改索引1~3元素的值
nums[1: 4] = [45.25, -77, -52.5]
print(nums)
[40, 45.25, -77, -52.5, 36, 100, 7]
如果对空切片(slice)赋值,就相当于插入一组新的元素:
nums = [40, 36, 89, 2, 36, 100, 7]
#在4个位置插入元素
nums[4: 4] = [-77, -52.5, 999]
print(nums)
[40, 36, 89, 2, -77, -52.5, 999, 36, 100, 7]
(8)查找列表元素
Python 列表(list)提供了 index() 和 count() 方法,它们都可以用来查找元素。
count() 方法用来统计某个元素在列表中出现的次数,
格式:listname.count(obj)
listname 代表列表名,obj 表示要统计的元素。
如果 count() 返回 0,就表示列表中不存在该元素,所以 count() 也可以用来判断列表中的某个元素是否存在。
index() 方法用来查找某个元素在列表中出现的位置(也就是索引),如果该元素不存在,则会导致 ValueError 错误,所以在查找之前最好使用 count() 方法判断一下。
格式:listname.index(obj, start, end)
listname 表示列表名称,obj 表示要查找的元素,start 表示起始位置,end 表示结束位置。
start 和 end 参数用来指定检索范围.
index() 方法会返回元素所在列表中的索引值。
(9)二维列表
二维列表的操作使用二重嵌套循环实现
3.元组
(1)介绍
元组的表现形式为一组包含在圆括号“()”中、由逗号分隔的元素,元组中元素的个数、类型不受限制。除了使用()构建元组外,还可以使用内置函数tuple()构建元组。
(element1, element2, ... , elementn)
其中 element1~elementn 表示元组中的各个元素,个数没有限制,只要是 Python 支持的数据类型就可以。
从存储内容上看,元组可以存储整数、实数、字符串、列表、元组等任何类型的数据,并且在同一个元组中,元素的类型可以不同,例如:(“www", 1, [2,'a'], ("abc",3.0))
在这个元组中,有多种类型的数据,包括整形、字符串、列表、元组。
(2)创建元组
创建元组与创建列表类似,在此不做赘述
需要注意的是:当使用圆括号“()”创建元组时,如果元组中只包含一个元素,那么需要在该元素的后面添加逗号,从而保证Python解释器能够识别其为元组类型。
还要注意的是,元组推导式生成的是一个生成器对象,还要用tuple转为元组形式
t1 = ('python')
t2 = ('python',)
print(type(t1))
print(type(t2))
结果为:
<class 'str'>
<class 'tuple'>
(3)访问元组元素
与列表相似
(4)元组与列表的不同
元组和列表(list)的不同之处在于:
通常情况下,元组用于保存无需修改的内容。
(5)修改元组
前面我们已经说过,元组是不可变序列,元组中的元素不能被修改,所以我们只能创建一个新的元组去替代旧的元组。例如,对元组变量进行重新赋值:
tup = (100, 0.5, -36, 73)
print(tup)
#对元组进行重新赋值
tup = ('Shell脚本’,”www")
print(tup)
运行结果为:
(100, 0.5, -36, 73)
('Shell脚本', ‘www')
另外,还可以通过连接多个元组(使用+可以拼接元组)的方式向元组中添加新元素,例如:
tup1 = (100, 0.5, -36, 73)
tup2 = (3+12j, -54.6, 99)
print(tup1+tup2)
print(tup1)
print(tup2)
运行结果为:
(100, 0.5, -36, 73, (3+12j), -54.6, 99)
(100, 0.5, -36, 73)
((3+12j), -54.6, 99)
使用+拼接元组以后,tup1 和 tup2 的内容不发生改变,这说明生成的是一个新的元组。
(6)删除元组
Python删除元组,Python 自带垃圾回收功能,会自动销毁不用的元组,所以一般不需要通过来手动删除。如果想手动删除,可以通过 del 关键字将其删除
4.集合
(1)介绍
Python 中的集合,和数学中的集合概念一样,用来保存不重复的元素,即集合中的元素都是唯一的,互不相同。从形式上看,Python 集合会将所有元素放在一对大括号 {} 中,相邻元素之间用“,”分隔,如下所示:
{element1,element2,...,elementn},
其中,elementn 表示集合中的元素,个数没有限制。
大括号“{}”或内置函数set()均可构建集合。
s1 = {1} # 使用{}构建集合
s2 = set([1,2]) # 使用set构建集合
(2)创建集合
set() 函数为 Python 的内置函数,其功能是将字符串、列表、元组、range 对象等可迭代对象转换成集合。该函数的语法格式如下:
setname = set(iteration)
其中,iteration 就表示字符串、列表、元组、range 对象等数据
需要注意,使用{}不能创建空集合(不包含元素的{}创建的是字典变量),空集合只能利用set()函数创建。
另外需要注意,Python的集合(set)本身是可变类型,但同一集合中,只能存储不可变的数据类型,包括整形、浮点型、字符串、元组,无法存储列表、字典、集合这些可变的数据类型,否则 Python 解释器会抛出 TypeError 错误。
还要注意,需要注意的是,数据必须保证是唯一的,因为集合对于每种数据元素,只会保留一份。
集合也可以利用推导式创建,集合推导式的格式与列表推导式相似,区别在于集合推导式外侧为大括号“{}”
(3)访问集合元素
由于集合中的元素是无序的,因此无法向列表那样使用下标访问元素。Python 中,访问集合元素最常用的方法是使用循环结构,将集合中的数据逐一读取出来。
a = {1,'c',1,(1,2,3),'c'}
for ele in a:
print(ele,end=' ')
运行结果为:
1 c (1, 2, 3)
(4)删除集合
可以使用 del() 语句删除集合
(5)集合的运算
(5)集合的操作
集合是可变的,集合中的元素可以动态增加或删除。Python提供了一些内置方法来操作集合
(6)特殊集合
set 集合是可变序列,程序可以改变序列中的元素;frozenset 集合是不可变序列,程序不能改变序列中的元素。set 集合中所有能改变集合本身的方法,比如 remove()、discard()、add() 等,frozenset 都不支持;set 集合中不改变集合本身的方法,fronzenset 都支持。
两种情况下可以使用 fronzenset:
5.字典
(1)介绍
字典(dict)是一种无序的、可变的序列,它的元素以“键值对(key-value)”的形式存储。相对地,列表(list)和元组(tuple)都是有序的序列,它们的元素在底层是挨着存放的。
字典类型是 Python 中唯一的映射类型。“映射”是数学中的术语,简单理解,它指的是元素之间相互对应的关系,即通过一个元素,可以唯一找到另一个元素。
(2)创建字典
①使用 { } 创建字典
由于字典中每个元素都包含两部分,分别是键(key)和值(value),因此在创建字典时,键和值之间使用冒号:分隔,相邻元素之间使用逗号分隔,所有元素放在大括号{ }中。语法格式如下:
dictname = {'key':'value1', 'key2':'value2', ..., 'keyn':valuen}
其中 dictname 表示字典变量名,keyn : valuen 表示各个元素的键值对。需要注意的是,同一字典中的各个键必须唯一,不能重复。
需要注意,字典元素无序,键值必须唯一
字典的值可以是 Python 支持的任意数据类型。
②通过 fromkeys() 方法创建字典
dictname = dict.fromkeys(list,value)
其中,list 参数表示字典中所有键的列表(list);value 参数,如果不写则为空值 None。
knowledge = ['语文', '数学', '英语']
scores = dict.fromkeys(knowledge, 60)
print(scores)
运行结果为:
{'语文': 60, '英语': 60, '数学': 60}
可以看到,knowledge 列表中的元素全部作为了 scores 字典的键,而各个键对应的值都是 60。这种创建方式通常用于初始化字典,设置 value 的默认值。
③通过 dict() 映射函数创建字典
(3)删除字典
和删除列表、元组一样,手动删除字典也可以使用 del 关键字,Python 自带垃圾回收功能,会自动销毁不用的字典,所以一般不需要通过 del 来手动删除。
(4)访问字典
字典的值可通过“键”或内置方法get()访问。
d2 = {'A': '123', 'B': '135'}
#键
d2['A']---->'123'
#get()
d2,get('B')---->'135'
get() 方法的语法格式为:dictname.get(key[,default])
dictname 表示字典变量的名字;key 表示指定的键;default 用于指定要查询的键不存在时,此方法返回的默认值,如果不手动指定,会返回 None。
字典涉及的数据分为键、值和元素(键值对),除了直接利用键访问值外,Python还提供了内置方法keys()、values()和items()。
info = {'name': 'Jack','age':23,'height':185}
#获取所有键
info.keys()
->dict_keys(['name', 'age', 'height'])
#获取所有值
info.values()
->dict_values(['Jack', 23, 185])
#获取所有元素
info.items()
->dict_items([('name', 'Jack'), ('age', 23), ('height', 185)])
可以发现,keys()、values() 和 items() 返回值的类型分别为 dict_keys、dict_values 和 dict_items。
(5)添加字典元素
①字典是由一个一个的 key-value 构成的,key 是找到数据的关键,Python 对字典的操作都是通过 key 来完成的。为字典添加新的键值对很简单,直接给不存在的 key 赋值即可,具体语法格式如下:
dictname[key] = value
其中:
setdefault() 方法
dictname.setdefault(key, defaultvalue)
其中dictname 表示字典名称,key 表示键,defaultvalue 表示默认值(可以不写,不写的话是 None)。
a = {'数学': 95, '语文': 89, '英语': 90}
print(a) # {'数学': 95, '语文': 89, '英语': 90}
#key不存在,指定默认值
a.setdefault('物理', 94)
print(a) # {'数学': 95, '语文': 89, '英语': 90, '物理': 94}
#key不存在,不指定默认值
a.setdefault('化学')
print(a)# {'数学': 95, '语文': 89, '英语': 90, '物理': 94, '化学': None}
#key存在,指定默认值
a.setdefault('数学', 100)
print(a)# {'数学': 95, '语文': 89, '英语': 90, '物理': 94, '化学': None}
如果key存在,该方法不会改变key对应的值
(6)修改字典元素
Python 字典中键(key)的名字不能被修改,我们只能修改值(value)。
字典中各元素的键必须是唯一的,因此,如果新添加元素的键与已存在元素的键相同,那么键所对应的值就会被新的值替换掉,以此达到修改元素值的目的。
update()方法实现元素的添加和修改。在执行 update() 方法时,如果被更新的字典中已包含对应的键值对,那么原 value 会被覆盖;如果被更新的字典中不包含对应的键值对,则该键值对被添加进去。
a = {'one': 1, 'two': 2, 'three': 3}
a.update({‘one’:4.5, ‘four’: 9.3}) 或者
a.update(one=4.5, four=9.3)
print(a)
运行结果为:
{'one': 4.5, 'two': 2, 'three': 3, 'four': 9.3}
(7)判断是否存在指定键值对
如果要判断字典中是否存在指定键值对,首先应判断字典中是否有对应的键。判断字典是否包含指定键值对的键,可以使用 in 或 not in 运算符。需要指出的是,对于 dict 而言,in 或 not in 运算符都是基于 key 来判断的。
a = {'数学': 95, '语文': 89, '英语': 90}
# 判断 a 中是否包含名为'数学'的key
print('数学' in a) # True
# 判断 a 是否包含名为'物理'的key
print('物理' in a) # False
(8)删除字典的元素
Python支持通过del、pop()、popitem()和clear()方法删除字典中的元素。
# 使用del语句删除键值对
a = {'数学': 95, '语文': 89, '英语': 90}
del a['语文']
del a['数学']
print(a)
运行结果为:
{'英语': 90}
del a
a = {'数学': 95, '语文': 89, '英语': 90, '化学': 83, '生物': 98, '物理': 89}
print(a) # {'数学': 95, '语文': 89, '英语': 90, '化学': 83, '生物': 98, '物理': 89}
a.pop('化学')
print(a) # {'数学': 95, '语文': 89, '英语': 90, '生物': 98, '物理': 89}
a.popitem()
print(a) #{'数学': 95, '语文': 89, '英语': 90, '生物': 98}
a.clear()
print(a) #{}
(9)字典推导式
字典推导式外侧为大括号“{}”,且内部需包含键和值两部分,具体格式如下:
基本格式:{ key_expr: value_expr for key, value in collection if condition }
用字符串和其索引创建字典
strings = ['import','is','with','if','file','exception’]
D = {key: val for val,key in enumerate(strings)}
# {'import': 0, 'is': 1, 'with': 2, 'if': 3, 'file': 4, 'exception': 5}
# 获取字典中key值是小写字母的键值对
dict1 = {"a":10,"B":20,"C":True,"D":"hello world","e":"python教程"}
dict2 = {key:value for key,value in dict1.items() if key.islower()}
print(dict2)
# 将字典中的所有key设置为小写
dict3 = {key.lower():value for key,value in dict1.items() }
print(dict3)
利用字典推导式可快速交换字典中的键和值,示例如下:
old_dict = {'name': 'Jack','age':23,'height':185}
new_dict = {value:key for key,value in old_dict.items()}
print(new_dict)
#{'Jack': 'name', 23: 'age', 185: 'height'}
六、函数
1.函数概述
函数是组织好的、实现单一功能或相关联功能的代码段。我们可以将函数视为一段有名字的代码,这类代码可以在需要的地方以“函数名()”的形式调用。
函数式编程具有以下优点:
2.函数的定义及调用
开发人员也可以根据自己的需求定义函数,Python中使用关键字def来定义函数,其语法格式如下:
函数内部也可以调用其他函数,这被称为函数的嵌套调用。
多学一招:函数的嵌套定义
函数在定义时可以在其内部嵌套定义另外一个函数,此时嵌套的函数称为外层函数,被嵌套的函数称为内层函数。
注意:
3.函数参数的传递
我们通常将定义函数时设置的参数称为形式参数(简称为形参),将调用函数时传入的参数称为实际参数(简称为实参)。函数的参数传递是指将实际参数传递给形式参数的过程。
Python 中,根据实际参数的类型不同,函数参数的传递方式可分为 2 种,分别为值传递和引用(地址)传递:
值传递:适用于实参类型为不可变类型(字符串、数字、元组);
引用(地址)传递:适用于实参类型为可变类型(列表,字典);
在执行值传递时,改变形式参数的值,实际参数并不会发生改变;而在进行引用传递时,改变形式参数的值,实际参数也会发生同样的改变。
函数参数的传递可以分为位置参数传递、关键字参数传递、默认参数传递、参数的打包与解包以及混合传递。
(1)位置参数的传递
函数在被调用时会将实参按照相应的位置依次传递给形参,也就是说将第一个实参传递给第一个形参,将第二个实参传递给第二个形参,以此类推。
调用函数时传入实际参数的数量和位置都必须和定义函数时保持一致。实际参数类型和形式参数类型要一致,或者在函数中,这两种类型之间能正常转换。
(2)关键字参数的传递
关键字参数的传递是通过“形参=实参”的格式将实参与形参相关联,将实参按照相应的关键字传递给形参。
通过此方式指定函数实参时,不再需要与形参的位置完全一致,只要将参数名写正确即可。数量要一致
注意:Python在3.8版本中新增了仅限位置形参的语法,使用符号“/”来限定部分形参只接收采用位置传递方式的实参。斜杠前的参数严格遵守仅位置参数的传递
(3)默认参数的传递
函数在定义时可以指定形参的默认值,如此在被调用时可以选择是否给带有默认值的形参传值,若没有给带有默认值的形参传值,则直接使用该形参的默认值。
def 函数名(...,形参名,形参名=默认值):
代码块
注意,在使用此格式定义函数时,指定有默认值的形式参数必须在所有没默认值参数的最后,否则会产生语法错误。
对于自己自定义的函数,可以轻易知道哪个参数有默认值,但如果使用 Python 提供的内置函数,又或者其它第三方提供的函数,怎么知道哪些参数有默认值呢?
Pyhton 中,可以使用“函数名.__defaults__”查看函数的默认值参数的当前值,其返回值是一个元组。
(4)参数的打包与解包
如果函数在定义时无法确定需要接收多少个数据,那么可以在定义函数时为形参添加“*”或“**”:
①*打包
②**打包
③解包
(5)混合传递
4.函数的返回值
函数中的return语句会在函数结束时将数据返回给程序,同时让程序回到函数被调用的位置继续执行。
如果函数使用return语句返回了多个值,那么这些值将被保存到元组中。
有关None的知识:
None(N 必须大写)特殊的常量 。和 False 不同,它不表示 0,也不表示空字符串,而表示没有值,也就是空值。这里的空值并不代表空对象,即 None 和 []、“” 不同:
>>> None is []
False
>>> None is ""
False
>>> type(None)
<class 'NoneType'>
除此之外,None 常用于 assert、判断以及函数无返回值的情况。举个例子,print() 函数输出数据,其实该函数的返回值就是 None。
>>> spam = print('Hello!')
Hello!
>>> None == spam
True
一般对于无返回值的函数定义,Python 都会在末尾加上 return None,使用不带值的 return 语句(也就是只有 return 关键字本身)
5.变量作用域
变量并非在程序的任意位置都可以被访问,其访问权限取决于变量定义的位置,其所处的有效范围称为变量的作用域。
根据作用域的不同,变量可以划分为局部变量和全局变量。
(1)局部变量
函数内部定义的变量,只能在函数内部被使用
函数执行结束之后局部变量会被释放,此时无法再进行访问。
不同函数内部可以包含同名的局部变量,这些局部变量的关系类似于不同目录下同名文件的关系,它们相互独立,互不影响
(2)全局变量
全局变量可以在整个程序的范围内起作用,它不会受到函数范围的影响。
全局变量在函数内部只能被访问,而无法直接修改。
这是因为函数内部的变量number视为局部变量,而在执行“number+=1”这行代码之前并未声明过局部变量number。
因此,函数内部只能访问全局变量,而无法直接修改全局变量。
多学一招:获取指定作用域范围中的变量
多学一招:LEGB原则
(3)global和nonlocal关键字
函数内部无法直接修改全局变量或在嵌套函数的外层函数声明的变量,但可以使用global或nonlocal关键字修饰变量以间接修改以上变量。
global就是告诉函数引用的变量是全局变量而不是局部变量,因为函数默认作为局部变量处理,所以会发生没找到的错误
与global相似修改
(4)局部函数
Python 函数内部可以定义变量,这样就产生了局部变量,那Python 函数内部能定义函数吗?答案是肯定的。Python 支持在函数内部定义函数,此类函数又称为局部函数。
和局部变量一样,默认情况下局部函数只能在其所在函数的作用域内使用。
就如同全局函数返回其局部变量,就可以扩大该变量的作用域一样,通过将局部函数作为所在函数的返回值,也可以扩大局部函数的使用范围。
(5)闭包函数
闭包,又称闭包函数或者闭合函数,和前面讲的嵌套函数类似,不同之处在于,闭包中外部函数返回的不是一个具体的值,而是一个函数。一般情况下,返回的函数会赋值给一个变量,这个变量可以在后面被继续执行调用。
6.递归函数
函数在定义时可以直接或间接地调用其他函数。若函数内部调用了自身,则这个函数被称为递归函数。
递归函数在定义时需要满足两个基本条件:一个是递归公式,另一个是边界条件。其中:
递归公式是求解原问题或相似的子问题的结构;
边界条件是最小化的子问题,也是递归终止的条件。
递归函数的执行可以分为以下两个阶段:
1.递推:递归本次的执行都基于上一次的运算结果。
2.回溯:遇到终止条件时,则沿着递推往回一级一级地把值返回来。
经典应用
7.匿名函数
匿名函数是一类无需定义标识符的函数,它与普通函数一样可以在程序的任何位置使用。Python中使用lambda关键字定义匿名函数,它的语法格式如下:
[name]=lambda [形式参数列表] :表达式
匿名函数与普通函数的主要区别如下:
普通函数在定义时有名称,而匿名函数没有名称;
普通函数的函数体中包含有多条语句,而匿名函数的函数体只能是一个表达式;
普通函数可以实现比较复杂的功能,而匿名函数可实现的功能比较简单;
普通函数能被其他程序使用,而匿名函数不能被其他程序使用。
定义好的匿名函数不能直接使用,最好使用一个变量保存它,以便后期可以随时使用这个函数。
8.高阶函数
一般地,一个函数可以接收另一个函数作为参数,那么这个函数就是“高阶函数”。