一、hashlib加密模块

hashlib模块是用于数据加密的,模块中有很多种加密算法,比如md5、base64、hmac、sha1等sha系列的加密算法。

1、何为加密

将明文数据处理成密文数据 让人无法看懂(无法逆转),但是可以通过已经加密过的结果进行穷举,来推测明文。

2、为什么加密

为了保证数据的安全

3、如何判断数据是否以加密

我们可以观看数据的构成,如果是用无序的数字、字母、符号来组成的,基本上都是加密数据

4、密文的长短有什么意义

密文越长表示两种情况,第一种就是明文很长,第二种就是加密的算法很复杂,这里我们需要注意算法并不是越复杂越好,应该根据实际情况选择使用,有些时候反而使用简单的算法就足够了。

5、加密算法的基本操作

# 第一步导入模块
import hashlib
# 2.传入明文数据
md5 = hashlib.md5()
md5.update(b'hello')
# 3.获取加密密文
res = md5.hexdigest()
print(res) # 5d41402abc4b2a76b9719d911017c592

注:md5中需要使用二进制才能转换

二、加密补充说明

1.加密算法不变 内容如果相同 那么结果肯定相同
# md5.update(b'hello~world~python~666') # 一次性传可以
md5.update(b'hello') # 分多次传也可以
md5.update(b'~world') # 分多次传也可以
md5.update(b'~python~666') # 分多次传也可以
2.加密之后的结果是无法反解密的
只能从明文到密文正向推导 无法从密文到明文反向推导
常见的解密过程其实是提前猜测了很多种结果
123 密文
321 密文
222 密文
3.加盐处理
在明文里面添加一些额外的干扰项
# 1.选择加密算法
md5 = hashlib.md5()
# 2.传入明文数据
md5.update('公司设置的干扰项'.encode('utf8'))
md5.update(b'hello python') # 一次性传可以
# 3.获取加密密文
res = md5.hexdigest()
print(res) # e53024684c9be1dd3f6114ecc8bbdddc
4.动态加盐
干扰项是随机变化的
eg:当前时间、用户名部分...
5.加密实战操作
1.用户密码加密
2.文件安全性校验
3.文件内容一致性校验
4.大文件内容加密
截取部分内容加密即可
比如一种情况就是,在一个大文件的每隔四分之一处取一千个字节进行加密,如果两个文件的密文一样说明,这里就是一样的两个文件

三、subprocess模块

subprocess是python内置的模块,这个模块中的Popen可以查看用户输入的命令行是否存在

如果存在,把内容写入到stdout管道中

如果不存在,把信息写入到stderr管道

需要注意的是,这个模块的返回结果只能让开发者看一次,如果想多次查看,需要在第一次输出的时候,把所有信息写入到变量中。

1、subprocess中的popen用法:

  • Popen基本格式:subprocess.Popen(‘命令’, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

  • shell=True 表示要在终端中运行的命令

    stdout=sbuprocess.PIPE 表示当命令存在的时候,把结果写入到stdout管道

    stderr=sbuprocess.PIPE 表示当命令不存在的时候,把结果吸入到stderr管道

import subprocess

res = subprocess.Popen(
'asdas', # 操作系统要执行的命令
shell=True, # 固定配置
stdin=subprocess.PIPE, # 输入命令
stdout=subprocess.PIPE, # 输出结果
)
print('正确结果', res.stdout.read().decode('gbk')) # 获取操作系统执行命令之后的正确结果
print('错误结果', res.stderr) # 获取操作系统执行命令之后的错误结果

2. subprocess模块中的常用函数

函数 描述
subprocess.run() Python 3.5中新增的函数。执行指定的命令,等待命令执行完成后返回一个包含执行结果的CompletedProcess类的实例。
subprocess.call() 执行指定的命令,返回命令执行状态,其功能类似于os.system(cmd)。
subprocess.check_call() Python 2.5中新增的函数。 执行指定的命令,如果执行成功则返回状态码,否则抛出异常。其功能等价于subprocess.run(…, check=True)。
subprocess.check_output() Python 2.7中新增的的函数。执行指定的命令,如果执行状态码为0则返回命令执行结果,否则抛出异常。
subprocess.getoutput(cmd) 接收字符串格式的命令,执行命令并返回执行结果,其功能类似于os.popen(cmd).read()和commands.getoutput(cmd)。
subprocess.getstatusoutput(cmd) 执行cmd命令,返回一个元组(命令执行状态, 命令执行结果输出),其功能类似于commands.getstatusoutput()。

说明:

1.在Python 3.5之后的版本中,官方文档中提倡通过subprocess.run()函数替代其他函数来使用subproccess模块的功能;

2.在Python 3.5之前的版本中,我们可以通过subprocess.call(),subprocess.getoutput()等上面列出的其他函数来使用subprocess模块的功能;

3.subprocess.run()、subprocess.call()、subprocess.check_call()和subprocess.check_output()都是通过对subprocess.Popen的封装来实现的高级函数,因此如果我们需要更复杂功能时,可以通过subprocess.Popen来完成。

4.subprocess.getoutput()和subprocess.getstatusoutput()函数是来自Python 2.x的commands模块的两个遗留函数。它们隐式的调用系统shell,并且不保证其他函数所具有的安全性和异常处理的一致性。另外,它们从Python 3.3.4开始才支持Windows平台。

3、上面各函数的定义及参数说明

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False, universal_newlines=False)

subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)

subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)

subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False, timeout=None)

subprocess.getstatusoutput(cmd)

subprocess.getoutput(cmd)

参数说明:

args: 要执行的shell命令,默认应该是一个字符串序列,如[‘df’, ‘-Th’]或(‘df’, ‘-Th’),也可以是一个字符串,如’df -Th’,但是此时需要把shell参数的值置为True。

shell: 如果shell为True,那么指定的命令将通过shell执行。如果我们需要访问某些shell的特性,如管道、文件名通配符、环境变量扩展功能,这将是非常有用的。当然,python本身也提供了许多类似shell的特性的实现,如glob、fnmatch、os.walk()、os.path.expandvars()、os.expanduser()和shutil等。

check: 如果check参数的值是True,且执行命令的进程以非0状态码退出,则会抛出一个CalledProcessError的异常,且该异常对象会包含 参数、退出状态码、以及stdout和stderr(如果它们有被捕获的话)。

stdout, stderr:input: 该参数是传递给Popen.communicate(),通常该参数的值必须是一个字节序列,如果universal_newlines=True,则其值应该是一个字符串。

run()函数默认不会捕获命令执行结果的正常输出和错误输出,如果我们向获取这些内容需要传递subprocess.PIPE,然后可以通过返回的CompletedProcess类实例的stdout和stderr属性或捕获相应的内容;

call()和check_call()函数返回的是命令执行的状态码,而不是CompletedProcess类实例,所以对于它们而言,stdout和stderr不适合赋值为subprocess.PIPE;

check_output()函数默认就会返回命令执行结果,所以不用设置stdout的值,如果我们希望在结果中捕获错误信息,可以执行stderr=subprocess.STDOUT。

universal_newlines: 该参数影响的是输入与输出的数据格式,比如它的值默认为False,此时stdout和stderr的输出是字节序列;当该参数的值设置为True时,stdout和stderr的输出是字符串。

四、logging日志模块

1、如何理解日志

所谓日志就是一个用来记录我们行为举止的代码,类似以前的史官,我们在平时的使用中并不要求自己可以写出来,会用别人的代码并且会改就可以了。因为以后会使用整合更好的模块来使用。

2、日志的五种级别

logging模块日志级别有DEBUG < INFO < WARNING < ERROR < CRITICAL 五种。

DEBUG - 调试模式,应用场景是问题诊断;

INFO - 通常只记录程序中一般事件的信息,用于确认工作一切正常;

WARNING - 打印警告信息,系统还在正常运行;

ERROR - 错误导致某些功能不能正常运行时记录的信息;

CRITICAL - 当发生严重错误,导致应用程序不能继续运行时记录的信息。

3、组成部分

  • logger:提供记录日志的方法。
  • handler:选择日志的输出地方(一个logger添加多个handler)。
  • filter:给用户提供更加细粒度的控制日志的输出内容。
  • format:用户格式化输出日志的信息。

4、配置方法

1.基础配置

logging.basicConfig(filename="config.log",
filemode="w",
format="%(asctime)s-%(name)s-%(levelname)s-%(message)s",
level=logging.INFO)

2.使用配置文件的方式

fileConfig(filename,defaults=None,disable_existing_loggers=Ture )

3.使用一个字典方式来写配置信息

使用dictConfig(dict,defaults=None, disable_existing_loggers=Ture )函数

3、日志输出

  • StreamHandler

  • logging.StreamHandler:日志输出到流,可以是sys.stderr,sys.stdout或者文件
  • FileHandler

  • logging.FileHandler:日志输出到文件
  • BaseRotatingHandler

  • logging.handlers.BaseRotatingHandler:基本的日志回滚方式
  • RotatingHandler

  • logging.handlers.RotatingHandler:日志回滚方式,支持日志文件最大数量和日志文件回滚

