-
正则表达式基础
-
字符组
-
特殊符号
-
量词
-
贪婪匹配和非贪婪匹配
-
转义符
-
re模块
-
re模块补充说明
-
第三方模块下载
-
网络爬虫模块之requests模块
-
hashlib加密模块
-
subprocess模块
-
logging日志模块
-
日志的组成
-
日志配置字典
-
日志实战应用
-
ATM大作业
正则表达式基础
案例:京东注册手机号校验
基本需求:手机号必须是11位、手机号必须以13 15 17 18 19开头、必须是纯数字
'''纯python代码实现'''
while True:
# 1.获取用户输入的手机号
phone_num = input('请输入您的手机号>>>:').strip()
# 2.先判断是否是十一位
if len(phone_num) == 11:
# 3.再判断是否是纯数字
if phone_num.isdigit():
# 4.判断手机号的开头
if phone_num.startswith('13') or phone_num.startswith('15') or phone_num.startswith(
'17') or phone_num.startswith('18') or phone_num.startswith('19'):
print('手机号码输入正确')
else:
print('手机号开头不对')
else:
print('手机号必须是纯数字')
else:
print('手机号必须是11位')
'''python结合正则实现'''
import re
phone_number = input('please input your phone number: ')
if re.match('^(13|14|15|18)[0-9]{9}$', phone_number):
print('是合法的手机号码')
else:
print('不是合法的手机号码')
"""
正则表达式是一门独立的技术 所有编程语言都可以使用
它的作用可以简单的概括为:利用一些特殊符号(也可以直接写需要查找的具体字符)的组合产生一些特殊的含义然后去字符串中筛选出符合条件的数据
>>>:筛选数据(匹配数据)
"""
字符组
"""
字符组默认匹配方式是挨个挨个匹配
"""
[0123456789]:匹配0-9任意一个数字(全写):文本中所有的数字会一一匹配,一次只能匹配一个字符
[0-9]:匹配0-9任意一个数(缩写):是上述功能的简写
[a-z]:匹配26个小写英文字母,一一匹配
[A-Z]:匹配26个大写英文字母,一一匹配
[0-9a-zA-Z]:匹配数字或小写字母或大写字母
"""
字符组内所有的数据默认都是或的关系
"""
特殊符号
"""
特殊符号默认的匹配方式是挨个匹配,一次只能匹配一个字符
"""
. 匹配除换行符以外的任意字符(数字、字母、下划线)
\w 匹配数字、字母、下划线
\d 匹配数字
^ 匹配字符串的开头(不限几个字符)
$ 匹配字符串的结尾(不限几个字符)
如果^和$连用,中间跟什么匹配到的内容就是什么,可以很好的限制匹配的内容
a|b 待匹配内容有a或b即可匹配
()::给正则表达式分组 不影响表达式的匹配功能
[]::字符组 内部填写的内容默认都是或的关系
[^]: 取反操作,上尖号后面的字符匹配不到,其他都可以匹配到
量词
"""
正则表达式默认情况下都是贪婪匹配,尽可能多的匹配
"""
* 匹配0次或多次,默认是多次(有多少匹配多少)
+ 匹配一次或多次,默认是多次(无穷次)
? 匹配0次或一次,和不加效果一样,作为量词意义不大名主要用于非贪婪匹配。字符后面加了?相当于?前的字符可有可无
{n} 相当于一次拿n个限定字符,不够n个不拿
{m,n} 相当于一次拿n到m和数字,在这个区间有多少拿多少,不够n个不拿,默认是m次
{n,} 一次拿n到无穷多个数字,默认是无穷多,不够n个不拿
贪婪匹配和非贪婪匹配
"""因为?默认匹配一次,所有的量词都是贪婪匹配如果想要变为非贪婪匹配只需要在量词后面加问号"""
请问匹配的内容
<script>alert(123)</script> 一条
# .*属于典型的贪婪匹配 使用它 结束条件一般在左右明确指定
待使用的正则(非贪婪匹配)
<.*?>
匹配到的内容是<script> 和</script>
转义符
"""斜杠与字母的组合有时候有特殊含义"""
\n 匹配的是换行符:在文本中不会显示匹配结果,但是会显示匹配到×条结果
\\n 匹配到的是文本中的\n
\\\\n 匹配到的是文本中的\\n
re模块
1.查找所有符合正则表达式要求的数据,结果是一个列表
import re
res = re.findall('ab', 'abc jdsfab dvjkab')
print(res) # ['ab', 'ab', 'ab']
2.查找所有符合正则表达式要求的数据,结果是一个迭代器对象
import re
res = re.finditer('ab', 'abc jdsfab dvjkab')
for i in res:
print(i)
# <re.Match object; span=(0, 2), match='ab'>
# <re.Match object; span=(8, 10), match='ab'>
# <re.Match object; span=(15, 17), match='ab'>
re模块补充说明
1.分组优先: findall分组优先展示:优先展示括号内正则表达式匹配到的内容
import re
res = re.findall('abc(aaa|bbb)cvvb', 'abcaaacvvb')
print(res)
res = re.search('www.(baidu|oldboy).com', 'www.oldboy.com')
print(res.group()) # www.oldboy.com
res = re.match('www.(baidu|oldboy).com', 'www.oldboy.com')
print(res.group()) # www.oldboy.com
2.分组别名:可以在分组当中加上<>,中建放上分组的别名,前面加?P,之后可以通过res.group('别名')的方式来找到匹配的内容;也可以通过索引值来找到匹配的内容,索引[0]是全部匹配的内容,索引[1]是第一个分组内匹配的内容,索引[2]是第二个分组内匹配的内容
res = re.search('www.(?P<content>baidu|oldboy)(?P<hei>.com)', 'www.oldboy.com')
print(res.group('content')) # oldboy
print(res.group()) # www.oldboy.com
print(res.group('hei')) # .com
print(res.group(0)) # www.oldboy.com
print(res.group(1)) # oldboy
print(res.group(2)) # .com
第三方模块下载
第三方模块:别人写的模块 一般情况下功能都特别强大
我们如果想使用第三方模块 第一次必须先下载后面才可以反复使用(等同于内置模块)
下载第三方模块的方式
1.pip工具
注意每个解释器都有pip工具 如果我们的电脑上有多个版本的解释器那么我们在使用pip的时候一定要注意到底用的是哪一个 否则极其任意出现使用的是A版本解释器然后用B版本的pip下载模块
为了避免pip冲突 我们在使用的时候可以添加对应的版本号
python27 pip2.7
python36 pip3.6
python38 pip3.8
下载第三方模块的句式
pip install 模块名
下载第三方模块临时切换仓库
pip install 模块名 -i 仓库地址
下载第三方模块指定版本(不指定默认是最新版)
pip install 模块名==版本号 -i 仓库地址
2.pycharm提供快捷方式
"""
下载第三方模块可能会出现的问题
1.报错并有警告信息
WARNING: You are using pip version 20.2.1;
原因在于pip版本过低 只需要拷贝后面的命令执行更新操作即可
d:\python38\python.exe -m pip install --upgrade pip
更新完成后再次执行下载第三方模块的命令即可
2.报错并含有Timeout关键字
说明当前计算机网络不稳定 只需要换网或者重新执行几次即可
3.报错并没有关键字
面向百度搜索
pip下载XXX报错:拷贝错误信息
通常都是需要用户提前准备好一些环境才可以顺利下载
4.下载速度很慢
pip默认下载的仓库地址是国外的 python.org
我们可以切换下载的地址
pip install 模块名 -i 仓库地址
pip的仓库地址有很多 百度查询即可
清华大学 :https://pypi.tuna.tsinghua.edu.cn/simple/
阿里云:http://mirrors.aliyun.com/pypi/simple/
中国科学技术大学 :http://pypi.mirrors.ustc.edu.cn/simple/
华中科技大学:http://pypi.hustunique.com/
豆瓣源:http://pypi.douban.com/simple/
腾讯源:http://mirrors.cloud.tencent.com/pypi/simple
华为镜像源:https://repo.huaweicloud.com/repository/pypi/simple/
"""
网络爬虫模块之requests模块
"""
整理链家网前十页房产信息,并且放在表格当中
"""
import requests
import re
from openpyxl import Workbook
wb = Workbook()
wb1 = wb.create_sheet('房产信息', 0)
wb1.append(['标题', '街道', '小区名称', '关注度', '发布时间', '总价', '单价'])
for i in range(1, 11): # 以获取10页数据为例,每遍历一页地址就会改变一次
res = requests.get(f'https://sh.lianjia.com/ershoufang/pudong/') # 观察网页数据,页数变化体现在pg后面的数字,用for循环挨个获取
data = res.text
# 获取标题
title_list = re.findall(
'data-log_index=".*?" data-el="ershoufang" data-housecode=".*?" data-is_focus="" data-sl="">(.*?)</a>', data)
# 获取街道
street_list = re.findall(
'target="_blank">(.*?)</a> </div></div><div class="address"><div class="houseInfo"><span class="houseIcon">',
data)
# 获取小区名称
name_list = re.findall('target="_blank" data-log_index=".*?" data-el="region">(.*?) </a>', data)
# 获取关注度
attention_list = re.findall('</div></div><div class="followInfo"><span class="starIcon"></span>(.*?)/', data)
# 获取发布时间
time_list = re.findall('</div></div><div class="followInfo"><span class="starIcon"></span>.*? / (.*?)</div><div',
data)
# 获取总价
price_list = re.findall('<div class="totalPrice totalPrice2"><i> </i><span class="">(.*?)</span>', data)
# 获取单价
unit_price = re.findall('data-hid=".*?" data-rid=".*?" data-price="(.*?)"><span>', data)
group = zip(title_list, street_list, name_list, attention_list, time_list, price_list, unit_price)
# group是每页小区的信息集合的列表,用for循环遍历,i就是每个小区的信息
for i in group:
wb1.append(i)
wb.save(r'房产信息前十页.xlsx')
pandas模块
openpyxl主要用于数据的写入 至于后续的表单操作它并不是很擅长 如果想做需要更高级的模块pandas
import pandas
data_dict = {
"公司名称": comp_title_list,
"公司地址": comp_address_list,
"公司邮编": comp_email_list,
"公司电话": comp_phone_list
}
# 将字典转换成pandas里面的DataFrame数据结构
df = pandas.DataFrame(data_dict)
# 直接保存成excel文件
df.to_excel(r'pd_comp_info.xlsx')
excel软件正常可以打开操作的数据集在10万左右 一旦数据集过大 软件操作几乎无效
需要使用代码操作>>>:pandas模块
hashlib加密模块
1.加密:将明文数据处理成密文数据,让人无法看懂
2.为什么加密:保证数据的安全
3.如何判断数据是否加密:如果是一长串没有规律的字符串(数字、字母、符号)那么数据被加密
4.密文的长短又和讲究:秘闻越长表示使用的加密算法(数据的处理过程)越复杂
5.常见的加密算法:md5、base64、hmac、sha系列
6.加密算法基本操作
import hashlib
# 1.选择加密算法
md5 = hashlib.md5()
# 2.传入明文数据
md5.update(b'123qwe')
"""
加密上传文本时,数字、英文一般用update(b'明文'), 汉语一般用变量名替代,用字符串内置方法update(s.encode('utf8'))
eg:
import hashlib
md5 = hashlib.md5()
md5.update(b'jksdhf12')
res = md5.hexdigest()
print(res) # 54ea00f1c784e860baf0bf6a68810070
s = '哈哈哈呵呵呵'
import hashlib
md5 = hashlib.md5()
md5.update(s.encode('utf8'))
res = md5.hexdigest()
print(res) # e3b3165fdfaf155ad01a9849db7b23d5
"""
# 3.获取加密密文
res = md5.hexdigest()
print(res) # 46f94c8de14fb36680850768ff1b7f2a
7.加密算法不变,如果内容相同,那么结果一定相同
import hashlib
md5 = hashlib.md5()
md5.update(b'hello~world~python')
res = md5.hexdigest()
print(res) # 5045c7522021858df55ff9a27b7cdc46、
import hashlib
md5 = hashlib.md5()
md5.update(b'hello')
md5.update(b'~world')
md5.update(b'~python')
res = md5.hexdigest()
print(res) # 393f30266b770278539d8fd96ff521c0
8.加密之后的那结果是无法反解密的
只能从明文到暗文正向推导,无法从密文到明文反向推导,常见的解密过程其实是提前保存了很多种明文的密文,如果明文过于复杂,无法反推找到明文。
3.加盐处理:在明文里面加一些额外的干扰项
import hashlib
md5 = hashlib.md5()
md5.update('其他的干扰项'.encode('utf8'))
md5.update(b'123321')
res = md5.hexdigest()
print(res) # e092bc9d7aaa814c51958f95237d27bd
““
结合获取用户输入使用:
import hashlib
user_pwd = input('请输入密码:')
md5 = hashlib.md5()
md5.update(user_pwd.encode('utf8'))
res = md5.hexdigest()
print(res)
””
9.动态加盐
干扰项是随机变化的
eg:当前时间、用户名部分...
10.加密实战操作
1.用户密码加密
2.文件安全性校验
3.文件内容一致性校验
4.大文件内容加密
截取部分内容加密即可
subprocess模块
模拟操作系统终端 执行命令并获取结果
import subprocess
res = subprocess.Popen(
'asdas', # 操作系统要执行的命令
shell=True, # 固定配置
stdin=subprocess.PIPE, # 输入命令
stdout=subprocess.PIPE, # 输出结果
)
print('正确结果', res.stdout.read().decode('gbk')) # 获取操作系统执行命令之后的正确结果
print('错误结果', res.stderr) # 获取操作系统执行命令之后的错误结果
logging日志模块
1.如何理解日志
简单的理解为是记录行为举止的操作(历史史官)
2.日志的级别
五种级别(debug、info、warning、error、critical)
3.日志模块要求
代码无需掌握 但是得会CV并稍作修改
import logging
# logging.debug('debug message')
# logging.info('info message')
# logging.warning('warning message')
# logging.error('error message')
# logging.critical('critical message')
file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf8',)
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
handlers=[file_handler,],
level=logging.ERROR
)
logging.error('你好')
日志的组成
1.产生日志
2.过滤日志
基本不用 因为在日志产生阶段就可以控制想要的日志内容
3.输出日志
4.日志格式
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,
'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('红浪漫顾客消费记录')
logger1.debug('慢男 猛男 骚男')
日志实战应用
start.py代码:
# 1.导入模块
import os
import sys
# 2.因为ATM文件可能被用户放在任意位置,首先动态获取ATM目录路径
base_dir = os.path.dirname(os.path.dirname(__file__))
# 3.添加到系统环境变量,这样通过ATM根目录就可以找其他文件
sys.path.append(base_dir)
# 4.条件判断:
if __name__ == '__main__':
from ATM.core import src
src.run()
src.py代码:
from ATM.lib import common
def register():
lg = common.get_my_logger('注册') # 括号内是task_id,根据需要修改
lg.info('注册成功') # 括号内是登录信息,根据需要修改
def login():
lg = common.get_my_logger('登陆')
lg.info('登陆成功')
def add_shop_car():
lg = common.get_my_logger('添加购物车')
lg.warning('添加购物车成功')
def pay_shop_car():
lg = common.get_my_logger('结算购物车')
lg.error('结算购物车成功')
func_dict = {
'1': register,
'2': login,
'3': add_shop_car,
'4': pay_shop_car
}
def run():
while True:
print("""
1.注册
2.购物
3.添加购物车
4.结算购物车
""")
choice_num = input('请输入任务编号>>>:').strip()
if choice_num in func_dict:
func_dict.get(choice_num)()
else:
print('请输入正确任务编号')
setting.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'
BASE_PATH = os.path.dirname(os.path.dirname(__file__))
DB_DIR = os.path.join(BASE_PATH, 'log')
if not os.path.exists(DB_DIR):
os.mkdir(DB_DIR)
logfile_path = os.path.join(DB_DIR, 'a4.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,
'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 conf import settings
def get_my_logger(name):
logging.config.dictConfig(settings.LOGGING_DIC)
logger1 = logging.getLogger(name) # 括号内需要填task_id(任务编号)
# logger1.info('用户Jason注册成功') # 括号内改备注,括号前改错误级别
return logger1
ATM大作业
start.py代码:
import os
import sys
base_dir = os.path.dirname(os.path.dirname(__file__)) # 2.拿到ATM目录路径
sys.path.append(base_dir) #
if __name__ == '__main__':
from core import src # 3.调用src.run(),也可以加上ATM.core,core会飘红但是pycharm任然可以找到core文件夹不会报错
src.run()
src.py代码:
import os.path
from interface import user_interface
from lib import common
is_login = {
'username': ''
}
def register():
username = input('请输入您的用户名>>>:').strip() # 4.获取用户输入,并构造字典
password = input('请输入您的密码>>>:').strip()
confirm_pwd = input('请再次输入您的密码>>>:').strip()
if password == confirm_pwd: # 10.判断两次密码输入是否一致,如果一致则调用接口文件中的函数来对比
msg = user_interface.register_interface(username, password)
print(msg) # 15.用返回值接收user.interface.py的返回值,并打印
else:
print('密码错误')
def login():
user_name = input('请输入您的用户名>>>:').strip()
user_pwd = input('请输入您的密码>>>:').strip()
flag, msg = user_interface.login_interface(user_name, user_pwd)
if flag:
is_login['username'] = user_name
print(msg)
@common.login_auth
def check_blance():
user_name = is_login.get('username')
msg = user_interface.check_balance(user_name)
print(msg)
@common.login_auth
def withdraw():
user_name = is_login.get('username')
amount = input('请输入您提现的金额(提现手续费1%)>>>:').strip()
if not amount.isdigit():
print('提现金额必须是纯数字')
return
amount = int(amount)
amount, brokerage, balance = user_interface.withdraw_interface(user_name, amount)
print(f'您本次提现{amount}, 手续费{brokerage}, 账户余额{balance}')
@common.login_auth
def pay_money():
user_name = is_login.get('username')
recharge = input('请输入您想充值的金额>>>:').strip()
if not recharge.isdigit():
print('充值金额必须是纯数字')
return
recharge = int(recharge)
recharge, balance = user_interface.pay_money_interface(user_name, recharge)
print(f'您本次充值{recharge}, 账户余额{balance}')
@common.login_auth
def transfer():
user_name = is_login.get('username')
target_name = input('请输入您想转账的账户名>>>:').strip()
money = input('请输入您转账报的金额>>>:').strip()
if not money.isdigit():
print('转账金额必须是纯数字')
return
money = int(money)
breakrage, msg = user_interface.transfer_interface(user_name, target_name, money)
if breakrage:
print(f'您本次转账{money},手续费{breakrage}, 账户余额{msg}')
print(msg)
def check_flow():
print('查看流水')
@common.login_auth
def add_shop_car():
tem_list = {}
while True:
user_name = is_login.get('username')
good_list = [
['挂壁面', 3],
['印度飞饼', 22],
['极品木瓜', 666],
['土耳其土豆', 999],
['伊拉克拌面', 1000],
['董卓戏张飞公仔', 2000],
['仿真玩偶', 10000]
]
for i, j in enumerate(good_list, start=1): # i:1, j:['挂壁面', 3]
print(f'商品编号:{i} | 商品名称:{j[0]} | 商品单价:{j[1]}')
choice = input('请输入您的商品编号(q)>>>:').strip()
if choice == 'q':
msg = user_interface.add_shop_car_q_interface(user_name, tem_list)
print(msg)
return
if not choice.isdigit():
print('商品编号必须是纯数字')
return
choice = int(choice)
if not choice in range(1, len(good_list) + 1):
print('没有此商品')
return
num = input(f'情输入您想购买{good_list[choice - 1][0]}的数量>>>:').strip()
if not num.isdigit():
print('商品数量必须是纯数字')
return
num = int(num)
tem_list = user_interface.add_shop_car_interface(user_name,choice, num, tem_list)
@common.login_auth
def check_shop_car():
user_name = is_login.get('username')
shop_car = user_interface.check_shop_car_interface(user_name)
for i in shop_car:
print(f"""
商品名称:{i} | 商品数量:{shop_car.get(i)[0]} | 商品单价:{shop_car.get(i)[1]}
""")
return
def pay_shop_car():
user_name = is_login.get('username')
msg = user_interface.pay_shop_car_interface(user_name)
print(msg)
def admin():
print('管理员权限')
func_dict = {
'1': register,
'2': login,
'3': check_blance,
'4': withdraw,
'5': pay_money,
'6': transfer,
'7': check_flow,
'8': add_shop_car,
'9': check_shop_car,
'10': pay_shop_car,
'11': admin
}
def run():
while True: # 1.功能搭建,放在函数里,方便调用
print("""
1.注册
2.登陆
3.查看余额
4.提现
5.充值
6.转账
7.查看流水
8.添加购物车
9.查看购物车
10.结算购物车
11.管理员权限
""")
choice_num = input('请输入您想执行的任务编号>>>:').strip()
if choice_num in func_dict:
func_dict.get(choice_num)()
else:
print('任务编号不存在,请重新输入')
user_interface.py代码:
import os
import db.db_handler
from db import db_handler
from conf import settings
from lib import common
# 12.由于拼接路径,写入文件代码移走,所以不需要调用os和json模块,导入db_handler方便调用save()函数
def register_interface(username, password):
# 9.创建接口文件,把校验功能放进去,因为将代码复制过来时取不到username和password,所以采用传参的方式传入
is_user = db_handler.select(username)
if is_user: # 18.用户路径存在,则会返回数据,布尔值为True,走该路径,返回'用户已注册'
return '用户已注册'
password = common.get_hash(password)
user_dict = {
'username': username,
'password': password,
'balance': 15000,
'shop_car': {},
'is_lock': False,
'bank_flow': []
}
db_handler.save(user_dict) # 13.拼接路径,创建文件,写入放在db_handler中,直接调用save()函数即可
return f'用户{username}注册成功' # 14.print()操作只能在第一或者第二层执行,所以在本层以返回值的形式传给第一层
def login_interface(user_name, user_pwd):
user_dict = db_handler.select(user_name)
user_pwd = common.get_hash(user_pwd)
if not user_dict:
return False, f'用户{user_name}未注册'
if user_pwd == user_dict.get('password'):
return True, f'用户{user_name}登陆成功'
else:
return False, '密码错误'
def check_balance(user_name):
user_dict = db_handler.select(user_name)
balance = user_dict.get('balance')
return balance
def withdraw_interface(username, amount):
user_dict = db_handler.select(username)
brokerage = amount * 0.01 # 手续费
sum_money = amount + brokerage # 提现总额加手续费
balance = user_dict.get('balance') - sum_money # 提现后余额
user_dict['balance'] = balance
db_handler.save(user_dict)
return amount, brokerage, balance
def pay_money_interface(user_name, recharge):
user_dict = db_handler.select(user_name)
user_dict['balance'] += recharge
db_handler.save(user_dict)
return f'{recharge}', f'{user_dict.get("balance")}'
def transfer_interface(user_name, target_name, money):
user_dict1 = db_handler.select(user_name)
if not user_dict1:
return 0, f'转账用户{user_name}未注册'
user_dict2 = db_handler.select(target_name)
if not user_dict2:
return 0, f'接收用户{target_name}未注册'
user_dict1 = db_handler.select(user_name) # 转账账户字典
user_dict2 = db_handler.select(target_name) # 接收账户字典
if money > user_dict1.get('balance'):
return 0, f'用户{user_name}账户余额不足,无法转账'
brokerage = money * 0.05
user_dict1['balance'] -= money
user_dict2['balance'] += (money - brokerage)
db_handler.save(user_dict1)
db_handler.save(user_dict2)
return brokerage, user_dict1.get('balance')
def add_shop_car_interface(user_name, choice, num, tem_list):
user_dict = db_handler.select(user_name)
good_list = [
['挂壁面', 3],
['印度飞饼', 22],
['极品木瓜', 666],
['土耳其土豆', 999],
['伊拉克拌面', 1000],
['董卓戏张飞公仔', 2000],
['仿真玩偶', 10000]
]
target_list = good_list[choice - 1]
target_good = target_list[0] # '挂壁面'
if target_good in tem_list:
tem_list.get(target_good)[0] += num
else:
tem_list[target_good] = [num, target_list[1]]
return tem_list
def add_shop_car_q_interface(user_name, tem_list):
user_dict = db_handler.select(user_name)
shop_car = user_dict.get('shop_car')
for i in tem_list: # tem_list:{'极品木瓜': [6, 666], '土耳其土豆': [4, 999]} i:'极品木瓜'
if i in shop_car:
shop_car.get(i)[0] += tem_list.get(i)[0]
else:
shop_car[i] = tem_list.get(i)
user_dict['shop_car'] = shop_car
db_handler.save(user_dict)
return f'{user_name}购物车添加成功'
def check_shop_car_interface(user_name):
user_dict = db_handler.select(user_name)
shop_car = user_dict.get('shop_car')
return shop_car
def pay_shop_car_interface(user_name):
user_dict = db_handler.select(user_name)
shop_car = user_dict.get('shop_car')
money = 0
current_balance = user_dict.get('balance')
for i in shop_car:
money += shop_car.get(i)[0] * shop_car.get(i)[1]
if money > current_balance:
return '您的账户余额不足,无法购买'
current_balance -= money
user_dict['balance'] = current_balance
user_dict['shop_car'] = {}
db_handler.save(user_dict)
return f'尊敬的{user_name},您本次消费{money},账户余额{current_balance}'
db_handler.py代码:
import os
import json
from conf import settings
def save(user_dict): # 11.代码当中需要两个参数:user_dict和username,因为可以通过user_dict找到username,所以形参当中只保留一个user_dict
username = user_dict.get('username')
user_file_path = os.path.join(settings.DB_DIR, f'{username}.json') # 7.拼接username路径
with open(user_file_path, 'w', encoding='utf8') as f: # 8.将用户数据写入db目录
json.dump(user_dict, f, ensure_ascii=False)
# 15.判断用户名是否存在,如果存在则退出,不存在则继续执行
def select(username):
user_file_path = os.path.join(settings.DB_DIR, f'{username}.json')
if os.path.exists(user_file_path): # 16.如果用户存在,则直接返回该路径下数据
with open(user_file_path, 'r', encoding='utf8') as f:
return json.load(f)
# 17.如果路径存在,则走if分支,返回数据,返回值对应的布尔值为True,如果不走该分支,拿不到f,返回值为None
setting.py代码:
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__)) # ATM目录路径
DB_DIR = os.path.join(BASE_DIR, 'db')
if not os.path.exists(DB_DIR):
os.mkdir(DB_DIR)
common.py代码:
from core import src
import hashlib
def login_auth(func):
def inner(*args, **kwargs):
if src.is_login.get('username'):
res = func(*args, **kwargs)
return res
else:
print('您尚未登陆,请先登陆')
src.login()
return inner
def get_hash(user_pwd):
md5 = hashlib.md5()
md5.update(user_pwd.encode('utf8'))
user_pwd = md5.hexdigest()
return user_pwd
标签:总结,name,python,car,第五,dict,user,print,import
From: https://www.cnblogs.com/zkz0206/p/16842455.html