以ATM购物车为例来介绍软件目录开发规范
1.什么是软件目录开发规范?
在我们学过了模块和包之后就可对编写好的代码进行整理了,因为模块和包都有对代码有很好地整理效果,软件目录开发规范就是基于模块和包的作用原理上对代码进行更近一部的整理,让代码整体看起来比较规范和标准.
2.什么时候需要使用软件目录发规范
在一个项目功能代码比较多,模块化之后还是觉得模块很混乱的时候,就需要使用软件目录开发规范对项目的代码进行整理了
软件的目录规范示例:
在这里对目录规范里每个文件夹进行简单的介绍:
soft:项目的根目录
bin:可执行文件,一般软件的启动文件会存放在这里,(类似于xxxlauncher,或者其他的启动方式)
conf(config):存放项目的配置信息的文件夹
core:存放项目主要逻辑体代码的文件夹
db(datebasic):存放数据文件的信息
lib(library):库(一般python中pip下载的第三方模块都存放在lib文件夹中,这也是在sys.path中第二个就是lib的文件夹的原因)多以 在lib中一般存放公共代码(这里的公共代码指一些比较常用的功能或者工具代码)
log:日志文件夹(用来存放日志信息,例如程序的报错信息,记录用户的操作信息等日志行为的文集)
一般除了这几个文件还会有一个Readme的文件,这个文件是个说明文档,对项目进行简单的介绍和操作
2.怎么使用软件目录开发
在这里以ATM购物车的项目为例介绍软件目录开发规范:
首先编写ATM:
整体逻辑:
# 主程序接口
# 购物中心================================================================================================
# 购物
def shopping():
print('shopping')
# 查看购物车
def shop_car():
print('shop_car')
#结算
def payment():
print('payment')
#清空购物车
def clear_shopcar():
print("clear_shopcar")
# 购物车接口
def shopping_center():
while True:
print('''
1.购物
2.查看购物车
3.结算
4.清空购物车
''')
admin_func = {'1': shopping, '2': shop_car, '3': payment, '4': clear_shopcar}
choice = input('请选择功能(q退出)>>:').strip()
if choice == 'q':
return
elif not choice.isdigit():
print('输入错误,请重试')
continue
elif choice in admin_func:
admin_func[choice]()
continue
else:
print('输入有误请重试')
return
# 购物中心==================================================================================================
# ATM========================================================================================================
# 登录
def atm_login():
print('login')
# 提现
def withdraw():
print('withdraw')
# 还款
def repayment():
print('repayment')
# 转账
def transfer():
print('transfer')
# 结算
def pay():
print('pay')
# atm 接口
def atm():
while True:
print('''
1.登录
2.提现
3.还款
4.转账
''')
admin_func = {'1': atm_login, '2': withdraw, '3': repayment, '4': transfer}
choice = input('请选择功能(q退出)>>:').strip()
if choice == 'q':
return
elif not choice.isdigit():
print('输入错误,请重试')
continue
elif choice in admin_func:
admin_func[choice]()
continue
else:
print('输入有误请重试')
return
# ATM==========================================================================================================
# 账户操作
# 读取所有用户到内存中user_data
user_data = []
file_path = 'user_db.txt'
def load_users():
with open(r'%s'%file_path,'rt',encoding='utf-8')as f:
for line in f:
l = line.strip('\n')
users = l.split('|')
user_data.append({'name':users[0],
'pwd': users[1],
'max': users[2],
'money': users[3],
'lock': users[4],
})
return user_data
# 信息持久化存储
def save_userinfo():
with open(r'%s' % file_path, 'wt', encoding='utf-8')as f:
for line in user_data:
user_info ='|'.join(line.values())
user_info +='\n'
f.write(user_info)
return
#日志的记录
def logger(msg):
with open('log.txt','at',encoding='utf-8') as f:
# 管理员登录================================================================================================
# 创建账户:
def add_usr():
print('add_usr')
# 修改额度
def modify_amount():
print('modify_amount')
# 冻结账户
def lock_usr():
print('lock')
# 解冻账户
def unlock_usr():
print('UNlock')
def admin_login():
while True:
adname = input('请输入管理员账号:').strip()
adpwd = input('请输入管理员密码>>:').strip()
if adname == 'admin' and adpwd == '123':
print('管理员登录成功')
while True:
print('''
1.创建账户
2.修改额度
3.冻结账户
4.解冻账户
''')
admin_func = {'1':add_usr , '2': modify_amount, '3':
lock_usr,'4':unlock_usr}
choice = input('请选择功能(q退出)>>:').strip()
if choice == 'q':
return
elif not choice.isdigit():
print('输入错误,请重试')
continue
elif choice in admin_func:
admin_func[choice]()
continue
else:
print('输入有误请重试')
return
# 管理员登录==========================================================================
# 主程序入口
def run():
while True:
print('''
1.购物中心
2.ATM
3.管理员登录
''')
func = {'1':shopping_center,'2':atm,'3':admin_login}
choice = input('请选择功能(q退出)>>:').strip()
if choice == 'q':
return
elif not choice.isdigit():
print('输入错误,请重试')
continue
elif choice in func:
func[choice]()
continue
else:
print('输入有误请重试')
return
run()
这样写出来,如果把整个项目写完,代码将会非常多,对开发者的管理和维护带来即极大的不便,这个时候就需要用今天所讲的项目目录开发规范了,使用目录开发规范,将整个项目中的各个部分放到不同的文件夹里边,很大程度上解决了开发者后期对程序的管理和维护,在用户的角度上来讲,用户运行相关的软件的时候,根本不需要知道这个软件的是怎么开发出来的,他只需要运行软件的启动器,知道软件有什么功能,每个功能怎么使用能给使用者带来什么体验就好了,所以作为开发者来讲,有一定的目录开发规范是非常有必要的,不但解决了程序的开发和维护,也使得应用程序的移植性大大提高,下面讲一下具体如何使用项目目录开发规范来规范程序代码:
首先要明白在上面的代码中各个函数的功能和整个项目的逻辑体系,然后以此来将项目中个函数按照功能类别有序的进行分类,最后按照项目目录开发规范使得程序代码规范化和标准化
2.程序代码规范后,各个模块之间的调用
在规范化的过程中将各个功能分好之后,在模块中对其他功能的调用是一个需要重点掌握的点
要明确项目的根目录在哪里,然后将项目的根目录添加到sys.path中,这样就可以在各个文件夹中任意的对其他模块进行调用
首先通过__file__来获取bin目录下执行文件的绝对路径,在项目中每个模块按照规范放到相应的文件夹中之后,位置一般是比较固定的,所以只需要获取到项目的根目录并将其添加到sys.path中即可,这样就可以对根目录下各个文件夹中的模块进行调用了
添加项目根目录到sys.path中的方法:
1.使用os模块的功能
具体办法:使用os.path.dirname(__file__)获取当前执行文件所在的文件夹路径
在使用一次获得上一级的文件夹所在路径,即bin所在的项目根目录.然后将其添加到sys,path中即可
下面开始介绍常用模块的常用功能:
time模块(对时间的一系列操作)
1.时间戳(time.time()):通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。
2.格式化的字符串时间(time.strftime("%Y-%m-%d %X"))
3.结构化的时间:struct_time元组共有9个元素 共九个元素:(年、月、日、时、分、秒、一年中的第几周、一年中的第几天、夏令时) 结构化的时间(本地时区的struct_time>>>time.localtime()) UTC(世界统一时间)时区的struct_time>>>time.gmtime()
import time
#--------------------------我们先以当前时间为准,快速认识三种形式的时间
print(time.time()) # 时间戳:1539696997.584178
print(time.strftime("%Y-%m-%d %X")) #格式化的时间字符串:'2018-10-16 21:37:10'
print(time.localtime()) #本地时区的struct_time
输出:time.struct_time(tm_year=2018, tm_mon=10, tm_mday=16, tm_hour=21, tm_min=37, tm_sec=10, tm_wday=1, tm_yday=289, tm_isdst=0)
print(time.gmtime()) #UTC时区的struct_time
输出:time.struct_time(tm_year=2018, tm_mon=10, tm_mday=16, tm_hour=13, tm_min=37, tm_sec=10, tm_wday=1, tm_yday=289, tm_isdst=0)
格式化字符串的时间格式
%a Locale’s abbreviated weekday name.
%A Locale’s full weekday name.
%b Locale’s abbreviated month name.
%B Locale’s full month name.
%c Locale’s appropriate date and time representation.
%d Day of the month as a decimal number [01,31].
%H Hour (24-hour clock) as a decimal number [00,23].
%I Hour (12-hour clock) as a decimal number [01,12].
%j Day of the year as a decimal number [001,366].
%m Month as a decimal number [01,12].
%M Minute as a decimal number [00,59].
%p Locale’s equivalent of either AM or PM. (1)
%S Second as a decimal number [00,61]. (2)
%U Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Sunday are considered to be in week 0. (3)
%w Weekday as a decimal number [0(Sunday),6].
%W Week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday are considered to be in week 0. (3)
%x Locale’s appropriate date representation.
%X Locale’s appropriate time representation.
%y Year without century as a decimal number [00,99].
%Y Year with century as a decimal number.
%z Time zone offset indicating a positive or negative time difference from UTC/GMT of the form +HHMM or -HHMM, where H represents decimal hour digits and M represents decimal minute digits [-23:59, +23:59].
%Z Time zone name (no characters if no time zone exists).
%% A literal '%' character.
由于计算机只能识别时间戳形式的时间,而人类可以识别的时间是格式化的时间和结构化的时间,所以三种时间之间要做对应的转化 三种时间之间的转换:
#--------------------------按图1转换时间
# localtime([secs])
# 将一个时间戳转换为当前时区的struct_time。secs参数未提供,则以当前时间为准。
time.localtime()
time.localtime(1473525444.037215)
# gmtime([secs]) 和localtime()方法类似,gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。
# mktime(t) : 将一个struct_time转化为时间戳。
print(time.mktime(time.localtime()))#1473525749.0
# strftime(format[, t]) : 把一个代表时间的元组或者struct_time(如由time.localtime()和
# time.gmtime()返回)转化为格式化的时间字符串。如果t未指定,将传入time.localtime()。如果元组中任何一个
# 元素越界,ValueError的错误将会被抛出。
print(time.strftime("%Y-%m-%d %X", time.localtime()))#2016-09-11 00:49:56
# time.strptime(string[, format])
# 把一个格式化时间字符串转化为struct_time。实际上它和strftime()是逆操作。
print(time.strptime('2011-05-05 16:37:06', '%Y-%m-%d %X'))
#time.struct_time(tm_year=2011, tm_mon=5, tm_mday=5, tm_hour=16, tm_min=37, tm_sec=6,
# tm_wday=3, tm_yday=125, tm_isdst=-1)
#在这个函数中,format默认为:"%a %b %d %H:%M:%S %Y"。
4.除了上面几种还有需要了解的time模块的功能
time.sleep()
import time
与时间相关的一个模块
时间的三类
1.时间戳 从1970-1-1 0:0:0开始到现在的秒数
print(time.time())
t = time.time()
time.sleep(10)
t2 = time.time()
print(t2-t)
2.结构化时间
print(time.localtime()) # 返回的是一个对象 其中包含一个元组 里面是每个时间的值 (东八区)
print(time.localtime().tm_year) #单独获取某个时间属性
print(time.gmtime()) # 世界统一时间 比北京时间晚了八小时
3.格式化的字符串时间
print(time.strftime("%Y-%m-%d %H:%M:%S %p"))
print(time.strftime("%Y-%m-%d %X %p"))
三种格式之间的相互转换
时间戳转为结构化
print(time.localtime(time.time()))
结构化转字符串
print(time.strftime("%Y-%m-%d",time.localtime(time.time())))
字符串转为结构化
print(time.strptime("2018-10-15","%Y-%m-%d"))
结构化转时间戳
print(time.mktime(time.strptime("2018-10-15","%Y-%m-%d")))
了解 格林威治时间
print(time.asctime(time.localtime(60*60*24)))
print(time.ctime(60*60*24))
2.datetime模块
对时间的处理和对日期的处理
datetime.timedelta()表示时间差
datetime.datetime() 获取当前时间
datetime.datetime.now()获取当前详细的时间
datetime.datetime.now().hour 获取当前时间的某一具体部分
替换当前时间的某一部分
t1 = datetime.datetime.now()
t1 = t1.replace(year=2019)
print(t1)
注意:1.datetime.datetime.now()之间不可以相加,因为会有一个时间范围限制,大概限制在4000年多 2.datetime.datetime.now()可以和时间差对象datetime.timedelta()之间相加减,例如:
ta1 = datetime.timedelta(weeks=1)
t1 = datetime.datetime.now()
print(t1 + ta1) # 2018-10-28 22:04:23.742224
每个模块功能使用之后返回的数据类型
时间戳time.time()返回的对象: 1540131281.7837002
结构化时间time.struct time.struct_time(tm_year=2018, tm_mon=10, tm_mday=21, tm_hour=22, tm_min=19, tm_sec=10, tm_wday=6, tm_yday=294, tm_isdst=0)
格式化时间time.strftime("%Y-%m-%d %H:%M:%S %p")) 2018-10-21 22:24:04 PM
time.strftime("%Y-%m-%d %X %p") 2018-10-21 22:24:44 PM
datetime.datetime.now() 2018-10-21 22:27:44.714215
datetime.timedelta() 7 days, 0:00:00