4、format常用格式说明

    %(levelno)s: 打印日志级别的数值
%(levelname)s: 打印日志级别名称
%(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0]
%(filename)s: 打印当前执行程序名
%(funcName)s: 打印日志的当前函数
%(lineno)d: 打印日志的当前行号
%(asctime)s: 打印日志的时间
%(thread)d: 打印线程ID
%(threadName)s: 打印线程名称
%(process)d: 打印进程ID
%(message)s: 打印日志信息

五、日志的执行过程

1、产生日志

2、过滤日志

这里我们需要注意,通常来说我们会在产生日志的时候设置需要产生的日志。其他不需要的日志就不会生成,所以基本用不到这个模块

3、输出日志

4、日志格式

六、字段解释

# 字段解释
filename:日志文件名的prefix; when:是一个字符串,用于描述滚动周期的基本单位,字符串的值及意义如下:
“S”: Seconds
“M”: Minutes
“H”: Hours
“D”: Days
“W”: Week day (0=Monday)
“midnight”: Roll over at midnight interval: 滚动周期,单位有when指定,比如:when=’D’,interval=1,表示每天产生一个日志文件
backupCount: 表示日志文件的保留个数

举例:

import logging

# 1.日志的产生(准备原材料)        logger对象
logger = logging.getLogger('购物车记录')
# 2.日志的过滤(剔除不良品) filter对象>>>:可以忽略 不用使用
# 3.日志的产出(成品) handler对象
hd1 = logging.FileHandler('a1.log', encoding='utf-8') # 输出到文件中
hd2 = logging.FileHandler('a2.log', encoding='utf-8') # 输出到文件中
hd3 = logging.StreamHandler() # 输出到终端
# 4.日志的格式(包装) format对象
fm1 = logging.Formatter(
fmt='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
)
fm2 = logging.Formatter(
fmt='%(asctime)s - %(name)s: %(message)s',
datefmt='%Y-%m-%d',
)
# 5.给logger对象绑定handler对象
logger.addHandler(hd1)
logger.addHandler(hd2)
logger.addHandler(hd3)
# 6.给handler绑定formmate对象
hd1.setFormatter(fm1)
hd2.setFormatter(fm2)
hd3.setFormatter(fm1)
# 7.设置日志等级
logger.setLevel(10) # debug
# 8.记录日志
logger.debug('写了半天 好累啊 好热啊')

六、日志配置字典

通常来说我们都是使用日志字典的形式来达成功能的(功能多又方便,谁不喜欢呢)。这里也是跟之前的说的一样,会用就好,不需要了解。

import logging
import logging.config
# 定义日志输出格式 开始
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
'[%(levelname)s][%(message)s]' # 其中name为getlogger指定的名字
simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
# 自定义文件路径
logfile_path = 'a3.log'
LOGGING_DIC = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': standard_format
},
'simple': {
'format': simple_format
},
},
'filters': {}, # 过滤日志
'handlers': {
# 打印到终端的日志
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'simple'
},
# 打印到文件的日志,收集info及以上的日志
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
'formatter': 'standard',
'filename': logfile_path, # 日志文件
'maxBytes': 1024 * 1024 * 5, # 日志大小 5M
'backupCount': 5,
# 这里两个参数的意思是一个日志文件最多写5M,最多可以存在五个不同的日志文件,但是当数量达到五个之后就会出现最早的那个会被删除,
# 然后再产生一个新的文件(类似于覆盖了最早的那个文件)
'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了
},
},
'loggers': {
# logging.getLogger(__name__)拿到的logger配置
'': {
'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG',
'propagate': True, # 向上(更高level的logger)传递
}, # 当键不存在的情况下 (key设为空字符串)默认都会使用该k:v配置
# '购物车记录': {
# 'handlers': ['default','console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
# 'level': 'WARNING',
# 'propagate': True, # 向上(更高level的logger)传递
# }, # 当键不存在的情况下 (key设为空字符串)默认都会使用该k:v配置
},
}
logging.config.dictConfig(LOGGING_DIC) # 自动加载字典中的配置
# logger1 = logging.getLogger('购物车记录')
# logger1.warning('尊敬的VIP客户 晚上好 您又来啦')
# logger1 = logging.getLogger('注册记录')
# logger1.debug('jason注册成功')
logger1 = logging.getLogger('红浪漫顾客消费记录')
# 当这里的getLogger内部的参数如果字典中没有,就会自动使用字典中名称为空的那个模版来执行
logger1.debug('慢男 猛男 骚男')

七、作业

完善购物车程序 尝试拆分成软件开发目录规范并添加日志功能

