Python程序结构

news2024/11/27 4:26:30

模块 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(字符数) # 省略字符数将读取至文件末尾

# 读取文件中的每行
forin 对象名:

练习: 获取项目中所有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.关闭文件
与前面一致

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2035255.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【目标检测实验系列】YOLOv5/YOLOv8改进:CARAFE轻量级上采样算子,聚合上下文信息,助力模型涨点(文内附源码)

1. 文章主要内容 本篇博客主要涉及轻量级上采样算子CARAFE&#xff0c;将YOLOv5/YOLOv8模型中最近邻上采样算子改为CARAFE算子&#xff0c;使模型聚合上下文信息&#xff0c;助力模型涨点。 2. 简要概括 论文地址&#xff1a;CARAFE论文地址 论文Github代码&#xff1a…

Go语言 Defer(延迟)

本文主要内容为Go语言中defer(延迟)介绍及应用文件读取使用defer的示例。 目录 定义 应用场景 代码示例 改为匿名函数 总结 定义 延迟&#xff1a;关键字&#xff0c;可以用于修饰语句、函数&#xff0c; 确保这条语句可以在当前栈退出的时候执行。 应用场景 1.一般用于…

【leetcode】特殊数组I【(炒鸡)简单】

好像这题没啥子好说的欸&#xff0c;那就祝点进来的友友今天有好事发生叭~ AC代码见下&#xff1a; class Solution { public:bool isArraySpecial(vector<int>& nums) {for(int i1; i<nums.size(); i)if(nums[i]%2 nums[i-1]%2) return false;return true;} }…

如何妙用哈希表来优化遍历查找过程?刷题感悟总结,c++实现

先上题目 题目链接&#xff1a;题目链接 这题我最先想到的就是前缀和a&#xff0c;构造好了以后就遍历每一个[l,r]数组&#xff08;满足题目要求的连续区间数组&#xff09;&#xff0c;奈何倒数第二个样例时间超限 先给出原思路代码 class Solution { public:int subarray…

网络如何发送一个数据包

网络如何发送一个数据包 网络消息发送就是点一点屏幕。 骚瑞&#xff0c;这一点都不好笑。&#xff08;小品就是我的本质惹&#xff09; 之前我就是会被这个问题搞的不安宁。是怎么知道对方的IP地址的呢&#xff1f;怎么知道对方的MAC呢&#xff1f;世界上计算机有那么多&…

top250的电影

本次的电影排行来源于豆瓣。材料仅用于自身学习和记录自己学习过程 使用python中的requests、BeautifulSoup、xlwt&#xff0c;三者需要提前下载好。。 预处理&#xff1a; url&#xff1a;反应网页变化 其中start后面的数字变化每次加25&#xff0c;对应一页&#xff0c;故…

用exceljs和file-saver插件实现纯前端表格导出Excel(支持样式配置,多级表头)

exceljs在Jquery&#xff08;HTML&#xff09;和vue项目中实现导出功能 前言Jquery&#xff08;HTML&#xff09;中实现导出第一步&#xff0c;先在项目本地中导入exceljs和file-saver包第二步&#xff0c;封装导出Excel方法&#xff08;可直接复制粘贴使用&#xff09;第三步&…

JJ音乐,听歌自由!

林俊杰&#xff0c;这位才华横溢的音乐才子&#xff0c;用他的音符编织了一个又一个令人陶醉的梦幻世界。作为他的音乐爱好者&#xff0c;每一次倾听都是一次心灵的旅程。 他的歌声仿佛有一种魔力&#xff0c;能够穿透灵魂。从《江南》的诗意浪漫&#xff0c;到《不为谁而作的歌…

探索树莓派Pico 2:新一代RP2350芯片引领的微型开发革命

Raspberry Pi Pico 2 是由树莓派基金会推出的微处理器开发板&#xff0c;作为Pico系列的最新成员&#xff0c;它在原有的基础上进行了多项改进和扩展。这款开发板搭载了全新的RP2350芯片&#xff0c;具有更强大的处理能力和更多的功能特性。 1. Raspberry Pi Pico 2的特性和规格…

