Python知识笔记
1.运算符
2.字符串,列表,元组,字典的使用方法:
1.字符串
(1)切片:[起始:结束:步长]
(2)查找:
find():检测某个子串是否包含在这个字符串中,如果在返回这个子串开始的位置下标,否则则返回-1。字符串序列.find(子串, 开始位置下标, 结束位置下标)。
index():检测某个子串是否包含在这个字符串中,如果在返回这个子串开始的位置下标,否则则报异常。
(3)修改:
replace():替换。字符串序列.replace(旧子串, 新子串, 替换次数)
split():按照指定字符分割字符串。字符串序列.split(分割字符, num)
len():len(字符串)求长度
2.列表
(1)添加元素:
append(“需要添加的元素”),extend(“需要融合的元素”),insert(index,object)
(2修改元素:
index:通过下标修改object[inext]=“需要修改的值”
(3)查找元素:
in(存在),如果存在那么结果为true,否则为false
not in(不存在),如果不存在那么结果为true,否则false
index和count与字符串中的用法相同。object.index(“需要查找的元素”)
(4)删除元素:
pop:删除最后一个元素。列表.pop()
del:根据下标进行删除。del 列表[下标]
remove:根据元素的值进行删除。列表.remove(“需要删除的元素”)
(5)排序:
sort:顺排
reverse:逆排
3.元组:
(1)按下标查找数据:元组[下标]
(2)index():查找某个数据,如果数据存在返回对应的下标,否则报错
(3)count():统计某个数据在当前元组出现的次数。
(4)len():统计元组中数据的个数。
定义元组t=(10,)
4.字典:
(1)查找元素:根据key查找数据或者使用get来获取数据。字典[“ket”]或字典.get(“key”)
(2)修改元素:根据key元素进行修改。字典[“key”]=“值”
(3)添加元素:字典[‘键’] = 值时,这个“键”在字典中,不存在,那么就会新增这个元素
(4)删除元素:del删除指定的元素 del 字典[“key”],clear清空整个字典
字典.clear()。
3.文件的基本操作
代码实例:
# 1. 打开文件
f = open('test.txt', 'w')
# 2.文件写入
f.write('hello world')
# 3. 关闭文件
f.close()
#readlines可以按照行的方式把整个文件中的内容进行一次性读取,并且返回的是一个列表,其中每一行的数据为一个元素。
#readline()一次读取一行内容。
4.面向对象
流程图:
5.闭包
1.定义:在函数嵌套(函数里面再定义函数)的前提下,内部函数使用了外部函数的变量(还包括外部函数的参数)外部函数返回了内部函数
代码实例:
import time
# 装饰器函数
def get_time(func):
def inner():
begin = time.time()
func()
end = time.time()
print("函数执行花费%f" % (end-begin))
return inner
#@get_time相当于func1=get_time(func1)
@get_time
def func1():
for i in range(100000):
print(i)
func1()
6.网络编程
1.Web服务器返回html页面
代码实例:
# 导入模块
import socket
# 创建tcp服务端套接字
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口号复用,让程序退出端口号立即释放
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 给程序绑定端口号
tcp_server_socket.bind(("", 8989))
# 设置监听
# 128:最大等待建立连接的个数, 提示: 目前是单任务的服务端,同一时刻只能服务与一个客户端,后续使用多任务能够让服务端同时服务与多个客户端,
# 不需要让客户端进行等待建立连接
# listen后的这个套接字只负责接收客户端连接请求,不能收发消息,收发消息使用返回的这个新套接字来完成
tcp_server_socket.listen(128)
while True:
# 等待客户端建立连接的请求, 只有客户端和服务端建立连接成功代码才会解阻塞,代码才能继续往下执行
# 1. 专门和客户端通信的套接字: service_client_socket
# 2. 客户端的ip地址和端口号: ip_port
service_client_socket, ip_port = tcp_server_socket.accept()
# 代码执行到此说明连接建立成功
print("客户端的ip地址和端口号:", ip_port)
# 接收客户端发送的数据, 这次接收数据的最大字节数是1024
recv_data = service_client_socket.recv(1024)
# 获取数据的长度
recv_data_length = len(recv_data)
print("接收数据的长度为:", recv_data_length)
# 对二进制数据进行解码
recv_content = recv_data.decode("utf8")
print("接收客户端的数据为:", recv_content)
# 解析http协议请求报文数据
# 获取请求行
request_line = recv_content.split("\n")[0]
# 获取请求路径
request_path = request_line.split(" ")[1]
print("客户端的请求路径为:", request_path)
# 符合http协议的响应报文
# 响应行
response_line = "HTTP / 1.1 200 OK\r\n"
# 响应头
response_header = "Server: Tengine\r\n"
# 获取html数据
with open("./source/html/gdp.html", "r") as f:
file_data = f.read()
# 响应体
response_body = file_data
# 组成响应报文
response_data = response_line + response_header + "\r\n" + response_body
# 发送数据给客户端
service_client_socket.send(response_data.encode())
# 关闭服务与客户端的套接字, 终止和客户端通信的服务
service_client_socket.close()
# 关闭服务端的套接字, 终止和客户端提供建立连接请求的服务
tcp_server_socket.close()
2.FastAPI框架
代码实例:
# 导入FastAPI模块
from fastapi import FastAPI
# 导入响应报文Response模块
from fastapi import Response
# 导入服务器uvicorn模块
import uvicorn
# 创建FastAPI框架对象
app = FastAPI()
# 通过@app路由装饰器收发数据
# @app.get(参数) : 按照get方式接受请求数据
# 请求资源的 url 路径
@app.get("/index1.html")
def main():
with open("source/html/index1.html") as f:
data = f.read()
# return 返回响应数据
# Response(content=data, media_type="text/html"
# 参数1: 响应数据
# 参数2: 数据格式
return Response(content=data, media_type="text/html")
@app.get("/index2.html")
def main():
with open("source/html/index2.html") as f:
data = f.read()
# return 返回响应数据
# Response(content=data, media_type="text/html"
# 参数1: 响应数据
# 参数2: 数据格式
return Response(content=data, media_type="text/html")
# 运行服务器
# 参数1: 框架对象
# 参数2: IP地址
# 参数3: 端口号
uvicorn.run(app, host="127.0.0.1", port=8000)
7.多任务编程
1.概念:多任务是指在同一时间内执行多个任务,例如: 现在电脑安装的操作系统都是多任务操作系统,可以同时运行着多个软件。
2.多任务执行方式:并发和并行。并发:在一段时间内交替去执行任务。并行:对于多核cpu处理多任务,操作系统会给cpu的每个内核安排一个执行的软件,多个内核是真正的一起执行软件。这里需要注意多核cpu是并行的执行多任务,始终有多个软件一起执行。
3.进程的概念:
一个正在运行的程序或者软件就是一个进程,它是操作系统进行资源分配的基本单位,也就是说每启动一个进程,操作系统都会给其分配一定的运行资源(内存资源)保证进程的运行。
4.多进程的使用
(1)导入进程包:import multiprocessing
Process([group [, target [, name [, args [, kwargs]]]]])
group:指定进程组,目前只能使用None
target:执行的目标任务名
name:进程名字
args:以元组方式给执行任务传参
kwargs:以字典方式给执行任务传参
Process创建的实例对象的常用方法:
start():启动子进程实例(创建子进程)
join():等待子进程执行结束
terminate():不管任务是否完成,立即终止子进程
Process创建的实例对象的常用属性:
name:当前进程的别名,默认为Process-N,N为从1开始递增的整数
3.多进程完成任务的代码
代码实例:
import multiprocessing
import time
import os
# 跳舞任务
def dance():
# 获取当前进程的编号
print("dance:", os.getpid())
# 获取当前进程
print("dance:", multiprocessing.current_process())
# 获取父进程的编号
print("dance的父进程编号:", os.getppid())
for i in range(5):
print("跳舞中...")
time.sleep(0.2)
# 扩展:根据进程编号杀死指定进程
os.kill(os.getpid(), 9)
# 唱歌任务
def sing():
# 获取当前进程的编号
print("sing:", os.getpid())
# 获取当前进程
print("sing:", multiprocessing.current_process())
# 获取父进程的编号
print("sing的父进程编号:", os.getppid())
for i in range(5):
print("唱歌中...")
time.sleep(0.2)
if __name__ == '__main__':
# 获取当前进程的编号
print("main:", os.getpid())
# 获取当前进程
print("main:", multiprocessing.current_process())
# 创建跳舞的子进程
# group: 表示进程组,目前只能使用None
# target: 表示执行的目标任务名(函数名、方法名)
# name: 进程名称, 默认是Process-1, .....
dance_process = multiprocessing.Process(target=dance, name="myprocess1")
sing_process = multiprocessing.Process(target=sing)
# 启动子进程执行对应的任务
dance_process.start()
sing_process.start()
4.多进程带有参数
代码实例:
import multiprocessing
import time
def dance(count):
for i in range(count):
print("dance.....")
time.sleep(0.5)
if __name__ == '__main__':
#实例化进程对象
#给执行的函数传入参数,通过args和kwargs参数
#args:接收的是一个元组(元素1,)
#kwargs:接收的是一个字典,{key,value}
p1=multiprocessing.Process(target=dance,args=(5,))
p2 = multiprocessing.Process(target=dance, kwargs={'count':5})
p1.start()
p2.start()
5.进程中注意点
(1)进程之间不共享全局变量,主进程会等待所有的子进程执行结束再结束,
进程守护有两种方式:子进程对象.daemon=True.子进程对象.terminate()
代码实例:
import multiprocessing
#定义全局变量
import time
data_list=[1,2,3]
#定义添加数据的函数
def add_data():
global data_list
for i in range(5):
data_list.append(i)
print(f"数据添加完毕:{data_list}")
#定义获取数据的函数
def read_data():
global data_list
print(f"读取的数据是:{data_list}")
def sing():
for i in range(10):
print("我要下班了")
time.sleep(1)
#创建多进程任务
if __name__ == '__main__':
#创建子进程的时候会将主进程的全局变量拷贝一份
p1=multiprocessing.Process(target=add_data)
p2 = multiprocessing.Process(target=read_data)
p3=multiprocessing.Process(target=sing)
#启动子进程
p1.start()
p2.start()
# 线程守护:主进程结束后会等待子进程结束后再结束
# 子进程对象名.daemn=True销毁子进程的方式:子进程对象.terminate()
#给子进程设置一个属性,让子进程随着主进程的结束而结束
#默认值为false
p3.sing=True
p3.start()
time.sleep(5)
# 手动结束子进程,子进程开始之后设置
# p3.terminate()
print("主进程执行完毕了")
6.线程
1.线程概念:线程是进程中执行代码的一个分支,每个执行分支(线程)要想工作执行代码需要cpu进行调度 ,也就是说线程是cpu调度的基本单位,每个进程至少都有一个线程,而这个线程就是我们通常说的主线程。
2.线程类Thread参数说明
Thread([group [, target [, name [, args [, kwargs]]]]])
group: 线程组,目前只能使用None
target: 执行的目标任务名
args: 以元组的方式给执行任务传参
kwargs: 以字典方式给执行任务传参
name: 线程名,一般不用设置
3.线程执行带有参数
代码实例:
import threading
import time
def dance(count):
for i in range(count):
print(f"我在跳舞{i}")
time.sleep(0.5)
def sing(count):
for i in range(count):
print(f"我在唱歌{i}")
time.sleep(0.5)
if __name__ == '__main__':
p1=threading.Thread(target=dance,args=(5,))
p2=threading.Thread(target=sing,kwargs={'count':5})
p1.start()
p2.start()
4.线程守护
1.线程之间是无序的,他是由cpu调度决定的,设置守护线程由两种方式1.线程对象.setDaemon(True) 2.thread.Thread(target=sing,daemon=True)
代码实例:
import threading
import time
def task():
time.sleep(1)
print(f"当前的线程是:{threading.current_thread().name}")
def sing():
for i in range(5):
print("我在唱歌")
time.sleep(0.5)
if __name__ == '__main__':
# print(f"当前的主线程是:{threading.current_thread().name}")
# 实例化线程,线程执行是无序的
# for _ in range(5):
# sub_threading=threading.Thread(target=task)
# sub_threading.daemon=True
# sub_threading.start()
# 线程守护
sub_threading1 = threading.Thread(target=sing)
#第一种方式守护线程
# sub_threading1 = threading.Thread(target=sing,daemon=True)
#第二种方式守护线程
sub_threading1.setDaemon(True)
sub_threading1.start()
time.sleep(2)
print(f"当前的主线程是:{threading.current_thread().name}")
3.线程之间共享全局变量
问题:多线程任务是多个线程同时执行,此时各自线程拿到的g_num=0,然后进行n+1的操作,线程1进行+1,此时g_num=1,而线程2此时拿到的g_num=0,放到了缓冲区此时就会导致数据统计不准确。
如何解决,就需要分开计算,使用对象名.join()避免资源竞争,保证同一时刻,只能只有一个任务在执行。
while回顾:with语句系统会自动调用f.close。在数据修改之后,如果数据的内存没有发生改变,数据就是可变类型。如果数据的内存地址发生了改变,数据就是不可变类型,可变类型:列表,字典,集合。不可变类型:数字,字符串,元组。浅拷贝copy.copy(a),浅拷贝对于可变类型的数据只会拷贝外层的内存地址,内层的内存地址不会进行拷贝。对于不可变的数据:不会给不可变的数据生成一个新的内存地址。可变类型的深拷贝:copy.deepcopy(a)。
(1)不可变类型的深拷贝:不可变类型进行深拷贝如果子对象没有可变类型则不会进行拷贝,而只是拷贝了这个对象的引用,否则会对该对象到最后一个可变类型的每一层对象就行拷贝, 对每一层拷贝的对象都会开辟新的内存空间进行存储。
(2)可变类型的深拷贝:通过上面的执行结果可以得知, 可变类型进行深拷贝会对该对象到最后一个可变类型的每一层对象就行拷贝, 对每一层拷贝的对象都会开辟新的内存空间进行存储。
8.正则表达式
1.re模块的使用
代码实例:
import re
#match方法:从头开始匹配字符串数
#参数1:正则表达式规则
#参数2:要匹配的数据(字符串)
# 返回一个匹配的结果对象
my_str="itcast.cn"
ret=re.match("itcast",my_str)
print(ret)
print(ret.group())#返回匹配到的正则表达式字符串结果
if ret:
print(f"匹配到的数据是:{ret.group()}")
else:
print("匹配失败...")
2.匹配单个字符:
"."匹配任意1个字符,[ ]匹配列表中的字符,
“[ ]” 匹配[ ]中列举的字符
“\d” 匹配数字,即0-9
“\D” 匹配非数字,即不是数字
“\s” 匹配空白,即 空格,tab键
“\S” 匹配非空白
“\w” 匹配非特殊字符,即a-z、A-Z、0-9、_、汉字
“\W” 匹配特殊字符,即非字母、非数字、非汉字
3.匹配多个字符:
"*"匹配前一个字符出现0次或者无限次,即可有可无
“+” 匹配前一个字符出现1次或者无限次,即至少有1次
“?” 匹配前一个字符出现1次或者0次,即要么有1次,要么没有
“{m}” 匹配前一个字符出现m次
“{m,n}” 匹配前一个字符出现从m到n次
4.匹配开头和结尾:
“^” 匹配字符串开头
“$” 匹配字符串结尾
5.匹配分组:
“|” 匹配左右任意一个表达式
“(ab)” 将括号中字符作为一个分组
“\num” 引用分组num匹配到的字符串
“(?P)” 分组起别名
“(?P=name)” 引用别名为name分组匹配到的字符串
代码实例:
import re
# | 匹配左右任意一个表达式
# ret=re.match("([a-zA-Z0-9_]{4,10})@(qq|163)\.com$","1234@qq.com")
# (ab) 将括号中字符作为一个分组
# \num 引用分组num匹配到的字符串
mystr="<html><div>这是一个嵌套</div></html>"
# ret=re.match("<([a-zA-Z0-9]+)><([a-zA-Z0-9]+)>.*</\\2></\\1>",mystr)
# (?P<name>) 分组起别名
# (?P=name) 引用别名为name分组匹配到的字符串
ret=re.match("<(?P<name1>[a-zA-Z0-9]+)><(?P<name2>[a-zA-Z0-9]+)>.*</(?P=name2)></(?P=name1)>",mystr)
if ret:
print(f"匹配到的数据是{ret.group()}")
# print(ret.groups())#取出匹配到的字符串分组的结果,组成元组
# print(ret.group(0))#取出匹配到的字符串
# print(ret.group(1))#取出匹配到的第一个分组中的字符串
# print(ret.group(2))#取出匹配到的第二个分组中的字符串
else:
print("匹配失败.....")
5.正则表达式拓展:
代码实例:
import re
# re.match("正则表达式",字符串) 从字符串开头进行匹配
# ret = re.match("abc","1111abc")
# re.search("正则表达式",字符串) 扫描整个字符串并返回第一个匹配成功的结果
# ret = re.search("abc","1111abcabcabc")
# print(ret.group())
# re.findall("正则表达式",字符串) 扫描整个字符串并返回所有匹配成功的结果,返回的是列表,如果没有匹配成功,返回的是空列表
# 在使用findall时,获取匹配到的数据直接进行打印,不需要再用group()
# ret = re.findall("abc","111abc222abc333abc") # ['abc', 'abc', 'abc']
# ret = re.findall("abc", "1234567") # []
# print(ret)
# re.sub("旧的元素","新的元素",字符串,count) 替换,和字符串类型的replace方法类似,返回新的字符串
# count:替换的次数,默认不写是替换所有的正则表达式内容
# ret = re.sub("-","*","python-59期-a",1)
# print(ret)
# re.split("分割符号",字符串,maxsplit) maxsplit:默认不限次数的分割,返回的是列表
# ret = re.split("-","python-59期-a",1)
# print(ret)
# 修饰符 ignore
# ret = re.match("hello","Hello",re.I)
# 忽略换行符,让 . 可以匹配到 \n
ret = re.match(".","\n", re.S)
print(ret.group())
9.网络爬虫
1.网页蜘蛛,网络机器人,按照一定的规则,自动的爬取网络信息的程序或者脚本,百度引擎本质就是利用爬虫技术搜索信息
2.爬虫的基本步骤
准备地址
发送请求,获取响应
解析响应数据
保存数据(保存数据到数据库)
3.安装:pipi install requests
4.zip() 函数: 用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表.
代码实例:
import requests
import re
import pyecharts.options as opts
from pyecharts.charts import Pie
#准备url地址
def get_gdp():
url="http://127.0.0.1:8080/gdp.html"
reponse=requests.get(url)
data=reponse.content.decode()
# print(data)
name=re.findall('<a href=""><font>(.*?)</font></a>',data)
gdp=re.findall('<font>¥(.*?)亿元',data)
#zip函数列表进行
list1=zip(name,gdp)
list2=list(list1)
return list2
def get_fenxi(list2):
pie=Pie(init_opts=opts.InitOpts(width="1400px",height="800px"))
pie.add(
"GDP",
list2,
label_opts=opts.LabelOpts(formatter='{b}:{d}%')
)
# pie.set_global_opts(title_opts=opts.TitleOpts(title="2020年世界GDP排名", subtitle="美元"))
pie.render()
if __name__ == '__main__':
ret=get_gdp()
get_fenxi(ret)
10.日志
1.logging打印日志
level:修改日志输出的等级,默认是warning
%(asctime)s:日期时间
%(filename):文件名称
line:%(lineno)d:行号,哪一行输出了信息
%(message)s:日志信息
filename:将日志信息保存到文件中
filemode:以什么形式保存,w:覆盖,a:追加
# 导入日志模块
import logging
# 配置日志
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s',
filename="log.txt",
filemode="w")