start.py

import weekends_work.core.src
# 完善购物车程序 尝试拆分成软件开发目录规范并添加日志功能
import os # 获取文件目前所在位置
out_path = os.path.dirname(os.path.dirname(__file__))
db_path = os.path.join(out_path, 'db') print(__name__)
if __name__ == '__main__':
weekends_work.core.src.choice_user()

src.py

import json
import os
import hashlib
import weekends_work.lib.common good_list = [['挂壁面', 3],
['印度飞饼', 22],
['极品木瓜', 666],
['土耳其土豆', 999],
['伊拉克拌面', 1000],
['董卓戏张飞公仔', 2000],
['仿真玩偶', 10000]] now_path = os.getcwd()
os.chdir('..')
all_path = os.getcwd()
db_path = os.path.join(all_path, 'db') log_user = {'name': ''} def choice_user():
while True: choice_user = input(
'''请选择需要执行的功能:\n1、用户登陆\n2、用户注册\n3、添加购物车\n4、结算购物车\n5、充值\n6、查看购物车中当前内容\n7、清空购物车中内容\n8、修改购物车中内容\n9、转账\n10、查看消费记录\n请输入需要执行的指令(q退出):''')
if choice_user == 'q':
print('退出成功')
break
if choice_user not in user_choice:
print('功能编号不存在 请重新输入')
continue
func_name = user_choice.get(choice_user) # 获取函数名
res = func_name() # 调用函数
if res:
print(res) # 整个装饰器判断是否登陆了
def is_log_z(func):
def intter(*args, **kwargs):
if log_user["name"] == '':
return '请先进行登陆'
else:
res = func(*args, **kwargs)
return res
return intter def log_in():
is_log_bool = True
while is_log_bool:
log_name = input('请输入登陆的用户名(q退出):')
# 获取用户名
if log_name == 'q':
break
# 输q退出
if log_name == '':
# 如果用户名为空就重新注册
print('用户名不能为空!')
continue
file_name = f'{log_name}.json'
file_path = os.path.join(db_path, file_name)
# 拼接路径,查找这个文件是不是存在(判断这个用户名是否已经存在)
is_file = os.path.exists(file_path) if not is_file:
print('用户名错误')
lg = weekends_work.lib.common.get_logger('登录记录')
lg.debug('用户名错误')
continue
# 如果有这个文件(有这个用户)
print('用户名正确')
log_pwd = input('请输入密码:')
# 获取密码
file_name = f'{log_name}.json'
file_path = os.path.join(db_path, file_name)
with open(file_path, 'r', encoding='utf8') as f1:
res = json.load(f1)
log_pwd_md5 = hashlib.md5()
log_pwd_md5.update(log_pwd.encode())
log_pwd_md5_get = log_pwd_md5.hexdigest()
if res['password'] != log_pwd_md5_get:
print('密码错误')
lg = weekends_work.lib.common.get_logger('登录记录')
lg.debug(f'用户{log_name}密码错误')
continue
print('登陆成功')
log_user['name'] = log_name
is_log_bool = False
lg = weekends_work.lib.common.get_logger('登录记录')
lg.debug(f'用户{log_name}登陆成功') def sign_in():
while True:
# 获取注册的用户名
sign_name = input('请输入注册的用户名(q退出):').strip()
if sign_name == 'q':
break
if sign_name == '':
# 如果用户名为空就重新注册
print('用户名不能为空!')
lg = weekends_work.lib.common.get_logger('注册记录')
lg.debug('用户名为空')
continue
file_name = f'{sign_name}.json'
file_path = os.path.join(db_path, file_name)
# 拼接路径,查找这个文件是不是存在(判断这个用户名是否已经存在)
is_file = os.path.exists(file_path) if is_file:
# 当这个文件存在了(用户名重复了),重新注册
print('用户名重复请重新输入!')
lg = weekends_work.lib.common.get_logger('注册记录')
lg.debug(f'用户{sign_name}重复')
continue
# 如果前面的操作都没出错,就获取密码,需要输入两次进行确定
sign_pwd = input('请输入密码:').strip()
check_sign_pwd = input('请确认密码:').strip()
if sign_pwd != check_sign_pwd:
# 如果两次密码不一致,重新注册
print('两次密码不一致,请重新输入!')
lg = weekends_work.lib.common.get_logger('注册记录')
lg.debug(f'用户{sign_name}两次密码不一致')
continue doc_name = f'{sign_name}.json'
user_path = os.path.join(db_path, doc_name)
sign_pwd_md5 = hashlib.md5()
sign_pwd_md5.update(sign_pwd.encode())
sign_pwd_md5_get = sign_pwd_md5.hexdigest()
with open(user_path, 'w', encoding='utf8') as f1:
user_infor = {'name': sign_name, 'password': sign_pwd_md5_get, 'balance': 15000, 'shop_car': {},
'record': []}
json.dump(user_infor, f1, ensure_ascii=False)
print('注册成功')
lg = weekends_work.lib.common.get_logger('注册记录')
lg.debug(f'用户{sign_name}注册成功')
break @is_log_z
def shop_add():
user_d = f'{log_user["name"]}.json'
add_path = os.path.join(db_path, user_d)
res_befor = {}
little_shop_car = {}
while True:
count = 1
print('-----------------商品目录如下:----------------')
for i, j in enumerate(good_list, start=1):
lis_shop = f'''
商品编号:{i}
商品名:{j[0]}
商品价格:{j[1]}元
'''
print(lis_shop)
choice_shop = input('请输入需要添加到购物车的物品(输入编号):').strip()
# 获取用户需要购买商品的编号
if not choice_shop.isdigit():
# 判断是否是纯数字编号,不是就重新来过
print('请输入正确的数字编号!')
lg = weekends_work.lib.common.get_logger('添加购物车记录')
lg.debug(f'用户{log_user["name"]}商品编号错误')
continue if int(choice_shop) not in range(1, 8):
print('你他奶奶的商品编号超出范围了!')
lg = weekends_work.lib.common.get_logger('添加购物车记录')
lg.debug(f'用户{log_user["name"]}商品编号错误')
continue
# 判断编号范围是否在范围内
shop_name = good_list[int(choice_shop) - 1][0]
shop_price = good_list[int(choice_shop) - 1][1]
choice_number = input(f'请输入需要购买{shop_name}数量:')
# 编号在范围内就获取需要购买的数量
if not choice_number.isdigit():
# 如果购买数量不是纯数字也重新来过
print('数量需要是纯数字!')
lg = weekends_work.lib.common.get_logger('添加购物车记录')
lg.debug(f'用户{log_user["name"]}商品编号错误')
continue
if little_shop_car.get(shop_name) == None:
# 临时购物车中如果没有这个商品的信息就直接加入
little_shop_car[shop_name] = [int(choice_number), shop_price]
else:
# 如果有信息就相加
little_shop_car[shop_name][0] += int(choice_number)
with open(add_path, 'r', encoding='utf8') as f1:
res_befor = json.load(f1)
old_car = res_befor.get('shop_car')
if old_car and count == 1:
# 如果数据库中不为空,把里面的数据值加进来
for i in old_car:
print(i) print(old_car[i][0])
if little_shop_car.get(i) == None:
little_shop_car[i] = old_car[i]
else:
little_shop_car[i][0] += old_car[i][0]
print('商品添加成功')
lg = weekends_work.lib.common.get_logger('添加购物车记录')
lg.debug(f'用户{log_user["name"]}商品成功加入临时购物车') count += 1
if_continue = input('输入q退出,其他字符继续购物')
if if_continue == 'q':
if little_shop_car:
res_befor['shop_car'] = little_shop_car
with open(add_path, 'w', encoding='utf8') as f2: json.dump(res_befor, f2, ensure_ascii=False)
print('退出成功')
lg = weekends_work.lib.common.get_logger('添加购物车记录')
lg.debug(f'用户{log_user["name"]}购物结束')
break
else:
print('退出成功')
lg = weekends_work.lib.common.get_logger('添加购物车记录')
lg.debug(f'用户{log_user["name"]}未购物直接退出')
break @is_log_z
def settle_account():
user_d = f'{log_user["name"]}.json'
add_path = os.path.join(db_path, user_d)
with open(add_path, 'r', encoding='utf8') as f1:
res_befor = json.load(f1) count_money_all = 0
for i in res_befor['shop_car']:
list_i = res_befor['shop_car'][i]
count_money = list_i[1] * list_i[0]
count_money_all += count_money
print(count_money_all)
balance_u = res_befor['balance'] - count_money_all
res_befor['record'].append(f'-{count_money_all}')
if balance_u <= 0:
print('余额不足')
lg = weekends_work.lib.common.get_logger('结算记录')
lg.debug(f'用户{log_user["name"]}余额不支持结算') res_befor['balance'] = balance_u
res_befor['shop_car'] = {}
with open(add_path, 'w', encoding='utf8') as f2:
json.dump(res_befor, f2, ensure_ascii=False)
print(f'尊敬的{log_user["name"]} 您本次消费{count_money} 卡上余额剩余{balance_u} 欢迎下次再来挥霍!!!')
lg = weekends_work.lib.common.get_logger('结算记录')
lg.debug(f'用户{log_user["name"]}结算成功') @is_log_z
def balance_add():
user_d = f'{log_user["name"]}.json'
add_path = os.path.join(db_path, user_d)
with open(add_path, 'r', encoding='utf8') as f1:
res_befor = json.load(f1)
balance_add_number = int(input('请输入充值金额:').strip()) res_befor['balance'] += balance_add_number
res_befor['record'].append(f'+{balance_add_number}')
with open(add_path, 'w', encoding='utf8') as f2:
json.dump(res_befor, f2, ensure_ascii=False)
print('添加成功')
lg = weekends_work.lib.common.get_logger('充值记录')
lg.debug(f'用户{log_user["name"]}充值成功') @is_log_z
def shop_car_print():
user_d = f'{log_user["name"]}.json'
add_path = os.path.join(db_path, user_d)
with open(add_path, 'r', encoding='utf8') as f1:
res_befor = json.load(f1)
print(f'-------------用户:{log_user["name"]}当前购物车中物品如下:------------')
if res_befor['shop_car'] == {}:
print('空')
lg = weekends_work.lib.common.get_logger('查看购物车记录')
lg.debug(f'用户{log_user["name"]}购物车为空')
else:
for i in res_befor['shop_car']:
number_i = res_befor['shop_car'][i][0]
price_i = res_befor['shop_car'][i][1] infor_p = f'''
--------------------------------------------------
商品名:{i}
单价:{price_i}
已添加数量:{number_i}
--------------------------------------------------
'''
print(infor_p)
lg = weekends_work.lib.common.get_logger('查看购物车记录')
lg.debug(f'用户{log_user["name"]}购物车内容已查看') @is_log_z
def shop_car_clear():
user_d = f'{log_user["name"]}.json'
add_path = os.path.join(db_path, user_d)
with open(add_path, 'r', encoding='utf8') as f1:
res_befor = json.load(f1)
res_befor['shop_car'] = {}
with open(add_path, 'w', encoding='utf8') as f1:
res_befor = json.dump(res_befor, f1, ensure_ascii=False)
lg = weekends_work.lib.common.get_logger('清空购物车记录')
lg.debug(f'用户{log_user["name"]}购物车已清空') @is_log_z
def change_shop_car():
while True:
user_d = f'{log_user["name"]}.json'
add_path = os.path.join(db_path, user_d)
with open(add_path, 'r', encoding='utf8') as f1:
res_befor = json.load(f1)
print(f'-------------用户:{log_user["name"]}当前购物车中物品如下:------------')
if res_befor['shop_car'] == {}:
print('空')
lg = weekends_work.lib.common.get_logger('修改购物车记录')
lg.debug(f'用户{log_user["name"]}购物车为空')
break else:
for i in res_befor['shop_car']:
number_i = res_befor['shop_car'][i][0]
price_i = res_befor['shop_car'][i][1] infor_p = f'''
--------------------------------------------------
商品名:{i}
单价:{price_i}
已添加数量:{number_i}
--------------------------------------------------
'''
print(infor_p)
change_name = input('请输入需要更改的商品名称(要中文输完整,输入q退出):').strip()
if change_name == 'q':
print('成功退出')
lg = weekends_work.lib.common.get_logger('修改购物车记录')
lg.debug(f'用户{log_user["name"]}直接退出')
break
if change_name in res_befor['shop_car']:
change_number = int(input('需要更改的数量:').strip())
if change_number == 0:
res_befor['shop_car'][change_name].pop
print(res_befor)
lg = weekends_work.lib.common.get_logger('修改购物车记录')
lg.debug(f'用户{log_user["name"]}购物车内容已修改')
else:
res_befor['shop_car'][change_name][0] = change_number
print(res_befor)
lg = weekends_work.lib.common.get_logger('修改购物车记录')
lg.debug(f'用户{log_user["name"]}购物车内容已修改')
with open(add_path, 'w', encoding='utf8') as f1:
json.dump(res_befor, f1, ensure_ascii=False) @is_log_z
def log_shopping():
user_d = f'{log_user["name"]}.json'
add_path = os.path.join(db_path, user_d)
with open(add_path, 'r', encoding='utf8') as f1:
res_befor = json.load(f1)
print(f'---------------用户{log_user}流水:----------------')
lg = weekends_work.lib.common.get_logger('查看流水记录')
lg.debug(f'用户{log_user["name"]}查看流水')
for i in res_befor['record']:
print(f'''
{i}元
''') @is_log_z
def send_money():
while True:
user_d = f'{log_user["name"]}.json'
add_path = os.path.join(db_path, user_d)
with open(add_path, 'r', encoding='utf8') as f1:
res_befor = json.load(f1)
money_now = res_befor['balance']
# 获取用户当前余额
# 获取转账对象并判断是否存在
send_user = input('请输入转账对象:')
if send_user == 'q':
print('成功退出')
lg = weekends_work.lib.common.get_logger('转账记录')
lg.debug(f'用户{log_user["name"]}直接退出')
break
user_s_d = f'{send_user}.json'
send_path = os.path.join(db_path, user_s_d)
ans = os.path.exists(send_path)
if not ans:
print('用户不存在')
lg = weekends_work.lib.common.get_logger('转账记录')
lg.debug(f'用户{log_user["name"]}转账用户不存在') # 如果用户存在就转账
send_number = input('请输入转账金额:')
print('111')
if int(send_number) <= money_now:
print('余额不足')
lg = weekends_work.lib.common.get_logger('转账记录')
lg.debug(f'用户{log_user["name"]}余额不足') # 如果转账金额足够就转账
with open(send_path, 'r', encoding='utf8') as f2:
res_befor_s1 = json.load(f2)
res_befor_s1['balance'] += int(send_number) with open(send_path, 'w', encoding='utf8') as f3:
json.dump(res_befor_s1, f3, ensure_ascii=False)
# 转账之后把转账用户中的金额扣除
res_befor['balance'] -= int(send_number)
res_befor['record'].append(f'-{send_number}')
with open(add_path, 'w', encoding='utf8') as f4:
json.dump(res_befor, f4, ensure_ascii=False)
lg = weekends_work.lib.common.get_logger('转账记录')
lg.debug(f'用户{log_user["name"]}转账成功') user_choice = {'1': log_in,
'2': sign_in,
'3': shop_add,
'4': settle_account,
'5': balance_add,
'6': shop_car_print,
'7': shop_car_clear,
'8': change_shop_car,
'9': send_money,
'10': log_shopping,
}

