模块 Module
定义:包含一系列数据、函数、类的文件,通常以.py结尾。
作用:让一些相关的数据,函数,类有逻辑的组织在一起,使逻辑结构更加清晰。
有利于多人合作开发。
导入
import
语法:
import 模块名
import 模块名 as 别名
作用:将模块整体导入到当前模块中
使用:模块名.成员
from import
语法:
from 模块名 import 成员名
from 模块名 import 成员名 as 别名
from 模块名 import *
作用:将模块内的成员导入到当前模块作用域中
使用:直接使用成员名
"""
module01.py
"""
def func01():
print("module01 - func01执行喽")
def func02():
print("module01 - func02执行喽")
# 导入方式1:import 模块名
# 使用:模块名.成员
# 原理:创建变量名记录文件地址,使用时通过变量名访问文件中成员
# 备注:"我过去"
# 适用性:适合面向过程(全局变量、函数)
import module01
module01.func01()
# 导入方式2.1:from 文件名 import 成员
# 使用:直接使用成员
# 原理:将模块的成员加入到当前模块作用域中
# 备注:"你过来"
# 注意:命名冲突
# 适用性:适合面向对象(类)
from module01 import func01
def func01():
print("demo01 - func01")
func01() # 调用的是自己的func01
# 导入方式2.2:from 文件名 import *
from module01 import *
func01()
func02()
练习1:
创建2个模块module_exercise.py与exercise.py
将下列代码粘贴到module_exercise模块中,并在exercise中调用。
data = 100
def func01():
print("func01执行喽")
class MyClass:
def func02(self):
print("func02执行喽")
exercise.py
# 1、import 模块名
import module_exercise
module_exercise.func01()
obj = module_exercise.MyClass()
obj.func02()
# 2、from 文件名 import 成员
from module_exercise import func01, MyClass
func01()
obj = MyClass()
obj.func02()
# 3、from 文件名 import *
from module_exercise import *
func01()
obj = MyClass()
obj.func02()
练习2:将信息管理系统拆分为4个模块student_info_manager_system.py
(1)创建目录student_info_manager_system
(2)创建模块bll,存储XXController(注:业务逻辑层 business logic layer)
(3)创建模块usl,存储XXView(注:用户显示层 user show layer)
(4)创建模块dtl,存储XXModel(注:数据传输层 data transfer layer)
(5)创建模块main,存储调用XXView的代码
dtl.py
class UserModel:
"""
数据模型类
"""
def __init__(self, id, name, age):
self.id = id
self.name = name
self.age = age
def __str__(self):
return f"ID: {self.id}, 姓名: {self.name}, 年龄: {self.age}"
bll.py
class UserController:
"""
逻辑控制类
"""
def __init__(self):
self.list_user = []
def add_user(self, user):
self.list_user.append(user)
print(f"用户 {user.name} 添加成功.")
def update_user(self, user_id, new_user):
for user in self.list_user:
if user.id == user_id:
user.__dict__.update(new_user) # 假设new_data是一个包含新属性的字典
print(f"用户ID {user_id} 修改成功.")
return
print(f"用户ID {user_id} 未找到.")
def remove_user(self, user_id):
for user in self.list_user[:]: # 使用[:]创建列表的副本,避免在迭代时修改列表
if user.id == user_id:
self.list_user.remove(user)
print(f"用户ID {user_id} 删除成功.")
return
print(f"用户ID {user_id} 未找到.")
def list_users(self):
if len(self.list_user) == 0:
print("系统用户为空")
for user in self.list_user:
print(user)
usl.py
import sys
from dtl import UserModel
class UserView:
"""
界面视图类
"""
def __init__(self, user_manager):
self.user_manager = user_manager
def __display_menu(self):
print("================== 欢迎使用用户管理系统 ==================")
print("================== 1.用户查询 ==================")
print("================== 2.用户录入 ==================")
print("================== 3.用户修改 ==================")
print("================== 4.用户删除 ==================")
print("================== 5.退出系统 ==================")
print("=======================================================")
def __select_menu(self):
choice = int(input("请输入序号: "))
return choice
def main(self):
while True:
self.__display_menu()
choice = self.__select_menu()
if choice == 1:
self.user_manager.list_users()
elif choice == 2:
user = self.__input_user()
self.user_manager.add_user(user)
elif choice == 3:
self.__modify_user()
elif choice == 4:
self.__delete_user()
elif choice == 5:
print("您已退出系统,欢迎下次使用!")
sys.exit(0)
break
else:
print("输入有误,请重新输入!")
def __input_user(self):
id = input("请输入ID: ")
name = input("请输入姓名: ")
age = input("请输入年龄: ")
return UserModel(id, name, int(age))
def __display_user(self, user):
print(user)
def __delete_user(self):
user_id = input("请输入需删除的ID: ")
self.user_manager.remove_user(user_id)
def __modify_user(self):
user_id = input("请输入需修改的ID: ")
new_name = input("请输入新的姓名: ")
new_age = input("请输入新的年龄: ")
new_data = {"name": new_name, "age": int(new_age)}
self.user_manager.update_user(user_id, new_data)
main.py
from bll import UserController
from usl import UserView
"""
主函数入口
"""
if __name__ == "__main__":
User_controller = UserController()
user_view = UserView(User_controller)
user_view.main()
模块变量
__name__变量:模块自身名字,可以判断是否为主模块。
当此模块作为主模块(第一个运行的模块)运行时,name绑定’main’,不是主模块,而是被其它模块导入时,存储模块名。
加载过程
在模块导入时,模块的所有语句会执行。
如果一个模块已经导入,则再次导入时不会重新执行模块内的语句。
分类
内置模块(builtins),在解析器的内部可以直接使用。
标准库模块,安装Python时已安装且可直接使用。
第三方模块(通常为开源),需要自己安装。
用户自己编写的模块(可以作为其他人的第三方模块)
练习1:定义函数,根据年月日,计算星期。
输入:2020 9 15
输出:星期二
import datetime
def cal_week(year, month, day):
return datetime.date(year, month, day).weekday()
cur_year = int(input("输入年:"))
cur_month = int(input("输入月:"))
cur_day = int(input("输入日:"))
cur_weekday = cal_week(cur_year, cur_month, cur_day)
if cur_weekday == 0:
print("星期一")
elif cur_weekday == 1:
print("星期二")
elif cur_weekday == 2:
print("星期三")
elif cur_weekday == 3:
print("星期四")
elif cur_weekday == 4:
print("星期五")
elif cur_weekday == 5:
print("星期六")
elif cur_weekday == 6:
print("星期日")
练习2:定义函数,根据生日(年月日),计算活了多天.
输入:2010 1 1
输出:从2010年1月1日到现在总共活了3910天
import time
def cal_days(year, mon, day):
str_time = "%d-%d-%d" % (year, mon, day)
time_tuple = time.strptime(str_time, "%Y-%m-%d")
cur_sec = time.time() - time.mktime(time_tuple)
return int(cur_sec / 60 / 60 / 24)
cur_year = int(input("输入年:"))
cur_month = int(input("输入月:"))
cur_day = int(input("输入日:"))
total_day = cal_days(cur_year, cur_month, cur_day)
print(f"从{cur_year}年{cur_month}月{cur_day}日到现在总共活了{total_day}天")
包package
定义:将模块以文件夹的形式进行分组管理。
作用:让一些相关的模块组织在一起,使逻辑结构更加清晰。
导入
import
语法:
import 路径.模块名
import 路径.模块名 as 别名
作用:将模块整体导入到当前模块中
使用:模块名.成员
from import
语法:
from 路径.模块名 import 成员名
from 路径.模块名 import 成员名 as 别名
from 路径.模块名 import *
作用:将模块内的成员导入到当前模块作用域中
使用:直接使用成员名
注意:路径从项目根目录开始计算
练习:
(1) 根据下列结构,创建包与模块。
my_project/
main.py
common/
init.py
list_helper.py
skill_system/
init.py
skill_deployer.py
skill_manager.py
(2) 在main.py中调用skill_manager.py中实例方法。
(3) 在skill_manager.py中调用skill_deployer.py中实例方法。
(4) 在skill_deployer.py中调用list_helper.py中实例方法。
list_helper.py
class Helper:
def list_helper(self):
print("list helper ...")
skill_deployer.py
from higher.my_project.common.list_helper import Helper
class Deployer:
def skill_deployer(self):
print("skill deployer ...")
Helper().list_helper()
skill_manager.py
from higher.my_project.skill_system.skill_deployer import Deployer
class Manager:
def skill_manager(self):
print("skill manager ...")
Deployer().skill_deployer()
main.py
from higher.my_project.skill_system.skill_manager import Manager
"""
主函数入口
"""
if __name__ == "__main__":
Manager().skill_manager()
异常处理Error
异常
定义:运行时检测到的错误。
现象:当异常发生时,程序不会再向下执行,而转到函数的调用语句。
常见异常类型:
- 名称异常(NameError):变量未定义。
- 类型异常(TypeError):不同类型数据进行运算。
- 索引异常(IndexError):超出索引范围。
- 属性异常(AttributeError):对象没有对应名称的属性。
- 键异常(KeyError):没有对应名称的键。
- 异常基类Exception。
处理
语法:
try:
可能触发异常的语句
except 错误类型1 [as 变量1]:
处理语句1
except 错误类型2 [as 变量2]:
处理语句2
except Exception [as 变量3]:
不是以上错误类型的处理语句
finally:
无论是否发生异常的语句
作用:将程序由异常状态转为正常流程。
说明:
as 子句是用于绑定错误对象的变量,可以省略
except子句可以有一个或多个,用来捕获某种类型的错误。
finally子句最多只能有一个,如果没有except子句,必须存在。
如果异常没有被捕获到,会向上层(调用处)继续传递,直到程序终止运行。
练习:创建函数,在终端中录入int类型成绩。如果格式不正确,重新输入。
效果:
score = get_score()
print(“成绩是:%d”%score)
def get_score():
while True:
try:
score = int(input("录入成绩:"))
return score
except:
print("格式不正确,重新输入")
score = get_score()
print("成绩是 %d" % score)
迭代
每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。例如:循环获取容器中的元素。
可迭代对象iterable
定义:具有__iter__函数的对象,可以返回迭代器对象。
语法:
# 创建:
class 可迭代对象名称:
def __iter__(self):
return 迭代器
# 使用:
for 变量名 in 可迭代对象:
语句
原理:
迭代器 = 可迭代对象.__iter__()
while True:
try:
print(迭代器.__next__())
except StopIteration:
break
演示:
message = "我是花果山水帘洞孙悟空"
# for item in message:
# print(item)
# 1. 获取迭代器对象
iterator = message.__iter__()
# 2. 获取下一个元素
while True:
try:
item = iterator.__next__()
print(item)
# 3. 如果停止迭代则跳出循环
except StopIteration:
break
练习1:创建列表,使用迭代思想,打印每个元素.
list_area = [
"河北",
"山西",
"辽宁",
"吉林",
"黑龙江",
"江苏",
"浙江",
"安徽",
"福建",
"江西",
"山东",
"河南",
"湖北",
"湖南",
"广东",
"海南",
"四川",
"贵州",
"云南",
"陕西",
"甘肃",
"青海",
"台湾",
"内蒙古",
"广西",
"西藏",
"宁夏",
"新疆",
"甘肃",
"北京",
"天津",
"上海",
"重庆",
"香港",
"澳门"
]
iterator = list_area.__iter__()
while True:
try:
print(iterator.__next__())
except StopIteration:
break
练习2:创建字典,使用迭代思想,打印每个键值对.
dict_mv = [
{"name": "八角笼中", "type": "剧情", "actor": "王宝强"},
{"name": "封神第一部", "type": "战争", "actor": "黄渤"},
]
iterator1 = dict_mv.__iter__()
while True:
try:
print(iterator1.__next__())
except StopIteration:
break
迭代器对象iterator
定义:可以被next()函数调用并返回下一个值的对象。
语法:
class 迭代器类名:
def __init__(self, 聚合对象):
self.聚合对象= 聚合对象
def __next__(self):
if 没有元素:
raise StopIteration()
return 聚合对象元素
说明:聚合对象通常是容器对象。
作用:使用者只需通过一种方式,便可简洁明了的获取聚合对象中各个元素,而又无需了解其内部结构。
演示:
class StudentIterator:
def __init__(self, data):
self.__data = data
self.__index = -1
def __next__(self):
if self.__index == len(self.__data) - 1:
raise StopIteration()
self.__index += 1
return self.__data[self.__index]
class StudentController:
def __init__(self):
self.__students = []
def add_student(self, stu):
self.__students.append(stu)
def __iter__(self):
return StudentIterator(self.__students)
controller = StudentController()
controller.add_student("悟空")
controller.add_student("八戒")
controller.add_student("唐僧")
# for item in controller:
# print(item) #
iterator = controller.__iter__()
while True:
try:
item = iterator.__next__()
print(item) #
except StopIteration:
break
练习1:遍历商品控制器
class CommodityController:
pass
controller = CommodityController()
controller.add_commodity("屠龙刀")
controller.add_commodity("倚天剑")
controller.add_commodity("芭比娃娃")
for item in controller:
print(item)
class controllerIterator:
def __init__(self, data):
self.__data = data
self.__ind = -1
def __next__(self):
if self.__ind == len(self.__data) - 1:
raise StopIteration
self.__ind += 1
return self.__data[self.__ind]
class CommodityController:
def __init__(self):
self.__controllers = []
def add_commodity(self,name):
self.__controllers.append(name)
def __iter__(self):
return controllerIterator(self.__controllers)
controller = CommodityController()
controller.add_commodity("屠龙刀")
controller.add_commodity("倚天剑")
controller.add_commodity("芭比娃娃")
for item in controller:
print(item)
练习2:创建自定义range类,实现下列效果.
class MyRange:
pass
for number in MyRange(5):
print(number)# 0 1 2 3 4
class RangeIterator:
def __init__(self, num):
self.__num = num
self.__ide = -1
def __next__(self):
self.__ide += 1
if self.__ide > self.__num - 1:
raise StopIteration
return self.__ide
class MyRange:
def __init__(self, num):
self.__num = int(num)
def __iter__(self):
return RangeIterator(self.__num)
for number in MyRange(5):
print(number) # 0 1 2 3 4
生成器generator
定义:能够动态(循环一次计算一次返回一次)提供数据的可迭代对象。
作用:在循环过程中,按照某种算法推算数据,不必创建容器存储完整的结果,从而节省内存空间。数据量越大,优势越明显。以上作用也称之为延迟操作或惰性操作,通俗的讲就是在需要的时候才计算结果,而不是一次构建出所有结果。
生成器函数
定义:含有yield语句的函数,返回值为生成器对象。
语法:
# 创建:
def 函数名():
"""
yield 数据
"""
# 调用:
for 变量名 in 函数名():
语句
说明:
- 调用生成器函数将返回一个生成器对象,不执行函数体。
- yield翻译为”产生”或”生成”
执行过程:
a. 调用生成器函数会自动创建迭代器对象。
b. 调用迭代器对象的next()方法时才执行生成器函数。
c. 每次执行到yield语句时返回数据,暂时离开。
d. 待下次调用next()方法时继续从离开处继续执行。
原理:生成迭代器对象的大致规则如下:
a. 将yield关键字以前的代码放在next方法中。
b. 将yield关键字后面的数据作为next方法的返回值。
案例:
def my_range(stop):
number = 0
while number < stop:
yield number
number += 1
for number in my_range(5):
print(number) # 0 1 2 3 4
练习1:定义函数,在列表中找出所有偶数
[43,43,54,56,76,87,98]
def even_comp(nums):
for number in nums:
if number % 2 == 0:
yield number
nums = [43, 43, 54, 56, 76, 87, 98]
for even in even_comp(nums):
print(even) # 54 56 76 98
练习2:定义函数,在列表中找出所有数字
[43,“悟空”,True,56,“八戒”,87.5,98]
def find_num(strs):
for str in strs:
if type(str) in (int, float):
yield str
strs = [43, "悟空", True, 56, "八戒", 87.5, 98]
for str in find_num(strs):
print(str) # 43 56 87.5 98
内置生成器
枚举函数enumerate
语法:
for 变量 in enumerate(可迭代对象):
语句
for 索引, 元素in enumerate(可迭代对象):
语句
作用:遍历可迭代对象时,可以将索引与元素组合为一个元组。
演示:
list01 = [43, 43, 54, 56, 76]
# 从头到尾读 -- 读取数据
for item in list01:
print(item)
# 非从头到尾读 -- 修改数据
for i in range(len(list01)):
if list01[i] % 2 == 0:
list01[i] += 1
for i, item in enumerate(list01): # -- 读写数据
if item % 2 == 0:
list01[i] += 1
练习1:将列表中所有奇数设置为None
nums = [43, 43, 54, 56, 76, 87, 98]
for i, item in enumerate(nums):
if item % 2 != 0:
nums[i] = None
print(nums)
练习2:将列表中所有偶数自增1
nums = [43, 43, 54, 56, 76, 87, 98]
for i, item in enumerate(nums):
if item % 2 == 0:
nums[i] += 1
print(nums)
zip
语法:
for item in zip(可迭代对象1, 可迭代对象2):
语句
作用:将多个可迭代对象中对应的元素组合成一个个元组,生成的元组个数由最小的可迭代对象决定。
演示:
list_name = ["悟空", "八戒", "沙僧"]
list_age = [22, 26, 25]
# for 变量 in zip(可迭代对象1,可迭代对象2)
for item in zip(list_name, list_age):
print(item)
# ('悟空', 22)
# ('八戒', 26)
# ('沙僧', 25)
应用:矩阵转置
map = [
[2, 0, 0, 2],
[4, 2, 0, 2],
[2, 4, 2, 4],
[0, 4, 0, 4]
]
# new_map = []
# for item in zip(map[0],map[1],map[2],map[3]):
# new_map.append(list(item))
# print(new_map)
# new_map = []
# for item in zip(*map):
# new_map.append(list(item))
new_map = [list(item) for item in zip(*map)]
print(new_map) # [[2, 4, 2, 0], [0, 2, 4, 4], [0, 0, 2, 0], [2, 2, 4, 4]]
练习:将两个列表合并为一个字典
list_student_name = ["悟空", "八戒", "白骨精"]
list_student_age = [28, 25, 36]
list_student_name = ["悟空", "八戒", "白骨精"]
list_student_age = [28, 25, 36]
new_dict = dict(zip(list_student_name, list_student_age))
print(new_dict)
生成器表达式
定义:用推导式形式创建生成器对象。
语法:
变量 = (表达式 for 变量 in 可迭代对象 if 条件)
练习1:使用生成器表达式在列表中获取所有字符串.
list01 = [43, "a", 5, True, 6, 7, 89, 9, "b"]
list01 = [43, "a", 5, True, 6, 7, 89, 9, "b"]
res = [item for item in list01 if type(item) == str]
print(res)
练习2:在列表中获取所有整数,并计算它的平方.
res = [item**2 for item in list01 if type(item) == int]
print(res)
函数式编程
定义:用一系列函数解决问题。
- 函数可以赋值给变量,赋值后变量绑定函数。
- 允许将函数作为参数传入另一个函数。
- 允许函数返回一个函数。
高阶函数:将函数作为参数或返回值的函数。
函数作为参数
将核心逻辑传入方法体,使该方法的适用性更广,体现了面向对象的开闭原则。
list01 = [342, 4, 54, 56, 6776]
# 定义函数,在列表中查找第一个大于100的数
def get_number_gt_100():
for number in list01:
if number > 100:
return number
# 定义函数,在列表中查找第一个偶数
def get_number_by_even():
for number in list01:
if number % 2 == 0:
return number
# 参数:得到的是列表中的元素
# 返回值:对列表元素判断后的结果(True False)
def condition01(number):
return number > 100
def condition02(number):
return number % 2 == 0
# 通用函数
def find_single(condition): # 抽象
for item in list01:
# if number > 100:
# if condition01(item):
# if condition02(item):
if condition(item):# 统一
return item
# 变化点函数:查找小于10的数据
def condition03(number):
return number < 10
print(find_single(condition03))
练习1:
需求:
定义函数,在列表中查找第一个奇数
定义函数,在列表中查找第一个能被3或5整除的数字
步骤:
- 根据需求,写出函数。
- 因为主体逻辑相同,核心算法不同.
所以使用函数式编程思想(分、隔、做)
创建通用函数find_single - 在当前模块中调用
# 使用函数式编程思想
# 抽象相同的主题结构,创建一个高阶函数
def find_single(nums, condition):
for item in nums:
if condition(item):
return item
# 奇数
def find_odd(num):
return num % 2 != 0
# 能被3或5整除的数字
def find_division(num):
return num % 3 == 0 or num % 5 == 0
nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(find_single(nums, find_odd))
print(find_single(nums, find_division))
练习2:
需求:
定义函数,在员工列表中查找所有部门是9001的员工
定义函数,在员工列表中查找所有姓名是2个字的员工
步骤:
– 根据需求,写出函数。
– 因为主体逻辑相同,核心算法不同.
所以使用函数式编程思想(分、隔、做)
创建通用函数find_all
– 在当前模块中调用
class Employee:
def __init__(self, eid, did, name, money):
self.eid = eid # 员工编号
self.did = did # 部门编号
self.name = name
self.money = money
list_employees = [
Employee(1001, 9002, "师父", 60000),
Employee(1002, 9001, "孙悟空", 50000),
Employee(1003, 9002, "猪八戒", 20000),
Employee(1004, 9001, "沙僧", 30000),
Employee(1005, 9001, "小白龙", 15000),
]
class Employee:
def __init__(self, eid, did, name, money):
self.eid = eid # 员工编号
self.did = did # 部门编号
self.name = name
self.money = money
def __str__(self) -> str:
return f"员工编号: {self.eid}, 部门编号: {self.did}, 姓名: {self.name}, 工资: {self.money}"
def find_all(employees, condition, param):
for employ in employees:
if condition(employ, param):
print(employ)
def find_by_did(employ, did):
return employ.did == did
def find_by_name(employ, count):
return len(employ.name) == count
if __name__ == '__main__':
list_employees = [
Employee(1001, 9002, "师父", 60000),
Employee(1002, 9001, "孙悟空", 50000),
Employee(1003, 9002, "猪八戒", 20000),
Employee(1004, 9001, "沙僧", 30000),
Employee(1005, 9001, "小白龙", 15000),
]
print("在员工列表中查找所有部门是9001的员工:")
find_all(list_employees, find_by_did, 9001)
print("-----------------------------------------------------")
print("在员工列表中查找所有姓名是2个字的员工:")
find_all(list_employees, find_by_name, 2)
lambda 表达式
定义:是一种匿名方法
作用:
- 作为参数传递时语法简洁,优雅,代码可读性强。
- 随时创建和销毁,减少程序耦合度。
语法:
# 定义:
变量 = lambda 形参: 方法体
# 调用:
变量(实参)
说明:
- 形参没有可以不填。
- 方法体只能有一条语句,且不支持赋值语句。
演示:
from common.iterable_tools import IterableHelper
# 定义函数,在列表中查找所有大于100的数
# def condition01(number):
# return number > 100
# 定义函数,在列表中查找所有偶数
# def condition02(number):
# return number % 2 == 0
list01 = [342, 4, 54, 56, 6776]
for item in IterableHelper.find_all(list01,lambda number: number > 100):
print(item)
for item in IterableHelper.find_all(list01,lambda number: number % 2 == 0):
print(item)
内置高阶函数
map(函数,可迭代对象):使用可迭代对象中的每个元素调用函数,将返回值作为新可迭代对象元素;返回值为新可迭代对象。
filter(函数,可迭代对象):根据条件筛选可迭代对象中的元素,返回值为新可迭代对象。
sorted(可迭代对象,key = 函数,reverse = bool值):排序,返回值为排序结果。
max(可迭代对象,key = 函数):根据函数获取可迭代对象的最大值。
min(可迭代对象,key = 函数):根据函数获取可迭代对象的最小值。
演示:
class Employee:
def __init__(self, eid, did, name, money):
self.eid = eid # 员工编号
self.did = did # 部门编号
self.name = name
self.money = money
# 员工列表
list_employees = [
Employee(1001, 9002, "师父", 60000),
Employee(1002, 9001, "孙悟空", 50000),
Employee(1003, 9002, "猪八戒", 20000),
Employee(1004, 9001, "沙僧", 30000),
Employee(1005, 9001, "小白龙", 15000),
]
# 1. map 映射
# 需求:获取所有员工姓名
for item in map(lambda item: item.name, list_employees):
print(item)
# 2. filter 过滤器
# 需求:查找所有部门是9002的员工
for item in filter(lambda item: item.did == 9002, list_employees):
print(item.__dict__)
# 3. max min 最值
emp = max(list_employees, key=lambda emp: emp.money)
print(emp.__dict__)
# 4. sorted
# 升序排列
new_list = sorted(list_employees, key=lambda emp: emp.money)
print(new_list)
# 降序排列
new_list = sorted(list_employees, key=lambda emp: emp.money, reverse=True)
print(new_list)
练习:
- 在商品列表,获取所有名称与单价
- 在商品列表中,获取所有单价小于10000的商品
- 对商品列表,根据单价进行降序排列
- 获取元组中长度最大的列表 ([1,1],[2,2,2],[3,3,3])
class Commodity:
def __init__(self, cid=0, name="", price=0):
self.cid = cid
self.name = name
self.price = price
def __str__(self):
return F"ID:{self.cid},名称:{self.name},单价:{self.price}"
# 商品列表
list_commodity_infos = [
Commodity(1001, "屠龙刀", 10000),
Commodity(1002, "倚天剑", 10000),
Commodity(1003, "金箍棒", 52100),
Commodity(1004, "口罩", 20),
Commodity(1005, "酒精", 30),
]
# 所有名称与单价
for item in map(lambda item: "名称:" + item.name + ",单价:" + str(item.price), list_commodity_infos):
print(item)
# 所有单价小于10000的商品
for item in filter(lambda item: item.price < 10000, list_commodity_infos):
print(item.__dict__)
# 根据单价进行降序排列
new_products = sorted(list_commodity_infos, key=lambda item: item.price)
print(new_products)
for item in new_products:
print(item)
# 获取元组中长度最大的列表 ([1,1],[2,2,2],[3,3,3])
tuple_nums = ([1, 1], [2, 2, 2], [3, 3, 3])
nums = max(tuple_nums, key=lambda item: len(item))
print(nums)
函数作为返回值
逻辑连续,当内部函数被调用时,不脱离当前的逻辑。
闭包
三要素:
- 必须有一个内嵌函数。
- 内嵌函数必须引用外部函数中变量。
- 外部函数返回值必须是内嵌函数。
语法:
定义:
def 外部函数名(参数):
外部变量
def 内部函数名(参数):
使用外部变量
return 内部函数名
# 调用:
变量 = 外部函数名(参数)
变量(参数)
定义:是由函数及其相关的引用环境组合而成的实体。
优点:内部函数可以使用外部变量。
缺点:外部变量一直存在于内存中,不会在调用结束后释放,占用内存。
作用:实现python装饰器。
演示:
def give_gife_money(money):
print("获得", money, "元压岁钱")
def child_buy(commodity, price):
nonlocal money
money -= price
print("购买了", commodity, "花了", price, "元,还剩下", money)
return child_buy
action = give_gife_money(500)
action("变形金刚", 200)
action("芭比娃娃", 300)
练习:使用闭包模拟以下情景:
在银行开户存入10000
购买xx商品花了xx元
购买xx商品花了xx元
def create_account(money):
print(f"在银行开户存入 {money}")
def buy_goods(goods, price):
nonlocal money
money -= price
print(f"购买 {goods} 商品花了 {price} 元,还剩 {money} 元")
return buy_goods
ac = create_account(10000)
ac("玩具车", 200)
ac("泡泡糖", 1)
函数装饰器decorator
定义:在不改变原函数的调用以及内部代码情况下,为其添加新功能的函数。
语法:
def 函数装饰器名称(func):
def wrapper(*args, **kwargs):
需要添加的新功能
res = func(*args, **kwargs)
return res
return wrapper
@ 函数装饰器名称
def 原函数名称(参数):
函数体
原函数(参数)
本质:使用“@函数装饰器名称”修饰原函数,等同于创建与原函数名称相同的变量,关联内嵌函数;故调用原函数时执行内嵌函数。
原函数名称 = 函数装饰器名称(原函数名称)
def func01():
print("旧功能")
def new_func(func):
def wrapper():
print("新功能")
func() # 执行旧功能
return wrapper
# 新功能覆盖了旧功能
# func01 = new_func
# 调用一次外部函数(装饰器本质)
func01 = new_func(func01)
# 调用多次内部函数
func01()
func01()
装饰器链:
一个函数可以被多个装饰器修饰,执行顺序为从近到远。
练习1:不改变插入函数与删除函数代码,为其增加验证权限的功能
def verify_permissions():
print("验证权限")
def insert():
print("插入")
def delete():
print("删除")
insert()
delete()
def verify_permissions():
print("验证权限")
def insert():
print("插入")
def delete():
print("删除")
def new_func(func):
def wrapper():
verify_permissions()
func()
return wrapper
new_insert = new_func(insert)
new_insert()
new_delete = new_func(delete)
new_delete()
练习2:为 sum_data 增加打印函数执行时间的功能.
函数执行时间公式: 执行后时间 - 执行前时间
def sum_data(n):
sum_value = 0
for number in range(n):
sum_value += number
return sum_value
print(sum_data(10))
print(sum_data(1000000))
import time
def sum_data(n):
sum_value = 0
for number in range(n):
sum_value += number
return sum_value
def new_func(func, *args):
def wrapper():
start_time = time.perf_counter() # 开始计时
print(func(*args))
end_time = time.perf_counter() # 结束计时
execution_time = end_time - start_time # 计算执行时间
print(f"函数执行时间{round(float(execution_time), 2)}毫秒")
return wrapper
new_sum_data01 = new_func(sum_data, 10)
new_sum_data02 = new_func(sum_data, 1000000)
new_sum_data01()
new_sum_data02()
文件操作
文件管理
基础概念
文件
定义:保存在持久化存储设备(硬盘、U盘、光盘…)上的一段数据。
例如:文本,图片,视频,音频等。
路径
定义:对文件存储在计算机中位置的标识,除Window使用反斜杠"“以外,其他操作系统使用斜杠”/“分隔。
当前路径:正在执行的Python文件所在目录。
绝对路径:从操作系统根目录开始,Window以盘符"C:”、“D:”,OS X或Linux以斜杠"/"开始。
相对路径:从当前目录开始。
pathlib模块
对os模块中与文件操作相关的封装,是基于面向对象的跨平台路径操作模块。
官方文档:https://docs.python.org/zh-cn/3/library/pathlib.html?highlight=pathlib
创建路径
语法
# 导入路径类
from pathlib import Path
# 相对路径
对象名 = Path(相对路径)
# 当前工作目录的绝对路径
对象名 = Path.cwd()
# 绝对路径 + 相对路径
对象名 = Path.cwd().joinpath("目录1","目录2")
练习:在path01目录中,分别使用相对路径、绝对路径判断下列文件是否存在:
test01/demo01.py
test02/demo/demo01.py
test03/demo/demo01.py
新建 test01、test02、test03 目录
test01下新建 demo01.py
test02下新建 demo 目录,demo目录下新建demo01.py
test03下新建 demo 目录,demo目录下新建demo02.py
在 path01 目录下新建 test.py ,程序内容如下:
from pathlib import Path
rela_path1 = Path("test01/demo01.py")
print(rela_path1.exists()) #True
rela_path2 = Path("test02/demo/demo01.py")
print(rela_path2.exists()) #True
rela_path3 = Path("test03/demo/demo01.py")
print(rela_path3.exists()) #False
路径信息
对象名.absolute() # 绝对路径(路径类型)
对象名.name # 带后缀的完整文件名(str类型)
对象名.stem # 文件名不带后缀(str类型)
对象名.suffix # 文件后缀(str类型)
对象名.parent # 上一级路径(路径类型)
对象名.parts # 分割路径(tuple类型)
对象名.exists() # 路径是否存在(bool类型)
对象名.is_file() # 是否文件(bool类型)
对象名.is_dir() # 是否目录(bool类型)
对象名.is_absolute() # 是否绝对路径(bool类型)
对象名.stat().st_ctime # 创建时间(时间戳)
对象名.stat().st_atime # 访问时间(时间戳)
对象名.stat().st_mtime # 修改的时间(时间戳)
对象名.stat().st_size # 文件大小(字节Bete)
搜索目录
语法
# 注意:路径对象必须是目录,不能是文件
# 搜索当前目录所有路径(一层)
生成器 = 对象名.iterdir():
# 根据通配符搜索当前目录所有路径(一层),*表示任意多个字符
# 例如:*.py表示所有Python文件
生成器 = path.glob("通配符"):
# 根据通配符递归搜索当前目录所有路径(多层)
生成器 = 对象名.rglob("通配符")
示例
# (当前目录为path01)
# 打印名称为demo的文件
for item in Path.cwd().glob(r"*/demo*"):
print(item)
# # 打印所有后缀为.py的文件
list_file = Path.cwd().rglob(r"*.py")
for item in list_file:
print(item)
练习(自定义实现):
打印所有图片的大小
#path01新建imgs目录,导入适量图片
img_path = Path("imgs").glob(r"*")
for item in img_path:
print(item.name + " 的大小:" + str(item.stat().st_size))
打印path01中所有文件的路径
all_path = Path.cwd().rglob(r"*")
for item in all_path:
print(item)
打印所有文本(.txt)文件的创建时间(格式:年/月/日)
#path01新建texts目录,创建部分.txt文件
img_path = Path("texts").glob(r"*")
for item in img_path:
time_struct = time.localtime(item.stat().st_ctime)
time_format = time.strftime("%Y-%m-%d %H:%M:%S", time_struct)
print(item.name + " 的创建时间为:" + str(time_format))
新建路径
# 新建文件
对象名.touch()
# 新建目录
对象名.mkdir()
对象名.mkdir(exist_ok=True) # 忽略目录存在时的报错
重命名
语法
对象名.rename(新路径对象)
示例:修改month01\day03\homework\exercise01.py文件名称或后缀
# 修改前:day03/homework/exercise01.py
old_file = Path("day03", "homework", "exercise01.py")
new_file_name = old_file.with_name("new_exercise.py")
# 修改后:day03/homework/new_exercise.py
old_file.rename(new_file_name)
删除路径
对象名.unlink() # 删除文件(永久删除,回收站不存在)
对象名.rmdir() # 删除目录(目录必须为空)
文件读写
读:即从文件中获取内容
写:即修改文件中的内容
基本步骤:打开文件,读写文件,关闭文件
官方文档:https://docs.python.org/zh-cn/3/library/functions.html?highlight=open#open
文本文件
打开后会自动解码为字符,如txt文件
打开文件
语法
对象名 = open(文件路径,"操作模式",encoding="编码方式")
操作模式
编码方式
Linux操作系统文本文件默认为"utf-8"
Windows操作系统文本文件默认为"gbk"
读写文件
读取
# 读取文件中指定数量字符
字符串 = 对象名.read(字符数) # 省略字符数将读取至文件末尾
# 读取文件中的每行
for 行 in 对象名:
练习: 获取项目中所有python代码字符数
num = 0
list_file = Path.cwd().rglob(r"*.py")
for item in list_file:
obj = open(item, "r", encoding="utf8")
s = obj.read()
num += len(s)
print(num)
写入
# 将字符串写入到文件
字符数 = 对象名.write(字符串)
关闭文件
文件作为操作系统资源,打开后必须关闭,避免超出操作系统限制。
close方法
对象名 = open(文件路径)
try:
操作文件对象
finally:
对象名.close()
with操作
对try…finally语法的简化,当with代码块全部执行完后,无论是否产生异常,都会自动释放资源
with open(文件路径) as 对象名:
通过对象名操作文件
二进制文件
内部编码为二进制码,无法通过文字编码解析,如压缩包,音频,视频,图片等。
打开文件
语法
对象名 = open(文件路径,"操作模式")
操作模式
读写文件
读取
# 读取文件中指定数量字节
字节串 = 对象名.read(字节数) # 省略字节数将读取至文件末尾
写入
# 将字节串写入到文件
字节数 = 对象名.write(字节串)
字节串
以字节类型表达数据,处理二进程数据更方便。
5.7.2.2.3.关闭文件
与前面一致