目录
一、编程思想
1、面向过程
# 核心:过程,即做事的步骤(先做什么,再做什么,然后再做什么)
# 优点:复杂的问题过程化,进而简单化
# 缺点:扩展性非常差
# 应用场景解析:不是所有的软件都需要频繁更迭,不是软件的所有组成部分都需要频繁更迭
2、面向对象
# 核心:对象,用于存放数据与功能的容器
# 优点:将程序整合,提高程序的解耦合程度,进而增强程序的可扩展性
# 缺点:设计复杂
#
3、猴子补丁
import json # 第一次导入会执行模块,产生一个json的名称空间
# 在当前模块产生一个名字json,指向上述名称空间
import ujson
json.dumps=ujson.dumps # json.dumps指向新的代码块
json.loads=ujson.loads
import json # 第二次导入不会执行模块
# 在当前模块产生一个名字,指向最初未关闭的json名称空间
json.dumps() # json.dumps指向的是新的代码块
二、模块
1、定义
'''
模块就是一个python文件(模块=模块名.py),是一系列功能的集合体
两个优点:
Ⅰ:极大地提升编程效率(内置与第三方的模块拿来就用无需定义)
Ⅱ:减少代码冗余(自定义的模块将程序的共性功能提取到一模块中为大家共享使用)
三个分类:
Ⅰ:内置的模块
Ⅱ:第三方的模块
Ⅲ:自定义的模块
四个形式
Ⅰ:使用python编写的.py文件
Ⅱ:把一系列模块组织到一起的文件夹(注:文件夹下有一个__init__.py)
Ⅲ:已被编译为共享库或DLL的C或C++扩展
Ⅳ:使用C编写并链接到python解释器的内置模块
'''
2、import导入模块
# 导入模块会发生的事情:
# 执行foo.py,将执行过程中产生的名字放到foo的名称空间中
# 在当前模块中产生一个名字foo,该名字指向foo的名称空间
import foo
# 如何调用:模块名.名字
foo.x
foo.get()
foo.change()
# 导入模块的顺序:内置>第三方>自定义
# 导入模块的位置:可以在函数内导入
# 在一行导入多个模块:import time,foo
# 将导入的模块取个别名:import 模块名 as 别名
# 自定义模块的命名:纯小写加下划线
# 模块是第一类对象:可以被赋值,作为函数参数、作为函数返回值、作为容器类型的元素
# __name__:在本模块执行时为"__main__",被当作模块导入时为"__模块名__"
3、from ... import导入模块
# 导入模块会发生的事情:
# 执行foo.py,将执行过程中产生的名字放到foo的名称空间中
# 在当前模块中产生一个名字,该名字指向foo的名称空间下的同一名字
from foo import x
from foo import get
from foo import change
# 如何调用:名字
x
get()
change()
# 将导入的名字取个别名:from 模块名 import 名字 as 别名
# 一行导入多个名字(不推荐):from 模块名 import 名字1,名字2
# 导入模块中的所有名字(不推荐):from 模块名 import *
# __all__:装有模块中所有名字的一个列表
4、模块查找优先级
'''
优先从内存找(python解释器在启动时会自动加载一些模块到内存中)
其次从硬盘找(按照sys.path中存放的文件的顺序依次查找)
1、sys.path中的第一个元素是当前执行文件所在的文件夹
2、不管导入的是包还是模块,它的上一级目录一定在sys.path
3、sys.path参照的是执行模块
'''
import sys
print(sys.path)
sys.path.append(r"D:\s38\Day03") # 将m1的路径临时加到sys.path
import m1 # 第一次导入:内存中没有,从硬盘找
# 执行m1.py,申请m1的名称空间存放名字
# 在当前模块中产生一个名字m1,m1指向m1的名称空间
print(sys.modules) # 查看已经加载到内存中的模块
del m1
def func():
import m2
func() # 解除绑定关系,导入的模块的名称空间仍然存在内存中
import m1 # 第二次导入:此时m1已经加载到内存中,从内存找
# 不会执行m1.py,不会申请内存空间
# 会在当前模块中产生一个名字m1,m1指向m1的名称空间
5、循环导入问题
# func.py
import m1
# m1.py
print("========>>导入m1")
x=111
from m2 import y
# m2.py
print("========>>导入m2")
from m1 import x
y=222
# func.py
import m1
f1()
# m1.py
print("========>>导入m1")
def f1():
from m2 import y
x=111
# m2.py
print("========>>导入m2")
from m1 import x
y=222
6、编写模块的规范
'''The module is used to ...''' # 模块的文档描述
import sys # 导入模块
x=1 # 定义全局变量,如非必须最好使用局部变量
class Foo: # 定义类,并写好类的注释
'''Class Foo is used to...'''
pass
def test(): # 定义函数,并写好函数的注释
'''Function is used to ...'''
pass
if __name__=="__main__":
test()
7、软件开发的目录规范
'''
ATM
readme # 解释描述
start.py # 程序入口
core # 用户视图层
src.py
interface # 逻辑接口层
user_interface.py
db # 数据处理层
db_handle.py
log # 存放日志
log.py
log.txt
conf # 存放配置文件(日志文件的路径)
settings.py
lib # 存放程序中常用的自定义模块
common.py
'''
# start.py
import sys
import os
PATH=os.path.dirname(__file__)
sys.path.append(PATH)
from core import src
src.run()
# src.py
from log.log import logger
def registe():
print("注册功能")
logger("注册")
def login():
print("登录功能")
logger("登录")
def withdrew():
print("提现功能")
logger("提现")
def transfer():
print("转账功能")
logger("转账")
func_dic = {
"0": ("退出", None),
"1": ("注册", registe),
"2": ("登录", login),
"3": ("提现", withdrew),
"4": ("转账", transfer),
}
def run():
while True:
for x in func_dic:
print(x, func_dic[x][0])
a = input("请输入序号:").strip()
if not a.isdigit():
print("请输入数字,二货!")
continue
if a not in fun_dic:
print("请输入已有的序号,二货!")
continue
if a == "0":
break
else:
func_dic[a][1]()
# log.py
import time
from conf.settings import LOG_PATH
def logger(mes):
with open(r"{}\log\user.log".format(LOG_PATH),mode="at",encoding="utf-8") as f:
f.write("{}{}\n".format(time.strftime("%Y-%m-%d %H-%M-%S"),mes))
# settings.py
import os
LOG_PATH=os.path.dirname(os.path.dirname(__file__))
三、包(模块的一种形式)
'''
包是模块的一种形式,是包含__init__.py文件的文件夹
foo
__init__.py
m1.py
m2.py
bbb
__init__.py
m3.py
test.py
'''
# test.py
import os
PATH=os.path.dirname(__file__)
import sys
sys.path.append(PATH)
import foo.m1 # .的左边必须是包
from foo.m1 import f1
import foo # foo 指向 __init__.py
from foo import x # x 指向 __init__.py中的x
from foo import m1 # m1 指向 m1.py
from foo import bbb # bbb 指向 bbb下的__init__.py
# __init__.py
x=1
# 绝对导入
from foo.m1 import f1 # sys.path参照的是被执行文件
from foo.m2 import f2
from foo.bbb.m3 import f3
# 相对导入
from .m1 import f1
from .m2 import f2
from .bbb.m3 import f3
# m1.py
def f1():
print("====>>f1")
# m2.py
def f2():
print("====>>f2")
# m3.py
def f3():
print("====>>f3")
四、常用模块
1、time
import time
# 1、时间戳:从1970到现在经历的秒数,用于时间间隔的计算
print(time.time())
# 2、结构化的时间,用于单独获取时间的某一部分
res=time.localtime()
print(res)
print(res.tm_year)
print(res.tm_yday)
# 3、格式化的时间:2022-05-16 20:20:20,用于展示时间
print(time.strftime("%Y-%m-%d %H:%M:%S %p"))
print(time.strftime("%Y-%m-%d %X"))
'''
localtime strftime
时间戳——————————>结构化的时间————————————>格式化的时间
timestamp<——————————struct_time<————————————format_time
mktime strptime
'''
import time
# 时间戳转换成结构化的时间
print(time.localtime(333333333))
print(time.gmtime(333333333))
# 结构化的时间转换成时间戳
s_time=time.localtime()
print(time.mktime(s_time))
# 结构化的时间转换成格式化的时间
print(time.strftime("%Y-%m-%d %H:%M:%S",s_time))
# 格式化的时间转换成结构化的时间
print(time.strptime("2022-05-16 21:03:02","%Y-%m-%d %H:%M:%S"))
2、datetime
import datetime
print(datetime.datetime.now()) # 2022-05-16 20:30:15.539775
print(datetime.datetime.now()+datetime.timedelta(days=10))
print(datetime.datetime.now()+datetime.timedelta(weeks=2))
# 了解
import datetime
print(datetime.datetime.now())
print(datetime.datetime.utcnow())
print(datetime.datetime.fromtimestamp(333333))
3、random
import random
print(random.random()) # (0,1)中取个小数
print(random.uniform(1,3)) # (1,3)中取个小数
print(random.randint(1,3)) # [1,3]中取个整数
print(random.randrange(1,3)) # [1,3)中取个整数
print(random.choice([1,"33",[4,5]])) # 随机取列表中的某一个元素
print(random.sample([1,"33",[4,5]],2)) # 随机取列表中的n个元素
item=[1,4,5,"a",3]
random.shuffle(item) # 打乱列表中元素的顺序
print(item)
# 验证码
print(chr(65)) # 65,66,...,90
print(ord("A")) # A, B,..., Z
import random
def make_code(size=4):
res=""
for i in range(size):
s1=str(random.randint(0,9))
s2=chr(random.randint(65,90))
res+=random.choice([s1,s2])
return res
print(make_code(6))
4、os
import os
print(os.listdir("dirname")) # 列出指定目录下所有的子文件和子文件夹
print(os.environ) # 获取环境变量
os.remove(r"D:\\aaa.txt") # 删除一个文件
os.rename(r"D:\\aaa.txt",r"D:\\bbb.txt") # 重命名文件/目录
os.system("cd D:\\") # 运行操作系统命令
print(os.path.split(r"D:\a\b\c")) # 将path分割成目录和文件名二元组返回
print(os.path.join("a","D:\\b","c")) # 将多个路径组合后返回,第一个绝对路径之前的参数被忽略
print(os.path.dirname(r"D:\a\b\c")) # 返回D:\a\b,其实就是os.path.split(path)中的第一个元素
print(os.path.basename(r"D:\a\b\c")) # 返回c,其实就是os.path.split(path)中的第二个元素
print(os.path.isfile(r"D:\a\b\c")) # 如果path是一个存在的文件,返回True;否则返回False
print(os.path.isdir(r"D:\a\b\c")) # 如果path是一个存在的目录,返回True;否
print(os.path.getsize(r"D:\a\b\c")) # 返回文件的大小(以字节为单位)
# 返回当前文件的上上一级目录
print(os.path.dirname(os.path.dirname(__file__)))
print(__file__)
print(os.path.join(__file__,"..",".."))
print(os.path.normpath(os.path.join(__file__,"..","..")))
# 在python3.5之后,推出了一个新的模块pathlib
from pathlib import Path
res=Path(__file__).parent.parent
print(res)
res=Path("/a/b/c") / "d/e.txt"
print(res)
# 了解
import os
print(os.getcwd()) # 获取当前工作目录
os.chdir(r"D:\\dirname1\\dirname2") # 改变当前脚本工作目录;相当于shell下cd
print(os.curdir) # 返回当前目录:"."
print(os.pardir) # 返回当前目录的父目录字符串名:".."
os.makedirs(r"D:\\dirname1\\dirname2") # 可生成多层递归目录
os.removedirs(r"D:\\dirname1\\dirname2") # 若目录为空,则删除并递归到上一级,如若也为空,则删除,依次类推
os.mkdir(r"D:\\dirname1") # 生成单级目录;相当于shell中的mkdir dirname1
os.rmdir(r"D:\\dirname1") # 删除单级目录,若目录不为空,则无法删除报错;相当于shell下rmdir dirname1
print(os.stat(r"D:\\s38\\ATM")) # 获取文件目录信息
print(os.sep) # 输出操作系统特定的路径分隔符,win下为\,Linux下为/
print(os.linesep) # 输出操作系统特定的行终止符,win下为\r\n,Linux下为\n
print(os.pathsep) # 输出操作系统特定的分割文件路径的字符,win下为;,Linux下为:
print(os.name) # 输出字符串指示当前使用平台,win->nt,linux->posix
print(os.path.abspath(r"D://c//c//c")) # 返回path规范化的绝对路径
print(os.path.exists(r"D:\s38\ATM")) # 如果path存在返回True,不存在返回False
print(os.path.isabs(r"D:\s38\ATM")) # 如果path是绝对路径返回True
print(os.path.getatime(r"D:\s38\ATM")) # 返回path所指向的文件或者目录的最后存取时间
print(os.path.getmtime(r"D:\s38\ATM")) # 返回path所指向的文件或者目录的最后修改时间
5、sys
import sys
# sys.argv获取的是解释器后的参数
print(sys.argv) # python3.8 run.py 1 2 3 ["run.py","1","2","3"]
# sys.path返回模块的搜索路径
print(sys.path)
# 打印进度条
import time
# res=""
# for i in range(50):
# res+="#"
# time.sleep(0.1)
# print("\r[{}]".format(res.ljust(50," ")),end="")
total_size=211111
start_size=0
while start_size<total_size:
if total_size-start_size>1024:
start_size+=1024
else:
start_size=total_size
time.sleep(0.01)
res=int(start_size/total_size*50)*"*"
print("\r[{}] {}%".format(res.ljust(50," "),int(start_size/total_size*100)),end="")
6、shutil(了解)
import shutil
shutil.copyfileobj(fsrc,fdst) # 将文件内容拷贝到另外一个文件中
shutil.copyfile(src,dst) # 拷贝文件(目标文件无需存在)
shutil.copymode(src,dst) # 仅拷贝权限,内容、用户、组均不变(目标文件必须存在)
shutil.copystat(src,dst) # 仅拷贝状态的信息,包括:mode bits,atime,mtime,flags(目标文件必须存在)
shutil.copy(src,dst) # 拷贝文件和权限
shutil.copy2(src,dst) # 拷贝文件和状态信息
shutil.copytree(src,dst,symlinks,ignore) # 递归的去拷贝文件夹
shutil.rmtree(path) # 递归的去删除文件
shutil.move(src,dst) # 递归的去移动文件
shutil.make_archive(base_name,format,root_dir) # 打包
7、json、pickle
'''
1、什么是序列化与反序列化
内存中的数据类型———————>序列化———————>特定的格式(json格式或者pickle格式)
内存中的数据类型<——————反序列化<——————特定的格式(json格式或者pickle格式)
2、为何要序列化
pickle是一种专用的格式(只有python可以识别),主要用于存储
json是一种通用的格式(能够被所有语言识别),主要用于跨平台数据交互
'''
import json
with open(r"test.json",mode="wt",encoding="utf-8") as f:
json_res=json.dumps([1,'aaa',True,False])
f.write(json_res)
# json.dump([1,'aaa',True,False],f)
with open(r"test.json",mode="rt",encoding="utf-8") as f:
json_res=f.read()
json.loads(json_res)
# json.load(f)
# json支持的是所有语言通用的类型,不能识别单一语言独有的类型
# 支持python类型:int、float、str、list、tuple、dict、bool、bytes(python3.5之后支持)
json.dumps([1,'aaa',True,False,None])
# json类型:{} [] 123.45 "string" true/false null
json.loads('[1,"aaa",true,false,null]')
import pickle
res=pickle.dumps({1,2,3,4})
print(res,type(res))
s=pickle.loads(res)
print(s,type(s))
8、configparser
import configparser
config=configparser.ConfigParser()
config.read("test.ini")
print(config.sections())
print(config.items("section1"))
print(config.options("section1"))
print(config.get("section1","k1"))
print(config.getint("section1","k1"))
print(config.getfloat("section1","k1"))
print(config.getboolean("section1","k5"))
# 配置文件test.ini
[section1]
k1=1
k2:"aaa"
# k3=4
; k4=4
k5=true
[section2]
k1=1
9、hashlib
'''
1、什么是哈希hash
任意长度的原始数据————————>hash算法————————>固定长度的hash值
特点:
Ⅰ 不能由hash值反解出内容
Ⅱ只要传入的内容一样,hash算法一样,得到的hash值必然一样
Ⅲ无论传入的内容有多大,只要使用的hash算法不变,得到的hash值长度是固定的
2、hash的用途
特点Ⅰ用于密码密文传输与验证
特点Ⅱ、Ⅲ用于文件完整性校验
'''
# 针对密文加密
import hashlib
m=hashlib.md5()
m.update("hello".encode("utf-8"))
m.update("world".encode("utf-8"))
res=m.hexdigest() # 'helloworld'
print(res)
# 针对文件完整性校验
f=open("a.txt",mode="rb")
m.update(f.read()) # 文件的所有内容太慢了
f=open("a.txt",mode="rb")
f.seek(1000)
m.update(f.read(20))
f.seek(3000)
m.update(f.read(20)) # 选取特定位置的字节进行hash运算
# 撞库
import hashlib
m=hashlib.md5()
m.update("cang0527".encode("utf-8"))
res=m.hexdigest()
print(res)
# 得到明文用户名与密文密码
user="cangyuan"
pwd="903e310503d2c8a615bcefede03a5521"
# 制作密码字典:
l=[
"cang111",
"cang123",
"cang444",
"cang0527"
]
dic={}
for i in l:
m=hashlib.md5()
m.update(i.encode("utf-8"))
dic[i]=m.hexdigest()
print(dic)
for k,v in dic.items():
if v==pwd:
print("撞库成功,密码是{}".format(k))
break
# 密码加盐
import hashlib
m=hashlib.md5()
m.update("天王".encode("utf-8"))
m.update("cang".encode("utf-8"))
m.update("盖地虎".encode("utf-8"))
m.update("0527".encode("utf-8"))
res=m.hexdigest()
print(res)
10、subprocess
import subprocess
obj=subprocess.Popen("dir",shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
) # 执行系统命令
print(obj)
res=obj.stdout.read()
print(res.decode("gbk"))
res=obj.stderr.read()
print(res)
11、logging
import logging
logging.basicConfig(
# 1、日志输出位置:终端、文件
filename='access.log', # 不指定,默认打印终端
# 2、日志格式
# %(name)s Logger的名字
# %(levelno)s 数字形式的日志级别
# %(levelname)s 文本形式的日志级别
# %(pathname)s 调试日志输出函数的模块的完整路径名,可能没有
# %(filename)s 调试日志输出函数的模块的文件名
# %(module)s 调试日志输出函数的模块名
# %(funcName)s 调试日志输出函数的函数名
# %(lineno)d 调试日志输出函数的语句所在的代码行
# %(created)f 当前时间,用UNIX标准的表示时间的浮点数表示
# %(relativeCreated)d 输出日志信息时的,自logger创建以来的毫秒数
# %(asctime)s 字符串形式的当前时间,默认格式是"2003-07-09 16:16:16,899"
# %(thread)d 线程ID,可能没有
# %(threadName)s 线程名,可能没有
# %(process)d 进程ID,可能没有
# %(message)s 用户输出的消息
format="%(asctime)s - %(name)s - %(levelname)s",
# 3、时间格式
datefmt="%Y-%m-%d %H:%M:%S",
# 4、日志级别(输出level级别之上的日志)
# debug => 10
# info => 20
# warning => 30
# error => 40
# critical => 50
level=20
)
logging.debug("调试")
logging.info("消息")
logging.warning("警告")
logging.error("错误")
logging.critical("严重")
# src.py
import settings
from logging import config,getLogger
config.dictConfig(settings.LOGGING_DIC)
# logger1=getLogger("logger1")
# logger1.info("这是一条info日志")
# logger1=getLogger("logger2")
# logger1.info("这是一条info日志")
logger1=getLogger("用户交易")
logger1.info("这是一条info日志")
# seettings.py
standard_format="%(asctime)s - %(name)s - %(levelname)s"
simple_format="%(asctime)s - %(name)s - %(levelname)s"
test_format="%(asctime)s - %(name)s - %(levelname)s"
LOGGING_DIC={
"version":1,
# 日志格式
"formatters":{
"formatter1":{
"format":standard_format
},
"formatter2":{
"format":simple_format
},
"formatter3":{
"format":test_format
}
},
# 日志的处理者,不同的handler会将日志输出到不同的位置
"handlers":{
# 打印到终端
"handler1":{
"level":"DEBUG",
"class":"logging.StreamHandler",
"formatter":"formatter1"
},
# 打印到文件
"handler2":{
"level":"DEBUG",
# "class":"logging.FileHandler",
"class":"logging.handlers.RotatingFileHandler", # 日志轮转
"maxBytes":200, # 超出200字节就切出去
"backupCount":5, # 切的次数
"filename":"a1.log",
"encoding":"utf-8",
"formatter":"formatter2"
}
},
# 日志的产生者,产生的日志会传递给handlers
"loggers":{
# 产生者1
"logger1":{
"handlers":["handler1","handler2"],
"level":"DEBUG",
"propagate":False
},
# 产生者2
"logger2":{
"handlers":["handler1"],
"level":"DEBUG",
"propagate":False
},
# 默认生产者
"":{
"handlers":["handler2"],
"level":"DEBUG",
"propagate":False
}
}
}
12、re
import re
# 元字符
print(re.findall("\w","aA\rbc\t\n12\f3_*()-= ")) # 匹配字母数字下划线
print(re.findall("\W","aA\rbc\t\n12\f3_*()-= ")) # 匹配非字母数字下划线
print(re.findall("\s","aA\rbc\t\n12\f3_*()-= ")) # 匹配空白符\n \t\r\f
print(re.findall("\S","aA\rbc\t\n12\f3_*()-= ")) # 匹配非空白符
print(re.findall("\d","aA\rbc\t\n12\f3_*()-= ")) # 匹配数字
print(re.findall("\D","aA\rbc\t\n12\f3_*()-= ")) # 匹配非数字
print(re.findall("^abc","abc is ab")) # 匹配行首
print(re.findall("sb$","abc is ab")) # 匹配行尾
print(re.findall("a.b","ab a1b a b abbbb a\nb a*b a\tb")) # 匹配任意字符(除\n)
print(re.findall("a.b","ab a1b a b abbbb a\nb a*b a\tb",re.DOTALL))
# 限定符
print(re.findall("ab*","a ab abb abbbbbbb bbbbbb")) # * 左测字符出现的次数为{0,}
print(re.findall("ab+","a ab abb abbbbbbb bbbbbb")) # + 左测字符出现的次数为{1,}
print(re.findall("ab?","a ab abb abbbbbbb bbbbbb")) # ? 左测字符出现的次数为{0,1}
print(re.findall("ab{2}","a ab abb abbbbbbb bbbbbb")) # {n} 左测字符出现的次数为n次
print(re.findall("ab{2,4}","a ab abb abbbbbbb bbbbbb")) # {n,m} 左测字符出现的次数为n到m次
print(re.findall("ab{2,}","a ab abb abbbbbbb bbbbbb")) # {n,} 左测字符出现的次数为n到无穷次
# 字符类
print(re.findall("a[012]b","a111b a3b a4b a9b aXb a b a\nb"))
print(re.findall("a[0-2]b","a111b a3b a4b a9b aXb a b a\nb"))
print(re.findall("a[a-zA-Z0-9]b","a111b a3b a4b a9b aXb a b a\nb"))
print(re.findall("a[^0-9]b","a111b a3b a4b a9b aXb a b a\nb"))
# 或运算符
# (a|b) 匹配a或者b
# (ab)|(cd) 匹配ab或者cd
# 贪婪/懒惰匹配
# <.+> 默认贪婪匹配“任意字符”
# <.+?> 懒惰匹配“任意字符”