settings.py

import os
# 定义日志输出格式 开始
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
'[%(levelname)s][%(message)s]' # 其中name为getlogger指定的名字
simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
# 自定义文件路径
out_path = os.path.dirname(os.path.dirname(__file__))
log_path = os.path.join(out_path,'log')
if not os.path.exists(log_path):
os.mkdir(log_path)
logfile_path = os.path.join(log_path, 'z1.log') LOGGING_DIC = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': standard_format
},
'simple': {
'format': simple_format
},
},
'filters': {}, # 过滤日志
'handlers': {
# 打印到终端的日志
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'simple'
},
# 打印到文件的日志,收集info及以上的日志
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
'formatter': 'standard',
'filename': logfile_path, # 日志文件
'maxBytes': 1024 * 1024 * 5, # 日志大小 5M
'backupCount': 5,
# 这里两个参数的意思是一个日志文件最多写5M,最多可以存在五个不同的日志文件,但是当数量达到五个之后就会出现最早的那个会被删除,
# 然后再产生一个新的文件(类似于覆盖了最早的那个文件)
'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了
},
},
'loggers': {
# logging.getLogger(__name__)拿到的logger配置
'': {
'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG',
'propagate': True, # 向上(更高level的logger)传递
}, # 当键不存在的情况下 (key设为空字符串)默认都会使用该k:v配置
# '购物车记录': {
# 'handlers': ['default','console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
# 'level': 'WARNING',
# 'propagate': True, # 向上(更高level的logger)传递
# }, # 当键不存在的情况下 (key设为空字符串)默认都会使用该k:v配置
},
}