使用CUbeMX配置STM32F103C8T6 CRC校验

一、CubeMX配置 1.配置RCC 2.配置SYS 3.启用CRC校验 二、Keil添加程序 1.main.c /* USER CODE BEGIN Header */ /********************************************************************************* file : main.c* brief : Main program body*******…

LVGL——(4)标签控件

文章目录 一、介绍二、用法1、创建2、显示文本2.1 直接设置要显示的文本2.2 格式化给定要显示的文本2.3 在 label 中进行换行 3、改变字体大小4、长模式5、文本选择6、文本对齐方式7、非常长的文本8、显示内置图标字体9、事件处理 三、拓展1、修改文本颜色1.1 Palette&#xff…

研0 冲刺算法竞赛 day30 P1102 A-B 数对

P1102 A-B 数对 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路&#xff1a; ①map&#xff0c;键值对计数&#xff0c;将A-B->A-C ②先排序&#xff0c;找对应差值为C的第一个和最后一个计数 代码&#xff1a; #include<iostream> #include <map> #i…

Typora绿色版

1、下载安装 Typora 官网地址&#xff1a;https://typora.io/ 中文站地址&#xff1a;Typora 2、击活 Typora 鼠标右击文件所在位置查询 resources\page-dist\static\js\LicenseIndex.180dd4c7.4da8909c.chunk.chunk.js e.hasActivated"true"e.hasActivated, 替…

使用nvm切换Node.js版本

一、安装nvm nvm&#xff08;Node Version Manager&#xff09;是一个用于管理Node.js版本的工具&#xff0c;它允许你在同一台机器上安装和切换多个Node.js版本。 1.安装nvm https://github.com/coreybutler/nvm-windows 访问以上链接到github去下载 点击releases 下载下图…

优化if-else的几种方式

优化if-else的几种方式 策略模式1、创建支付策略接口2、书写不同的支付方式逻辑代码微信支付QQ支付 3、service层的实现类使用4、controller层的调用说明 枚举与策略模式结合1、创建枚举2、service层书写处理方法3、controller层调用4、说明 Lambda表达式与函数接口说明 策略模…

用于理解视频的基础视觉编码器VideoPrism

人工智能咨询培训老师叶梓 转载标明出处 如何让机器有效地理解和处理视频内容&#xff0c;一直是计算机视觉领域的一个挑战。最近&#xff0c;Google Research的研究人员提出了一种名为VideoPrism的新型视频编码器&#xff0c;旨在通过单一的冻结模型处理多样化的视频理解任务。…

风云崛起之拉氏变换和拉式逆变换

图像的分割写出来了&#xff0c;但是写的不好&#xff0c;暂时先不发了。这两天小y想在把拉式变换的内容写出来&#xff0c;小y最近再看信号和电路&#xff0c;需要复习数学&#xff0c;所以把这点写出来。 首先要推出分布积分的公式&#xff0c;我们知道积分和微分为逆运算&am…

纯css实现多行文本右下角最后一行展示全部按钮

未展开全部&#xff1a; 展开全部&#xff1a; 综上演示按钮始终保持在最下方 css代码如下&#xff1a; <div class"info-content"><div class"info-text" :class"!showAll ? mle-hidden : "><span class"show-all"…

STM32-定时器-定时器中断-PWM调光

1、TIM 定时器 定时器是一种电子设备或软件组件&#xff0c;用于在预定时间后触发一个事件或操作。它可以基于时钟信号或其他周期性信号来工作&#xff0c;并且可以用来测量时间间隔、生成延时、触发中断等。 时钟信号 时钟信号是一种周期性的电信号&#xff0c;用于同步电路中…

如何检查端口占用:netstat和lsof指令

在网络故障排查和系统管理中&#xff0c;检查端口占用情况是一项常见且重要的任务。本文将详细介绍如何使用 netstat 和 lsof 这两个强大的工具来检查端口占用和相关服务。 1. 使用 netstat 查看端口占用 netstat (network statistics) 是一个用于显示网络连接、路由表、接口…