从Python代码到诗

在这里插入图片描述

🐳序言

  在Python社区,没有强制的编码标准,这虽然赋予了开发者更多的自由,但也导致代码风格不一致性。使得部分代码变得晦涩难懂,本文将探讨一系列的开发技巧和最佳实践,开发出优雅的Python脚本。

1、参数接收与校验

argparse模块可以使用标准的命令行界面风格解析命令行参数,支持位置参数和可选参数,使用-h可查看脚本使用说明。

1.1 ArgumentParser常用属性

字段说明备注
name参数名称或选项例如:-file、–file
default默认值
type类型
choices可选值列表
required是否必传默认为False
nargs参数的数量默认为None,支持int,+,*
metavar帮助信息显示参数的名字
action动作支持store_true、store_false等
help帮助信息

1.2 获取位置参数

使用位置参数我们可以处理n多个值,输出列表

# python main.py 3 5import argparseparser = argparse.ArgumentParser(description="位置参数测试")
parser.add_argument("number", type=int, nargs="*", help="传入数字")args = parser.parse_args()# [3, 5]
print(args.number)

1.3 获取可选参数

使用可选参数可以避免传入位置不准确的问题

# python main.py --name '欢颜' --datatime '2023-08-18 13:14:52' --is_worktimeimport argparsefrom datetime import datetimeclass ParserArgs:def __init__(self):parser = argparse.ArgumentParser(description='从Python代码到诗')parser.add_argument('--name', type=str, required=True, help='输入名称')parser.add_argument('--datetime', type=self.validate_dt, required=True, help='日期时间(YYYY-MM-DD HH:MM:SS)')parser.add_argument('--is_worktime', action='store_true', help='是否在工作时间')self.args = parser.parse_args()@staticmethoddef validate_dt(dt_str, fmt_dt='%Y-%m-%d %H:%M:%S'):try:dt_obj = datetime.strptime(dt_str, fmt_dt)except ValueError:raise argparse.ArgumentTypeError("Invalid datetime format.")else:return dt_obj# Namespace(name='欢颜', datetime=datetime.datetime(2023, 8, 17, 0, 0), is_worktime=True)
Args = ParseArgs().args

2、日志记录器

​ 项目开发中应避免直接使用print函数,日志记录能够更好地管理和调试代码、故障排除以及监控程序的运行状态。Python内置了logging 模块,用于创建日志记录器,实现灵活的日志记录和输出控制,通常将日志直接写入文件,输出更加优雅。

2.1 日志简单使用

#!/usr/bin/env python3
# -*-coding:utf-8 -*-import loggingdef get_logger():# 实例化日志对象logger = logging.getLogger()logger.setLevel(logging.INFO)ch = logging.StreamHandler()formatter = logging.Formatter("[%(asctime)s] [%(levelname)s] [%(filename)s] [%(funcName)s:%(lineno)d] %(message)s", "%Y-%m-%d %H:%M:%S")ch.setFormatter(formatter)logger.addHandler(ch)return loggerlogger = get_logger()# [2023-08-18 16:40:07] [INFO] [main.py] [main:27] hello world!
logger.info("hello world!")

3、进度条的使用

  在命令行界面中展示进度条,以增强长时间运行的循环、任务或操作的可视化体验。Python的tqdm库,可以非常方便地应用于各种迭代操作,从文件读写到数据处理,都能通过进度条的方式直观地显示进度。

3.1 tqdm方法常用参数

参数含义类型必填备注
iterableIterable 用进度条装饰iterable可选可迭代对象
total预计迭代的次数int/float可选默认为迭代器的长度
ncols整个输出消息的宽度int可选
mininterval最小进度显示更新间隔float可选默认0.1s
ascii进度填充bool可选默认unicode平滑块来填充仪表
unit单位str可选默认为it
color条形颜色str可选
initial初始计数器值int/float可选

3.2 trange方法

trange方法是封装了range方法的tqdm, 它会在循环中显示进度条、多用于循环次数固定的情况。

import timefrom tqdm import trangefor _ in trange(10):time.sleep(0.1)

