* 容器类型之 集合(set)
* 容器类型的公共操作
* 公共的运算符
* 公共的函数
* 推导式**(非常重要)**
* 函数详解
* 格式介绍
* 几种写法
* 无参无返回的函数
* 有参无返回的函数
* 无参有返回的函数
* 有参有返回的函数
* 函数的调用图解
* 匿名函数
---
1.扩展-sort函数的key参数
# 案例: 演示下 sort()函数的用法.
# 需求1: 数值列表, 元素排序.
# 1. 定义列表.
list1 = [11, 33, 22, 55]
# 2. 对列表元素值进行排序.
list1.sort() # 升序
list1.sort(reverse=False) # 升序
list1.sort(reverse=True) # 降序
# 3. 打印列表元素内容.
print(f'list1: {list1}')
print("-" * 28)
# 需求2: 字符串列表, 元素排序.
list2 = ['bc', 'abc', 'xyz1', 'h']
# 对list2列表的元素排序.
# list2.sort() # 默认按照 字典顺序排列, 即: ['abc', 'bc', 'h', 'xyz1']
# 要求: 按照 字母(单词) 的长度进行排序.
list2.sort(key=len) # 会先用len()函数计算每个字符串的长度, 然后按照结果(长度)排序
list2.sort(key=len, reverse=True) # 会先用len()函数计算每个字符串的长度, 然后按照结果(长度)排序
print(f'list2: {list2}')
print("-" * 28)
# 需求3: 对 列表嵌套元组, 内容排序.
list3 = [(1, 3), (2, 2), (5, 1), (3, 9)]
# 该函数接收1个元组, 然后返回该元组的 第2个元素(即: 索引为1的元素)
def get_data(t1):
return t1[1]
# 要求: 按照 元素的第2个元素值 进行排序.
list3.sort(key=get_data) # key参数接收的是1个函数, 该函数会做用到列表中的每个元素.
list3.sort(key=get_data, reverse=True) # key参数接收的是1个函数, 该函数会做用到列表中的每个元素.
print(f'list3: {list3}')
2.set集合入门
"""
set集合介绍:
概述:
它属于容器类型的一种, 其元素特点为: 无序, 唯一.
无序解释:
这里的无序, 并不是排序的意思, 而是: 元素的存, 取顺序不一致, 例如: 存的时候顺序是1, 2, 3, 取的时候顺序是2, 1, 3
应用场景:
去重.
set集合定义格式:
set1 = {值1, 值2, 值3...}
set2 = set()
"""
# 1. 定义集合.
set1 = {10, 2, 'c', 5, 'a', 6, 3, 'b', 10, 5, 'a'}
set2 = set()
set3 = {} # 这个不是在定义集合, 而是在定义: 字典.
# 2. 打印变量的数据类型
print(type(set1)) # <class 'set'>
print(type(set2)) # <class 'set'>
print(type(set3)) # <class 'dict'>
# 3. 打印元素内容.
print(f'set1: {set1}') # set1: {2, 3, 5, 6, 'a', 10, 'c', 'b'}
print(f'set2: {set2}') # set2: set()
print(f'set3: {set3}') # set3: {}
print('-' * 28)
# 需求: 对列表元素值进行去重.
list1 = [10, 20, 30, 20, 10, 30, 50]
# 去重
# 思路1: 定义新列表, 遍历原始列表获取每个元素, 然后判断是否在新列表中, 不存在就添加.
# 代码略, 自己写一下.
# 思路2: list -> set, 会自动去重 -> list
set_tmp = set(list1)
list1 = list(set_tmp)
# 打印去重后的结果.
print(f'list1: {list1}')
3.容器类型-公共的运算符
"""
容器类型的公共运算符解释:
概述:
至此, 5种容器类型我们已经初步了解了, 例如: 字符串str, 列表list, 元组tuple, 字典dict, 集合set.
那么我们接触过的 运算符 或者 函数 有没有哪些是可以作用到它们所有容器类型呢? 我们简单总结一下.
公共的运算符:
+ 表示: 合并(拼接), 可以作用于: 字符串, 列表, 元组
* 表示: 复制, 可以作用于: 字符串, 列表, 元组
in 表示: 是否在, 可以作用于: 字符串, 列表, 元组, 字典, 集合
not in 表示: 是否不在, 可以作用于: 字符串, 列表, 元组, 字典, 集合
"""
# 演示 + 表示: 合并(拼接), 可以作用于: 字符串, 列表, 元组
print('aa' + 'bb')
print([1, 2, 3] + [4, 5, 6] + ['a', 'b'])
print((1, 2, 3) + ('a', 'b'))
# print({1, 2, 3} + {'a', 'b'}) # +不支持集合, 因为集合元素具有 唯一性. 合并可能存在重复元素, 然后会自动删除重复的, 无意义.
# print({'name': '张三', 'age': 23} + {'name': '李四', 'address':'北京'}) # +不支持字典, 键具有唯一性.
# 演示 * 表示: 复制, 可以作用于: 字符串, 列表, 元组
print('-' * 28)
print([1, 2, 3] * 2)
print((1, 2, 3) * 2)
# print({1, 2, 3} * 2) # *不能作用于集合, 集合元素具有唯一性.
# print({'name': '张三', 'age': 23} * 2) # *不能作用于字典, 键具有唯一性
print('-' * 28)
# 演示 in 表示: 是否在, 可以作用于: 字符串, 列表, 元组, 字典
print('a' in 'abc')
print(10 in [10, 20, 30])
print(10 in (10, 20, 30))
print(10 in {10, 20, 30})
print('name' in {'name': '张三', 'age': 23}) # 字典只能判断是否包含这个键.
print(23 in {'name': '张三', 'age': 23}) # 字典只能判断是否包含这个键.
print('-' * 28)
# 演示 not in 表示: 是否不在, 可以作用于: 字符串, 列表, 元组, 字典
print('a' not in 'abc')
print(10 not in [10, 20, 30])
print(10 not in (10, 20, 30))
print(10 not in {10, 20, 30})
print('name' not in {'name': '张三', 'age': 23}) # 字典只能判断是否包含这个键.
print(23 not in {'name': '张三', 'age': 23}) # 字典只能判断是否包含这个键.
4.容器类型-公共函数
"""
容器类型的公共操作-函数:
len() 获取长度
del 或者 del() 删除
max() 获取最大值
min() 获取最小值
range(start, end, step) 生成指定范围内的数据
enumerate() 基于可迭代类型(字符串, 列表, 元组等), 生成 下标 + 元素的方式, 即: ['a', 'b', 'c'] => [(0, 'a'), (1, 'b'), (2, 'c')]
"""
# 此处以列表作为演示, 其它雷同.
list1 = [10, 50, 20, 30, 66, 22]
# 演示: len() 获取长度
print(len(list1))
# 演示: del 或者 del() 删除
del list1[1]
del(list1[1]) # 效果同上.
print(f'删除后的list1: {list1}')
# 演示: max() 获取最大值
print(f'最大值: {max(list1)}')
# 演示: min() 获取最小值
print(f'最大值: {min(list1)}')
# 演示: range(start, end, step) 生成指定范围内的数据
print(f'range生成数据: {range(1, 5, 2)}') # range生成数据: range(1, 5, 2)
print(f'range生成数据: {list(range(1, 5, 2))}') # range生成数据: [1, 3]
# 演示: enumerate() 基于可迭代类型(字符串, 列表, 元组等), 生成 下标 + 元素的方式, 即: ['a', 'b', 'c'] => [(0, 'a'), (1, 'b'), (2, 'c')]
print(f'list1: {list1}') # [10, 30, 66, 22]
print(enumerate(list1)) # 直接打印是: 枚举对象的地址值, 无意义, 我们来遍历它. <enumerate object at 0x000001DFB75F6640>
for i in enumerate(list1):
print(i) # 格式: (下标, 元素值), 且下标默认从 0 开始.
print('-' * 28)
for i in enumerate(list1, 5):
print(i) # 格式: (下标, 元素值), 且下标从 5 开始.
5.列表推导式详解
"""
推导式介绍:
概述:
推导式也叫解析式, 属于Python的一种特有写法, 目的是: 简化我们代码编写的.
分类:
列表推导式
集合推导式
字典推导式
格式:
变量名 = [变量名 for ... in ... if 判断条件]
变量名 = {变量名 for ... in ... if 判断条件}
变量名 = {变量名1:变量名2 for ... in ... if 判断条件}
"""
# 需求1: 创建1个 0 ~ 9的列表.
# 方式1: 不使用推导式.
list1 = []
for i in range(10):
list1.append(i)
print(list1)
# 方式2: 列表推导式.
list2 = [i for i in range(10)] # 效果同上.
print(list2)
# 方式3: 类型转换.
list3 = list(range(10))
print(list3)
print('-' * 28)
# 需求2: 创建1个 0 ~ 9的 偶数 列表.
# 方式1: 不使用推导式.
list1 = []
for i in range(10):
if i % 2 == 0:
list1.append(i)
print(list1)
# 方式2: 列表推导式.
list2 = [i for i in range(10) if i % 2 == 0] # 效果同上.
print(list2)
# 方式3: 类型转换.
list3 = list(range(0, 10, 2))
print(list3)
print('-' * 28)
# 需求3: 创建列表 => [(1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
# 提示: 循环嵌套, i的值 1, 2 j的值 0, 1, 2
# 方式1: 普通版, 循环嵌套.
list1 = []
for i in range(1, 3):
for j in range(3):
# print((i, j))
# 把 i 和 j 封装成元组.
# tuple1 = (i, j)
# list1.append(tuple1)
list1.append((i, j))
print(list1)
# 方式2: 列表推导式.
list2 = [(i, j) for i in range(1, 3) for j in range(3)] # 效果同上.
print(list2)
print('-' * 28)
6.集合和字典推导式详解
# 演示 集合推导式.
# 需求1: 生成 0 ~ 9 的偶数 集合.
set1 = {i for i in range(10) if i % 2 == 0}
print(set1)
# 需求2: 创建1个集合, 数据为下方列表的 2次方.
# 目的: 集合元素具有 唯一性, 会自动去重.
list1 = [1, 1, 2]
set2 = {i ** 2 for i in list1}
print(set2)
print('-' * 28)
# 演示 字典推导式, 回顾字典写法: dict1 = {'name':'张三', 'age':23}
# 需求3: 创建1个字典, key是 1 ~ 5的数字, value是该数字的2次方, 例如: {1:2, 2:4, 3:9, 4:16, 5:25}
dict1 = {i: i ** 2 for i in range(1, 6)}
print(dict1)
print('-' * 28)
# 需求4: 把下述的两个列表, 拼接成1个字典.
# 细节: 两个列表的元素个数(长度) 要 一致.
list1 = ['name', 'age', 'gender']
list2 = ['Tom', 20, 'male']
dict2 = {list1[i]: list2[i] for i in range(len(list1))}
print(dict2)
7.函数入门
"""
函数解释:
概述:
函数也叫方法, 就是把 一些具有独立功能的代码封装到一起, 使其称为具有特殊功能的代码集.
函数: function, 方法: method
例如:
独立功能: 拿牙刷, 挤牙膏, 刷上排牙, 刷下排牙, 漱口
代码集: 刷牙
作用:
1. 模块化编程, 方便我们进行管理.
2. 提高代码的复用性.
格式:
def 函数名(形式参数1, 形式参数2...):
函数体
return 具体的返回值
格式解释:
def 固定写法, defined, 定义的意思.
函数名 类似于变量名, 见名知意即可.
形参列表 表示调用函数, 应该传入什么内容(值)
函数体 具体的逻辑代码, 就是以前我们写的if, while, for, 容器...
return 作用1: 结束方法的(类似于break) 作用2: 可以把函数的执行结果进行返回.
细节:
1. 函数必须先定义, 然后才能调用.
2. 定义函数小技巧, 三个明确:
明确函数名
明确形参列表
明确返回值
3. 调用函数小技巧, 三个步骤
写 函数名()
传参, 要什么给什么, 不要就不给.
接收返回值, 返回什么就接收什么, 不给就不接收.
4. 如果函数没有明确的返回值, 则return可以省略不写.
5. 函数必须调用, 才会执行.
"""
# 需求: 模拟基站工作流程, 给 刘亦菲 打电话
print('----- 拨号 -----')
print('拨号方手机 发送信号包 到就近的基站')
print('拨号方就近基站 会解析信号包, 找到 接收方就近的基站')
print('两个基站之间通过 底下电缆的形式 传输信号包')
print('接收方就近的基站 发送信号包到 接收方手机')
print('----- 忙音等待, 嘟嘟嘟 -----')
print('*' * 28)
# 需求: 模拟基站工作流程, 给 胡歌 打电话
print('----- 拨号 -----')
print('拨号方手机 发送信号包 到就近的基站')
print('拨号方就近基站 会解析信号包, 找到 接收方就近的基站')
print('两个基站之间通过 底下电缆的形式 传输信号包')
print('接收方就近的基站 发送信号包到 接收方手机')
print('----- 忙音等待, 嘟嘟嘟 -----')
print('*' * 28)
# 虽然上述的代码实现了需求, 但是 实际开发中, 同样功能的代码绝对不会写两次. 我们可以通过 函数 来优化它.
# 定义函数.
def call():
print('----- 拨号 -----')
print('拨号方手机 发送信号包 到就近的基站')
print('拨号方就近基站 会解析信号包, 找到 接收方就近的基站')
print('两个基站之间通过 底下电缆的形式 传输信号包')
print('接收方就近的基站 发送信号包到 接收方手机')
print('----- 忙音等待, 嘟嘟嘟 -----')
print('*' * 28)
# return # 没有返回值, 可以省略不写.
# 调用函数.
call()
call()
8.函数-说明文档
"""
函数的 说明文档介绍:
概述:
函数的说明文档也叫 文档说明, 就是解释函数的 参数, 作用, 返回值的.
格式:
在函数内的第一行, 用 三引号的写法来实现即可, 可以是双引号(推荐), 也可以单引号.
如何查看说明文档:
help(函数名)
鼠标放到函数上, 点击: ctrl + Q
"""
# 需求1: 定义函数print_info(), 打印自己的信息.
# 1. 定义函数, 介绍自己的基本信息.
def print_info():
'''
该函数用于打印 自身的信息
:return: 无
'''
print('你好, 我叫: 夯哥')
print('我今年 18 岁了')
print('很高兴认识大家, 祝大家学有所成, 早日高薪!')
# return 没有返回值, return可以省略不写.
# 2. 调用函数
print_info()
# 3. 查看上述函数的说明文档.
help(print_info)
print('-' * 28)
# 需求2: 定义get_sum()函数, 计算两个整数和, 并返回.
# 1. 定义函数.
def get_sum(a, b):
"""
该函数用于计算两个整数和, 并返回求和结果.
:param a: 要计算的第1个整数
:param b: 要计算的第2个整数
:return: 两个整数的求和结果.
"""
sum = a + b
return sum
# 2. 调用函数.
result = get_sum(10, 20)
# 3. 打印结果.
print(f'求和结果为: {result}')
9.函数-参数解释
```python
"""
函数 参数 解释:
概述:
定义函数的时候, 写的参数叫: 形式参数, 简称: 形参, 形容调用 函数 需要传入什么值.
调用函数的时候, 写的参数叫: 实际参数, 简称: 实参, 表示 实际参与运算的数据.
"""
# 需求: 定义 get_sum()函数, 用于计算两个整数的和.
# 写法1: 无参, 无返回值的函数.
# 定义函数
def get_sum1():
a, b = 10, 20
sum = a + b
print(f'求和结果为: {sum}')
# 调用函数
get_sum1()
print('-' * 28)
# 虽然上述的操作已经实现了需求, 但是不够灵活, 上述的函数属于把两个数值写"死"了, 只能计算10 和 20的结果.
# 如果我们想计算任意两个整数的和, 如何实现呢?
# 写法2: 有参, 无返回值的函数.
# 定义函数
def get_sum2(a, b): # 形参, 形容调用函数需要给什么值, 给几个. 钱, 饮料名
"""
该函数用于计算两个整数和
:param a: 求和计算的第1个整数
:param b: 求和计算的第2个整数
:return: 无
"""
sum = a + b
print(f'求和结果为: {sum}')
# 调用函数
get_sum2(11, 22) # 33, 11 和 22 叫 实际参数(实参), 表示实际参与运算的数据. 10元, 苏打水
c, d = 100, 200
get_sum2(c, d) # 300 c(100), d(200) 叫实参, 表示实际参与运算的数据. 5元, 娃哈哈矿泉水
# 虽然上述的操作已经实现了需求, 但是不够灵活, 因为上述 求和计算完毕后, 是直接把 求和结果 打印出来了.
# 并没有赋值给变量, 如果未来要对 求和结果做其它的操作, 例如: 和另一个值相加, 比较等, 就实现不了了.
# 可以采用 返回值的 思路解决, 即: 把 两个整数的求和结果当做返回值 进行返回.
10.函数-返回值解释
"""
函数 返回值解释:
概述:
返回值指的是 函数操作完毕后, 需要返回给 调用者 1个什么结果.
格式:
在函数内部通过 return 返回值 这个格式即可返回.
细节:
在哪里调用函数, 就把返回值返回到哪里.
"""
# 接上个脚本, 即: 09-函数-参数解释.py 接着写.
# 写法3: 有参有返回值的函数. 即: 计算两个整数和, 并返回结果.
# 定义函数
def get_sum3(a, b): # 形参
"""
该函数用于计算两个整数和
:param a: 求和计算的第1个整数
:param b: 求和计算的第2个整数
:return: 返回求和结果.
"""
sum = a + b
return sum
# 调用函数
sum = get_sum3(1, 2) # 实参
print(f'求和结果为: {sum}')
print(f'平均值为: {sum // 2}')
11.函数-嵌套调用
"""
函数的嵌套 解释:
概述:
函数的嵌套指的是 函数的嵌套调用, 并不是函数的嵌套定义.
例如: 在 func_B 函数中 调用 func_A 这个函数, 就叫: 函数的嵌套调用.
回顾:
顺序结构: 代码会按照 从上往下, 从左往右, 依次逐行执行.
"""
# 1. 定义func_A()函数.
def func_A():
print('----- func_A start -----') # 2
print('我是 funcA函数 ') # 3
print('----- func_A end -----') # 4
# 2. 定义func_B()函数.
def func_B():
print('----- func_B start -----') # 1
# 3. 在这里调用 funcA()函数.
func_A()
print('----- func_B end -----') # 5
# 4. 在main函数中, 调用 func_B()函数, 观察程序的打印结果.
# main函数是程序的主入口, 所有代码的执行都是从这里开始的.
# main方法可以省略不写(建议写), Python解释器底层执行的时候, 会自动帮我们加.
if __name__ == '__main__':
func_B()
12.函数-嵌套调用案例
# 需求1: 定义函数print_line()用于打印 一行图形, 定义函数 print_lines(), 底层调用 print_line()函数, 实现打印多行图形.
# 1. 定义函数print_line()用于打印 一行图形.
def print_line(cols): # columns: 列.
"""
定义函数, 用于打印1行图形.
:param cols: 该行的列数.
:return: 无
"""
for i in range(cols):
print('-', end='')
print() # 打印完毕后, 记得换行
# 2. 定义函数 print_lines(), 底层调用 print_line()函数, 实现打印多行图形.
def print_lines(rows, cols):
"""
该函数用于打印 多行图形.
:param rows: 行数
:param cols: 每行的列数
:return: 无
"""
for i in range(rows):
# 具体的打印每一行图形的操作, 直接调用 print_line()函数即可.
print_line(cols)
# 3. 调用print_lines()函数, 查看图形.
print_lines(3, 5)
# 需求2: 定义函数 get_sum(), 用于计算三个整数的和. 然后再 get_avg()函数中, 调用get_sum()函数, 并计算它们(三个整数)的平均值.
# 1. 定义函数 get_sum(), 用于计算三个整数的和
def get_sum(a, b, c):
"""
求和函数.
:param a: 求和操作的第1个整数
:param b: 第2个整数
:param c: 第3个整数
:return: 3个整数的 和
"""
sum = a + b + c
return sum
# 2. get_avg()函数中, 调用get_sum()函数, 并计算它们(三个整数)的平均值.
def get_avg(a, b, c):
"""
求 平均值 函数
:param a: 要操作的第1个整数
:param b: 第2个整数
:param c: 第3个整数
:return: 3个整数的平均值.
"""
sum = get_sum(a, b, c)
avg = sum // 3
return avg
# 3. 打印结果.
avg = get_avg(10, 20, 30)
print(f'平均值为: {avg}')
13.变量的作用域
"""
变量的作用域介绍:
概述:
变量的作用域指的是 变量的哪里能用, 哪里不能用, 即: 变量的作用区间.
分类:
局部变量: 定义在函数内 或者 函数形参列表中的 变量.
全局变量: 定义在函数外的变量, 或者用 global 关键字修饰的变量.
面试题:
局部变量 和 全局变量的区别?
答案:
1. 定义位置不同.
局部变量: 定义在函数内 或者 函数形参列表中的 变量.
全局变量: 定义在函数外的变量, 或者用 global 关键字修饰的变量.
2. 在内存中的存储位置不同.
局部变量: 存储在 堆区.
全局变量: 存储在 方法区.
3. 生命周期不同.
局部变量: 随着函数的调用而存在, 随着函数的调用完毕而消失.
全局变量: 随着 .py文件加载而存在, .py文件从内存中移除而消失.
细节:
使用变量遵循就近原则, 局部位置有就直接使用, 没有就去 全局位置找, 有就使用, 没有就报错.
"""
# 案例1: 演示 局部变量的生命周期.
def func1():
a = 10 # 局部变量
print(f'a: {a}')
# 调用 func1()函数.
func1()
# 报错, 超出了 局部变量的作用域
# print(f'在func1()函数外, 调用变量a: {a}')
# 案例2: 演示 全局变量的生命周期.
b = 100
def func2():
print(f'func2函数, b: {b}')
def func3():
print(f'func3函数, b: {b}')
# 调用函数
func2()
func3()
print('-' * 28)
# 案例3: 演示global关键字.
c = 66
def func4():
print(f'func4函数, c: {c}')
def func5():
global c # global声明的变量, 属于: 全局变量. 不写global, 下述的c是 局部变量.
c = 200
print(f'func5函数, c: {c}') # 使用变量遵循 就近原则.
# 调用函数
func4() # 66
func5() # 200
func4() # 200
print('-' * 28)
14.多函数执行流程
"""
关于 函数传递 你需要掌握的两句话.
1. 函数的返回值可以作为 (另一个函数的)参数进行传递.
2. 函数可以作为 (另一个函数的)参数进行传递.
"""
# 演示 1. 函数的返回值可以作为 (另一个函数的)参数进行传递.
def fun1():
return 100 # 返回1个结果 100
def fun2(num): # 需要1个参数
print(num)
# 调用fun1()函数, 获取返回值.
a = fun1() # 相当于 a = 100
# 调用fun2()函数.
fun2(a)
# 合并版.
fun2(fun1()) # 函数的返回值可以作为 (另一个函数的)参数进行传递.
print('-' * 28)
# 演示 直接写函数名, 是函数对象.
def get_sum(a, b):
return a + b
# 正常调用
sum = get_sum(10, 20)
print(sum)
# 直接写函数名 是 对象, 可以赋值给变量, 那个变量就有了和该函数一样的功能.
hg = get_sum # 等价于: def hg(a, b): return a + b
sum2 = hg(20, 30)
print(sum2)
print('-' * 28)
# 演示 2. 函数可以作为 (另一个函数的)参数进行传递.
def get_substract(a, b):
return a - b
def calculate(a, b, fn):
"""
自定义函数, 模拟计算器, 传入什么 函数(对象), 就做什么操作.
:param a: 要操作的第1个整数
:param b: 要操作的第2个整数
:param fn: 具体的操作规则
:return: 计算结果.
"""
return fn(a, b)
print(calculate(10, 20, get_sum))
print(calculate(10, 20, get_substract))