common.py

import logging
import logging.config
from weekends_work.conf import settings def get_logger(name): logging.config.dictConfig(settings.LOGGING_DIC) # 自动加载字典中的配置 logger1 = logging.getLogger(name) return logger1

10月27日内容总结——hashlib加密模块和logging、subprocess模块的更多相关文章

  1. 2016年10月27日 星期四 --出埃及记 Exodus 19:12

    2016年10月27日 星期四 --出埃及记 Exodus 19:12 Put limits for the people around the mountain and tell them, `Be ...

  2. hashlib加密模块、logging日志模块

    hashlib模块 加密:将明文数据通过一系列算法变成密文数据 目的: 就是为了数据的安全 基本使用 基本使用 import hashlib # 1.先确定算法类型(md5普遍使用) md5 = ha ...

  3. 10月27日Java整理

    实验一:凯撒密码 import java.util.Scanner; //zhanxinwu,October,25,2016 public class Addmi { public static vo ...

  4. 2016年10月27日--css样式表

    CSS样式表 样式表分类 1.内联样式表 和html联合显示,控制精确,但是可重用性差,冗余多. !doctype html> <html> <head> <met ...

  5. 10月27日PHP加载类、设计模式(单例模式和工厂模式)、面向对象的六大原则

    加载类可以使用include.require.require_once三种中的任意一种,每个关键字都有两种方法,但是这种方法的缺点是需要加载多少个php文件,就要写多少个加载类的方法.一般也就需要加载 ...

  6. EditPlus 3.7.1186 中文版(10月27日更新)重大性能改进,推荐更新!

    3.7.* 版的 EditPlus 存在性能问题:加载行数比较多的文档时,要等很长的时间.加载一个十几兆的文本文件,可能需要等十几秒.在编辑窗口内翻页也会有明显的迟滞感.而此前的 3.6 版本并非如此 ...

  7. 2016年10月16日 星期日 --出埃及记 Exodus 18:27

    2016年10月16日 星期日 --出埃及记 Exodus 18:27 Then Moses sent his father-in-law on his way, and Jethro returne ...

  8. Java分布式互联网架构/微服务/高性能/springboot/springcloud 2018年10月17日直播内容

    2018年10月17日直播内容 大规模并发必备的消息中间件技术ActiveMq 网盘链接: https://pan.baidu.com/s/1GlxsZ2JnrvX- YN16-S7lQw 提取码: ...

  9. Java分布式互联网架构/微服务/高性能/springboot/springcloud2018年10月16日直播内容

    2018年10月16日直播内容 架构师揭秘springboot对springmvc的自动配置原理 直播地址:https://ke.qq.com/course/179440?tuin=9b386640 ...

  10. 我的Python成长之路---第七天---Python基础(22)---2016年2月27日(晴)

    socket网络编程 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. ...

随机推荐

  1. 《ASP.NET Core技术内幕与项目实战》精简集-目录

    本系列是杨中科2022年最新作品<ASP.NET Core技术内幕与项目实战>及B站配套视频(强插点赞)的精简集,是一个读书笔记.总结和提炼了主要知识点,遵守代码优先原则,以利于快速复习和 ...

  2. Windows版CheatSheet——一键显示当前程序快捷键列表

    Windows系统上的各种软件有太多的快捷键,想要记住是几乎不可能的,推荐一个一键显示当前软件快捷键的软件,在使用其他程序的时候,只要按下Ctrl+`就可以理解弹出该软件的所有快捷键列表,还支持收藏功 ...

  3. Dubbo-聊聊Dubbo协议

    前言 Dubbo源码阅读分享系列文章,欢迎大家关注点赞 SPI实现部分 Dubbo-SPI机制 Dubbo-Adaptive实现原理 Dubbo-Activate实现原理 Dubbo SPI-Wrap ...

  4. Codeforces Round #835 (Div. 4) A-G

    比赛链接 A 题意 给出三个不同的数,求中位数. 题解 知识点:模拟. 显然. 时间复杂度 \(O(1)\) 空间复杂度 \(O(1)\) 代码 #include <bits/stdc++.h& ...

  5. Vue使用Element表单校验错误Cannot read property ‘validate’ of undefined

    在做注册用户的页面使用表单校验一直提示Cannot read property 'validate' of undefined错误,其实这个错误的提示根据有多种情况,比较常见的就是 ref 的名字不一 ...

  6. Devexpress控件pivotGridControl显示字段面板

    可在窗口加载的时候使用函数 pivotGridControl1.ShowCustomization(); 大家如果有问题可以 Console.WriteLine("加群"+&quo ...

  7. vue3响应式原理以及ref和reactive区别还有vue2/3生命周期的对比,第二天

    前言: 前天我们学了 ref 和 reactive ,提到了响应式数据和 Proxy ,那我们今天就来了解一下,vue3 的响应式 在了解之前,先复习一下之前 vue2 的响应式原理 vue2 的响应 ...

  8. VulnHub靶场渗透实战8-DarkHole: 2

    靶场地址:DarkHole: 2 ~ VulnHub DescriptionBack to the Top Difficulty:Hard This works better with VMware ...

  9. VSCode解决Python中空格和制表符混用报错

    Python对缩进的要求非常严格,缩进控制不正确可能会造成代码执行不正确甚至报错. 遇到报错"TabError: inconsistent use of tabs and spaces in ...

  10. Django中ORM多对多三种创建方式(全自动-纯手动-半自动)

    一:多对多三种创建方式 1.全自动: 利用orm自动帮我们创建第三张关系表 class Book(models.Model): name = models.CharField(max_length=3 ...