3.3 tqdm方法

tqdm是tqdm模块最常用的方法,用于在循环中显示进度条。传递一个迭代对象给它,然后迭代这个对象,会产生一个进度条。

import timefrom tqdm import tqdm
from colorama import Fore, Styleiterable = ['Python', 'GoLang', 'Java', 'JavaScript']
progress_bar = tqdm(iterable, ncols=100, ascii=False)
for element in progress_bar:progress_bar.set_description("{}正在处理:{}".format(Fore.LIGHTBLUE_EX, element))time.sleep(0.5)

4、测试函数执行时间

  Python关于计时比较有代表性的两个库是timetimeittime库中有time()perf_counter()以及process_time()三个函数可用来计时(以秒为单位),加后缀_ns表示以纳秒计时。上述三者的区别如下:

  • time()精度上相对没有那么高,而且受系统的影响,适合表示日期时间或者大程序的计时。
  • perf_counter()适合小一点的程序测试,会计算sleep()时间。
  • process_time()适合小一点的程序测试,不计算sleep()时间。

time库相比,timeit 有两个优点:

  • timeit 会根据您的操作系统和 Python 版本选择最佳计时器。
  • timeit 在计时期间会暂时禁用垃圾回收。

4.1 使用time计时

import timedef statistic_cost(func):def wrapper(*args, **kwargs):start_time = time.time()result = func(*args, **kwargs)cost = time.time() - start_timelogger.info(f"execute {func.__name__} cost {cost:.3f} 秒")return resultreturn wrapperdef test():time.sleep(3)if __name__ == '__main__':test()

4.2 使用timeit

"""
timeit方法参数:stmt: 需要计时的语句或者函数
setup: 执行stmt之前要运行的代码。通常,它用于导入一些模块或声明一些必要的变量。
timer: 计时器函数,默认为time.perf_counter()。
number: 执行计时语句的次数,默认为一百万次。
globals: 指定执行代码的命名空间。
"""import time
from timeit import timeitdef test():time.sleep(3)if __name__ == '__main__':cost = timeit(test, number=1)print(cost)

5、使用装饰器缓存

  Python支持装饰器缓存,在内存中维护特定类型的缓存,以实现最佳软件驱动速度,使用lru_cache来实现。lru_cache 的性能优势在于重复性高、计算密集型的函数。在一些情况下,使用缓存可能会导致额外的内存使用,因为缓存会保留一部分函数调用的结果。因此,应根据具体情况权衡是否使用缓存。对于需要实时更新或频繁变动的数据,lru_cache 并不适用。它适用于那些函数的计算结果在短时间内保持一致的场景。

5.1 缓存简单使用

#!/usr/bin/env python3
# -*-coding:utf-8 -*-
# maxsize: 指定缓存中保留的最大函数调用结果数量。当超过数量,最早的结果将被移除,默认为128。
# typed: 如果设置为True,则不同类型的参数会被视为不同的参数。import functools@functools.lru_cache(maxsize=128)
def fibonacci(n):if n == 0:return 0elif n == 1:return 1return fibonacci(n - 1) + fibonacci(n - 2)# 从获取相同
for _ in range(10):fibonacci(10)

5.2 缓存强制刷新

  lru_cache函数不支持主动刷新的功能, 缓存的更新是由缓存装饰器内部的缓存策略自动管理的,通常是根据函数的参数和调用次数来决定哪些缓存条目会被保留或淘汰。如果需要在特定时刻主动刷新缓存, 可以使用cache_clear() 方法强制清除缓存中的所有条目,从而让缓存失效,下次访问时会重新计算。你可以在数据发生变动时调用此方法。

# 以上面计算斐波那契函数为例# 强制清除缓存
fibonacci.cache_clear()

6、单元测试

本文使用unittest编写单元测试

  单元测试是软件开发过程中的一个关键环节,旨在验证代码中的最小功能单元是否按预期工作。通过编写单元测试,你可以有效地发现和修复代码中的错误,确保代码在不同情况下都能正确运行。在Python中有多个测试框架可以选择unittest、pytest和nose等。

