软件开发目录规范、python常用内置模块
编程思想的转变
1.面条版阶段
所有的代码全部堆叠在一起。可以看成是直接将所有的数据放在C盘
视频、音频、文本、图片
2.函数版阶段
根据功能的不同封装不同的函数。可以看成是将C盘下的数据分类管理
视频文件夹、音频文件夹、文本文件夹、图片文件夹
3.模块版阶段
根据功能的不同拆分成不同的py文件。可以看成是将C盘下的数据根据功能的不同划分到更合适的位置
系统文件夹 C盘、视频文件夹 D盘、图片文件夹 E盘
- ps:类似于开公司(小作坊>>>小公司>>>上市公司)
-
目的:更方便快捷高效的管理资源
为了提高程序的可读性和可维护性,我们应该为软件设计良好的目录结构,这与规范的编码风格同等重要。软件的目录规范并无硬性标准,只要清晰可读即可。
目录的规范优点
1.可读性高: 不熟悉这个项目的代码的人,一眼就能看懂目录结构,知道程序启动脚本是哪个,测试目录在哪儿,配置文件在哪儿等等。从而非常快速的了解这个项目。
2.可维护性高: 定义好组织规则后,维护者就能很明确地知道,新增的哪个文件和代码应该放在什么目录之下。这个好处是,随着时间的推移,代码/配置的规模增加,项目结构不会混乱,仍然能够组织良好。
文件分类详细
1.bin文件夹:
- 用于存储程序的启动文件
>>>>>start.py 启动文件可以放在bin目录下,也可以直接在项目根目录
2.conf文件夹:
- 用于存储程序的配置文件
settings.py 里面存放项目的默认配置,一般都是全大写
3.core文件夹:
- 用于存储程序的核心逻辑
src.py 里面存放项目核心功能
4.lib文件夹:
- 用于存储程序的公共功能
common.py
5.db文件夹:
- 用于存储程序的数据文件
userinfo.txt
db_handler.py 存放数据库操作相关的代码
6.log文件夹:
- 用于存储程序的日志文件
log.log
7.interface文件夹:
- 用于存储程序的接口文件
user.py order.py goods.py
8.README文件(文本文件):
- 用于存储程序的说明、介绍、广告(类似于产品说明书)
9.requirements.txt文件:
- 用于存储程序所需的第三方模块名称和版本
补充
README文件说明
-
README文件是每个项目都应该有的一个文件
-
目的:能简要描述该项目的信息,让读者快速了解这个项目
-
需要说明以下几个事项:
- 软件定位,软件的基本功能
- 运行代码的方法:安装环境、启动命令等
- 简要的使用说明
- 代码目录结构说明,更详细点可以说明软件的基本原理
- 常见的问题说明
requirements.txt文件说明
- 这个文件的存在是为了方便开发者,维护软件的依赖库,我们需要的第三方库都可以写进去,pycharm非常智能,会通过识别版本号以及包名导入,这样也方便我们查看使用了哪些python包。
注意:在编写软件的时候,可以不完全遵循上面的文件名
- start.py可以放在bin文件夹下也可以直接放在项目根目录下
- db文件夹等学到真正的项目会被数据库软件替代
- log文件夹等学到真正的项目会被专门的日志服务替代
在内置数据类型(dict、list、set、tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter、deque、defaultdict、namedtuple和OrderedDict等。
- namedtuple:具名元组,生成可以使用名字来访问元素内容的元组
- deque:双端队列,可以快速的从另一侧追加和推出对象
- Counter:计数器,主要用来计数
- OrderedDict:有序字典
- defaultdict:带有默认值的字典
namedtuple
from collections import namedtuple point = namedtuple('二维坐标系',['x','y']) p1 = point(1, 3) print(p1) # 二维坐标系(x=1, y=3) print(p1.x) # 1 print(p1.y) # 3 point = namedtuple('三维坐标系',['x', 'y', 'z']) p2 = point(2, 5, 6) print(p2) # 三维坐标系(x=2, y=5, z=6) print(p2.x) # 2 print(p2.y) # 5 print(p2.z) # 6 c = namedtuple('扑克牌', ['花色', '点数']) c1 = c('♥', 'A') c2 = c('♠', 'A') print(c1) # 扑克牌(花色='♥', 点数='A') print(c2) # 扑克牌(花色='♠', 点数='A')
deque
使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。
deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:
from collections import deque q = deque() q.append(111) q.append(222) q.append(333) print(q) # deque([111, 222, 333]) q.appendleft(555) print(q) # deque([555, 111, 222, 333])
deque除了实现list的append()
和pop()
外,还支持appendleft()
和popleft()
,这样就可以非常高效地往头部添加或删除元素。
Counter
Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数)。Counter类和其他语言的bags或multisets很相似。
例:统计字符串中每个字母出现的次数:
s = 'abccbbbacaacbcab'
方法1:
s = 'abccbbbacaacbcab' d = {} for i in s: if i not in d: d[i] = 1 else: d[i] += 1 print(d) # {'a': 5, 'b': 6, 'c': 5}
方法2:
from collections import Counter s = 'abccbbbacaacbcab' print(Counter(s)) # Counter({'b': 6, 'a': 5, 'c': 5})
OrderedDict
使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序。
如果要保持Key的顺序,可以用OrderedDict
:
from collections import OrderedDict d = dict([('a', 1), ('b', 2), ('c', 3)]) print(d) # {'a': 1, 'b': 2, 'c': 3} od = OrderedDict([('a', 1), ('b', 2), ('c', 3)]) print(od) # OrderedDict([('a', 1), ('b', 2), ('c', 3)])
defaultdict
defaultdict是对Python中字典dict的改善
如果是字典dict:用法是dict={},
添加元素是dict[element]=value
调用是dict[element]
但是前提是element是存在于字典的,不然会报错误KeyError错误。
对于这种情况,defaultdict就可以避免这个错误,defaultdict的作用是在于,当字典里的element不存在但被查找时,返回的不是keyError而是一个默认值。
例:有一个列表:l1 = [11, 22, 33, 44, 55, 66, 77, 88, 99],将所有小于60的数保存到字典的第一个键中,将所有小于60的数保存到字典的第二个键中,即{'k1': 小于60的数,'k2': 大于60的数}
方法1:
l1 = [11, 22, 33, 44, 55, 66, 77, 88, 99] d1 = {'k1':[], 'k2': []} for i in l1: if i < 60: d1.get('k1').append(i) else: d1.get('k2').append(i) print(d1) # {'k1': [11, 22, 33, 44, 55], 'k2': [66, 77, 88, 99]}
方法2:(用得不多)
from collections import defaultdict res = defaultdict(k1=[i for i in l1 if i < 66], k2=[i for i in l1 if i >= 66]) print(res) # defaultdict(None, {'k1': [11, 22, 33, 44, 55], 'k2': [66, 77, 88, 99]})
使用dict
时,如果引用的Key不存在,就会抛出KeyError
。如果希望key不存在时,返回一个默认值,就可以用defaultdict
:
from collections import defaultdict d = defaultdict(lambda: 'N/A') d['key1'] = 'abc' print(d['key1']) # key1存在 'abc' print(d['key2']) # key2不存在,返回默认值 'N/A'
import time # 导入时间模块 time.time() # 时间戳 print(time.time()) # 1666168231.4251723
2. 结构化时间(主要给计算机看的,用得少)
3. 格式化时间
-
time.strftime()
-
格式化符号:"%Y-%m-%d %H:%M:%S" 或 "%Y-%m-%d %X"
import time # 导入时间模块 print(time.strftime('%Y-%m-%d %H:%M:%S')) # 2022-10-19 16:38:09 print(time.strftime('%Y-%m-%d %X')) # 2022-10-19 16:38:09
几种时间之间的相互转换
datetime模块
import datetime # 导入datetime模块 print(datetime.datetime.now()) # 获取当前时间 2022-10-19 16:53:26.651335 print(datetime.datetime.today()) # 获取当前时间 2022-10-19 16:53:26.651335 print(datetime.date.today()) # 获取当前日期 2022-10-19
from datetime import date, datetime # 导入模块 print(date.today()) # 获取当前日期 2022-10-19 print(datetime.today()) # 获取当前时间 2022-10-19 16:58:13.340812
指定日期时间
c = datetime.datetime(2017, 5, 23, 12, 20) # print('指定日期:',c) # 指定日期: 2017-05-23 12:20:00
把不规则的时间转化为固定的格式
from datetime import datetime d=datetime.strptime('2017/9/30','%Y/%m/%d') print(d) # 2017-09-30 00:00:00 e=datetime.strptime('2017年9月30日星期六','%Y年%m月%d日星期六') print(e) # 2017-09-30 00:00:00 f=datetime.strptime('2017年9月30日星期六8时42分24秒','%Y年%m月%d日星期六%H时%M分%S秒') print(f) # 2017-09-30 08:42:24
设置距离当前几天之后的时间
import datetime # 导入模块 time1 = datetime.date.today() # 设置当前模块 print(time1) d_time = datetime.timedelta(days=3) # 设置时间差值 print(time1 + d_time) # 打印距离当前时间3天以后的时间
import datetime # 导入模块 time1 = datetime.date.today() # 设置当前模块 print(time1) # 2022-10-19 d_time = datetime.timedelta(days=3) # 设置时间差值 print(time1 + d_time) # 打印距离当前时间3天以后的时间 # 2022-10-22 time2 = datetime.datetime.today() # 设置当前模块 print(time2) # 2022-10-19 17:22:55.336720 d_time = datetime.timedelta(minutes=20) # 设置时间差值 print(time2 + d_time) # 打印距离当前时间20分钟以后的时间 # 2022-10-19 17:42:55.336720
import random print(random.random()) # 随机产生一个0-1之间的小数 0.4885910693172658 print(random.randint(1, 10)) # 随机产生一个1-10之间的整数 9 print(random.randrange(1,10, 2)) # 随机产生一个1-10之间的数,指定步长 3 print(random.choice(['一等奖', '二等奖', '三等奖', '谢谢惠顾'])) # 随机产生一个选项 一等奖 print(random.sample(['Alex', 'Bob', 'Cindy', 'Tony', 'Jason'], 2)) # 随机获取指数个数的样本 ['Alex', 'Bob'] l1 = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K', 'A'] random.shuffle(l1) # 随机打乱数据集 print(l1) # ['Q', 10, 9, 'J', 2, 3, 4, 5, 'A', 6, 'K', 8, 7]
小练习:
随机产生4位的图片验证码: 每一位都可以是大写字母、小写字母、数字 (搜狗公司的一道笔试题)
# 3. 循环取4次 for i in range(4): # 1. 先产生随机的大写字母、小写字母、数字 random_upper = chr(random.randint(65,90)) random_lower = chr(random.randint(97, 122)) rand_int = str(random.randint(0, 9)) # 2. 随机三选一 temp = random.choice([random_upper, random_lower,rand_int]) print(temp,end='')
拔高:如果要随机产生不同位数的验证码呢:
>>>考虑函数传参:
def get_code(n): code = '' # 3. 循环取4次 for i in range(n): # 1. 先产生随机的大写字母、小写字母、数字 random_upper = chr(random.randint(65,90)) random_lower = chr(random.randint(97, 122)) rand_int = str(random.randint(0, 9)) # 2. 随机三选一 temp = random.choice([random_upper, random_lower,rand_int]) code += temp return code res = get_code(5) # 5位验证码,参数设置为5 print(res) res = get_code(10) # 10位验证码,参数设置为10 print(res)