6.1 单元测试简单使用

6.1.1 编写一个函数用于测试
import functools@functools.lru_cache(maxsize=128)
def fibonacci(n):if n < 0:raise ValueError('Invalid Value')elif n in (0, 1):return nreturn fibonacci(n - 1) + fibonacci(n - 2)
6.1.2 使用unittest完成测试
import unittestfrom script import main as algclass TestFibonacci(unittest.TestCase):def test_fibonacci(self):output = alg.fibonacci(10)self.assertEqual(output, 55)def test_fibonacci_invalid(self):with self.assertRaises(ValueError):alg.fibonacci(-1)if __name__ == '__main__':unittest.main()

6.2.1 模拟对象

  模块unittest.mock提供了两个主要的类来进行模拟和断言行为(Mock和MagicMock),Mock通常用于模拟普通方法和属性,MagicMock具有更多的魔法方法,允许一些特殊的Python行为,如迭代,上下文管理等,返回自身。

对以下函数进行测试

ParserArgs对象在参数接收于校验模块

import time
from colorama import Forefrom logger import logger
from parser_args import ParserArgsdef launch():args = ParserArgs().argslogger.info(f"input args: {args.__dict__}")iterable = ['Python', 'GoLang', 'Java', 'JavaScript']progress_bar = tqdm(iterable, ncols=100, ascii=False)for element in progress_bar:progress_bar.set_description("{}正在处理:{}".format(Fore.LIGHTBLUE_EX, element))return Trueif __name__ == '__main__':launch()

模拟获取参数的行为

替换ParserArgs的参数为mock对象

import argparse
import unittest
from unittest.mock import patchfrom script import main as algclass TestParserArgs(unittest.TestCase):def setUp(self) -> None:self.mock_args = argparse.Namespace(name='欢颜',datetime='2023-05-20 13:14:00',is_worktime=True)@patch('script.main.ParserArgs')def test_launch(self, mock_parser_args):parser_args_obj = mock_parser_args.return_valueparser_args_obj.args = self.mock_argsoutput = alg.launch()expect = Trueself.assertEqual(output, expect)if __name__ == '__main__':unittest.main()

7、包的构建与分发

7.1 打包程序为可执行文件(EXE)

  可以使用pyinstaller将单文件应用或多文件应用,打包为exe可执行文件,需要编译作为程序入口的文件即可。

7.1.1 打包应用程序

pip3 install pyinstaller

# pyinstaller -F app.pydef main():print('程序开始执行')if __name__ == '__main__':main()
7.2.2 Pyinstaller常用选项
-h帮助信息
-F产生单个的可执行文件
-D产生一个目录(包含多个文件)作为可执行程序
-a不包含 Unicode 字符集支持
-d产生 debug 版本的可执行文件
-w指定程序运行时不显示命令行窗口(仅对 Windows 有效)
-c指定使用命令行窗口运行程序(仅对 Windows 有效)
-o指定 spec 文件的生成目录。如果没有指定,则默认使用当前目录来生成 spec 文件
-p设置 Python 导入模块的路径
-n指定项目名字。如果省略该选项,那么第一个脚本的主文件名将作为 spec 的名字

7.2 使用setuptools构建包

7.2.1 创建合适的项目结构
# 一个最简单的项目结构
pkgs/
├── LICENSE       # 许可证文件
├── main.py       # 入口文件
├── app           # 存放子文件等
├── README.md     # 应用文档
└── setup.py      # 用于构建、安装和分发包的脚本文件
7.2.2 编写setup文件

一个最简单的setup示例

from setuptools import setup, find_packagessetup(name='PkgName',version='0.1',description='描述信息',author='Your Name',packages=find_packages(),install_requires=[# 依赖项列表],
)
7.2.3 构建包

  在项目根目录中运行python setup.py sdist生成源分发包,也可以生成二进制分发包bdist_wheel。然后可以将包发布到Python包索引(PyPI),这需要在PyPI上创建一个帐户,并使用工具如twine来上传包(twine upload dist/*)。

7.2.4 分发包

  您可以通过以下方式分享生成的分发包,将其发布到代码托管平台如GitHub,上传至内部或外部的PyPI服务器,或者使用pip来进行安装包。

🧀 小结

  编写一个优雅的Python脚本关键在于遵循Python的最佳实践和编码规范(PEP8),以确保代码风格一致性和可读性。使用有意义的命名、拆分代码块成小函数、适度添加注释和文档、合理处理异常、充分利用Python的内置函数和模块、避免滥用全局变量、保持模块化和可重用性、采用测试驱动开发等方法,有助于编写出清晰、可维护、优雅的Python脚本,提高代码质量和可维护性。以上是笔者开发过程中经常使用的一些小Tips,在这里记录分享,当然,我没还可以使用pandas,numpy等工具处理数据,提高脚本执行效率等…

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

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

相关文章

ElasticSearch(三)

1.数据聚合 聚合&#xff08;aggregations&#xff09;可以让我们极其方便的实现对数据的统计、分析、运算。例如&#xff1a; 什么品牌的手机最受欢迎&#xff1f; 这些手机的平均价格、最高价格、最低价格&#xff1f; 这些手机每月的销售情况如何&#xff1f; 实现这些…

laravel框架 - 消息队列如何使用

业务场景&#xff1a;项目里边有很多视频资源需要上传到抖音资源库&#xff0c;通过队列一条一条上传。 参考实例&#xff1a;发送邮件&#xff0c;仅供参考 (1)创建任务【生成任务类】 在你的应用程序中&#xff0c;队列的任务类都默认放在 app/Jobs 目录下。如果这个目录不存…

解决ubuntu系统python2.7安装uwsgi报错

背景 因为项目老旧&#xff0c;仍需使用python2.7&#xff0c;仍需要使用pip2 安装依赖。在安装uwsgi的时候&#xff0c;报错。 错误一 Building wheel for uwsgi (setup.py) ... error ERROR: Command errored out with exit status 1: command: /usr/bin/python2 -u -…

vulhub打靶第三周

第三周 靶机下载地址&#xff1a;https://www.vulnhub.com/entry/chronos-1,735/ 环境折磨导致做晚了&#xff0c;再加上期末的考试多耽搁下来了&#xff0c;然后就是辗转反侧打比赛&#xff0c;拖了这么久&#xff0c;时隔三个月重新开打 因为陆陆续续打了两次&#xff0c;所…

[winerror 5] 拒绝访问。: ‘..\\data‘解决方案

使用Jupyter Notebook学习深度学习时出现错误如下&#xff1a;[winerror 5] 拒绝访问。: ‘…\data’ 解决方法&#xff1a; 打开anaconda3找到对应环境的python.exe 点开属性&#xff0c;点安全&#xff0c;选择如下&#xff1a; 点编辑&#xff0c;选择User&#xff0c;勾…

9、DVWA——XSS(Stored)

文章目录 一、存储型XSS概述二、low2.1 源码分析2.2 通关分析 三、medium3.1 源码分析3.2 通关思路 四、high4.1 源码分析4.2 通关思路 一、存储型XSS概述 XSS&#xff0c;全称Cross Site Scripting&#xff0c;即跨站脚本攻击&#xff0c;某种意义上也是一种注入攻击&#xff…

李航老师《统计学习方法》第1章阅读笔记

1.1 统计学习 统计学习的特点 统计学习&#xff1a;计算机基于数据构建概率统计模型并运用模型对数据进行预测与分析 现在人们提及机器学习时&#xff0c;往往指统计机器学习&#xff0c;所以可以认为本书介绍的是机器学习方法 统计学习的对象 统计学习研究的对象是数据(data)…

《Web安全基础》09. WAF 绕过

web 1&#xff1a;基本概念1.1&#xff1a;DoS & DDos1.2&#xff1a;CC 攻击1.3&#xff1a;扫描绕过方式 2&#xff1a;WAF 绕过2.1&#xff1a;信息收集阶段2.2&#xff1a;漏洞发现阶段2.3&#xff1a;权限控制阶段2.3.1&#xff1a;密码混淆2.3.2&#xff1a;变量覆盖…

解决方案:TSINGSEE青犀+智能分析网关助力智慧仓储智能化监管

为全面保障物流仓储的安全性与完整性&#xff0c;解决仓库管理难题&#xff0c;优化物流仓储方式&#xff0c;提升仓储效率&#xff0c;降低人工成本&#xff0c;旭帆科技推出智慧仓储AI视频智能分析方案&#xff0c;利用物联网、大数据、云计算等技术&#xff0c;对仓储管理进…

IDEA2023新UI回退老UI

idea2023年发布了新UI&#xff0c;如下所示 但是用起来真心不好用&#xff0c;各种位置也是错乱&#xff0c;用下面方法可以回退老UI

【轨道机器人】成功驱动伺服电机(学生电源、DCH调试软件、DH系列伺服驱动器)

1、硬件平台 工控机 学生电源 DH系列伺服驱动器 电机 调试平台&#xff1a;DCH 2、如何利用dch驱动电机 点击可驱动电机 下面的步骤是比较关键的几步&#xff1a; 3、遇到的问题 不能成功驱动电机&#xff0c;还和厂家那边打电话&#xff0c;询问 发现是这…

JavaScript简介引入方式(JavaScript基础语法、JavaScript对象、BOM、DOM、事件监听)

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 Redis 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 JavaScript简介&引入方式 简介&#xf…

智能生活从这里开始:数字孪生驱动的社区

数字孪生技术&#xff0c;这个近年来备受瞩目的名词&#xff0c;正迅速渗透到社区发展领域&#xff0c;改变着我们居住的方式、管理的方式以及与周围环境互动的方式。它不仅仅是一种概念&#xff0c;更是一种变革&#xff0c;下面我们将探讨数字孪生技术如何推动社区智能化发展…

基于微服务的第二课堂管理系统(素质拓展学分管理平台)SpringCloud、SpringBoot 分布式,微服务

基于微服务的第二课堂管理系统 一款真正的企业级开发项目&#xff0c;采用标准的企业规范开发&#xff0c;有项目介绍视频和源码&#xff0c;需要学习的同学可以拿去学习&#xff0c;这是一款真正可以写在简历上的校招项目&#xff0c;能够真正学到东西的一个项目&#xff0c;话…

基于springboot高校场馆预订系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

重新认识架构—不只是软件设计

前言 什么是架构&#xff1f; 通常情况下&#xff0c;人们对架构的认知仅限于在软件工程中的定义&#xff1a;架构主要指软件系统的结构设计&#xff0c;比如常见的SOLID准则、DDD架构。一个良好的软件架构可以帮助团队更有效地进行软件开发&#xff0c;降低维护成本&#xff0…

Leetcode171. Excel 表列序号

给你一个字符串 columnTitle &#xff0c;表示 Excel 表格中的列名称。返回 该列名称对应的列序号 。 例如&#xff1a; A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 ... 题解&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱…

mysqld_exporter监控MySQL服务

一、MySQL授权 1、登录MySQL服务器对监控使用的账号授权 CREATE USER exporterlocalhost IDENTIFIED BY 123456 WITH MAX_USER_CONNECTIONS 3; GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO exporterlocalhost; flush privileges;2、上传mysqld_exporter安装包&#…

Spring boot原理

起步依赖 Maven的传递依赖 自动配置 Springboot的自动配置就是当spring容器启动后&#xff0c;一些配置类、bean对象就自动存入到IOC容器中&#xff0c;不需要我们手动去声明&#xff0c;从而简化了开发&#xff0c;省去了繁琐的配置操作。 自动配置原理&#xff1a; 方案一…

MongoDB(一) windows 和 linux 之 Ubuntu 安装

数据库分类 一、关系型数据库&#xff08;RDBMS&#xff09; mysql 、Oracle、DB2、SQL Server 关系数据库中全都是表 二、非关系型数据库&#xff08;NO SQL&#xff09; MongoDB、Redis 键值对数据库 文档数据库MongoDB 下载 mongoDB https://www.mongodb.com/try/downloa…