一、变量和输出
def main():
在这里编程
pass
if __name__ == '__main__':
main()
def main():
# 1.变量
a = 1
b = "haha ni ye hao"
c = b
#print(a)
#print(b) #print(c)
# 2.注释
#单行注释
'''
多行注释
'''
# 3.拼接
#name = input("请输入你的姓名:")
#print("欢迎",name)
#print("欢迎" + name + "过来")
#print("haha nihao")
'''
4.布尔型
true = 1 false = 0 ''' #d = True
#print(d)
#格式化输出
name = input("姓名:")
age = input("年龄:")
job = input("工作:")
info = "name is %s ! age is %s ! job is %s"%(name,age,job)
print(info)
pass
if __name__ == '__main__':
main()
二、运算符
'''
运算符
+ - * / % **
!= < >
==
> < >= <=
'''
''' a = 4
#a += 1 # a = a+1
b = 2
c = a % b
print(c)
'''
#成员运算符
a = 'abc'
b = 'fiosejfapoksaopfkengabcfpjoweaabcoo[afke'
print(a in b)
三、流程控制
input 进来的东西都是字符串!!!
利用 int 强制转换成数字
# if语句
"""
age = 17
if age > 18:
print("成年了")
elif age < 16:
print("aaa")else:
print("还没有")
"""
# while语句
"""
print("小游戏开始")
num = 101
while True:
guess = int(input("你猜猜数字是啥:")) #input里面的都是字符串!
if guess < num: print("哈哈 小了")
elif guess > num: print("哈哈 大了")
else: print("答对了")
break """
四、字符串切片
计算机大多数情况计算从0开始
#字符串切片
"""
a = "abcdefghijklmn"
print(a[0:3])#从第0个开始取3个
print(a[2:])#从第2个开始,到最后
print(a[2:-1])#从第2个开始,取 到! 倒数第一个之前
print(a[1:10:2])#从第1个开始取到直到第十个,步长为2
"""
五、常用字符串处理方法
"""
a = "aABCabc123haha!"
b = "haha nihao wo ye hao"
c = "**ha**ha**"
d = "192.168.1.2"
# 1.capitalize()首字母大写,其他自动小写
print(a.capitalize())
# 2.swapcase()大小写反转
print(a.swapcase())
# 3.title()每个单词首字母大写
print(b.title())
# 4.center 变量居中,用8个位置,空的位置用*代替
print(c.center(8,"*"))
# 5.startswith() 判断以什么开头
print(c.startswith("h"))
#从计算机的第五个(人类第6个)取到人类的第7个是不是ni
print(b.startswith("ni",5,7))
# 6.endswith() 判断以什么结尾
print(b.endswith("ao",18,20))
# 7.发现ih的i在计算机的第几个
print(b.find("ih"))
# 8.replace() 替换,前两个a替换为N
print(a.replace('a','N',2))
# 9.isalpha() 判断字符串中是否都是字母
print(c.isalpha())
# 10.isnumberic() 判断字符串中是否是纯数字
print(a.isnumeric())
# 11.strip() 只能去掉左右的*,中间去不掉
#lstrip() 去掉左边的
#rstrip() 去掉右边的
print(c.strip('*'))
# 12.split 以 . 的形式分割,分割结果是列表
print(d.split('.'))
"""
六、列表 [ ]
如何去重:
列表→集合
集合→列表
"""
# 列表 [ ]
li = ['xiaoming','xiaoli','xiaohong']
# 1.访问
print(li[2])
# 2.插入
li.insert(1,'haha')
print(li)
# 3.插入到最后
li.append('nihao')
print(li)
# 4.删除最后一个
li.pop()
print(li)
# 5.批量删除
del li[1:3]
print(li)
# 6.精确删除
li.remove('xiaoming')
print(li)
# 7.修改
li[0] = 'wobuzhidao'
print(li)
# 8.删除所有
li.clear()
print(li)
zz = [1,2,3,4,2,5,6,2,7,8]
# 9.计算2出现的次数
ret = zz.count(2)
print(ret)
# 10.计算 5 第一次出现的位置
net = zz.index(5)
print(net)
"""
七、字典 { }
字典是无序的,而且是以 键值对 来记录数据
"""
#字典 { }dic = {"name":"xiaoming","age":"18","job":"driver"}
# 1.增加数据
dic["home"] = "xuanwuqu"
print(dic)
# 2.删除
dic.pop("age")
print(dic)
# 3.修改
dic["job"] = "lose"
print(dic)
# 4.查
value = dic["name"]
print(value)
value2 = dic.get("a","xxxxxx")# 查找a,如果查不到就返回xxxxxx
print(value2)
# 遍历字典的内容
for key,value in dic.items():
print(key + "--------" + value)
# 只遍历键值对里的键
for i in dic:
print(i)
# 只遍历键值对中的值
for j in dic:
print(dic[j])
print(dic.keys())
print(dic.values())
"""
八、集合 { }
{ }
无序,但是不允许重复
"""
#集合
set1 = {1,2,8,9,3,4,5,6,5,7,2,1} set2 = {7,8,1,9,1,9,8,7} print(set1)
# 1.增
set1.add('aaa')
# 2.删除
set1.remove(3)#删除3这个值,并且自动排序
print(set1)
# 3.随机删除
set1.pop()# set1.clear() #删除所有
# 4.取交集
print(set1 & set2)
# 5.取并集
print(set1 | set2)
# 6.取差集
print(set1 - set2)
# 7.取反交集
print(set1 ^ set2) """
九、元祖 ( )
( )
tuple
无法改变 没有增,删,改
"""
#元祖 tuple
x = ['l1','l2','l3','l2','l4']
y = ("haha1","haha2","haha3")
#print(y)
# 列表 → 元祖
x1 = tuple(x) # 对数据的保护,防止别人修改
print(x1)
# 列表 → 集合
x2 = set(x) #对数据去重
print(x2)
# 元祖 → 列表
y1 = list(y)
print(y1)
"""
十、文件操作
r – 读
w – 写
a – 追加
r+ w+ a+ 基于字符的读写
对于二进制的读写
rb wb ab
文件的本指 – 句柄(唯一标识符)
10.1 读操作
读写文件基本操作
"""
#f就是句柄
f = open("./a.txt","r") #若对f操作,即对a.txt操作
print(f)
#从句柄中读取内容
data = f.read()
print(data)
#关闭文件句柄
f.close()
"""
import os
f = open("./a.txt", "r")
"""
#判断文件是否存在
print(os.path.isfile("D:/ObsidianNotes/Python/a.txt"))
print(os.path.isfile("./a.txt"))
#一行一行读
data = f.readline()
print(data)
#读取每一行,并且保存 每一行 为列表(\n换行符也读出)
data1 = f.readlines()
print(data1)
"""
while True:
info = f.readline(4) # 每次读取4个字
print(info)
if len(info) == 0: # 什么时候读不出来了
break
10.2 写操作
f = open("./a.txt", "w")
# 写入的内容,原来内容会被清空
# 如果文件不存在,则会自动创建
f.write("wobuhao")
10.3 追加操作
f = open("./a.txt", "a")
# 追加内容
f.write("heiheihei")
f.close()
10.4 免关闭
# 免关闭文件操作
with open("./a.txt","a") as f:
f.write(">>>>>????")
with open("./a.txt","r") as f:
print(f.read())
同时操作两个文件
with open("./a.txt","r") as f1,open("./b.txt","a") as f2:
data = f1.read()
data = data.replace('a','N')
f2.write(data)
十一、操作系统命令
import os
#创建文件夹
os.mkdir("c:/abcd")
#删除文件夹
os.rmdir("c:/abcd")
#列出文件夹的内容
print(os.listdir("c:/dell"))
#执行操作系统的命令
os.system("whoami")
os.system("ipconfig")
print(os.system("mkdir 123"))
十二、函数介绍
12.1 无返回值
# 有返回值的函数
def my_len():
s = 'haha nihao'
length = 0
for i in s :
length += 1
print(length)
def main():
my_len()
12.2 有返回值
# 有返回值的函数
def my_len():
s = 'haha nihao'
length = 0
for i in s :
length += 1
return length
def main():
a = my_len()
print(a)
pass
12.3 有参数
# 有参数的函数
def maxnum(x,y):
if x > y:
the_max = x
else:
the_max = y
return the_max
def main():
a = maxnum(10 ,59)
print(a)
12.4默认参数
# 默认参数的函数
def maxnum(x,y=20):
if x > y:
the_max = x
else:
the_max = y
return the_max
def main():
a = maxnum(10 ,59)
print(a)
pass
12.5 匿名函数
#匿名函qqqqqqq数
x = lambda y,z:y+z
print(x(2,3))
12.6 函数名的写法
函数名里面是一个内存地址
<function fun1 at 0x00000237852EE040>
有这个内存地址的任,加个 () 就可以运行了
def fun1():
print("i am fun1")
pass
def main():
f = fun1 #fun1的内存地址
print(fun1)
print(f)
f()
def f1():
print("i am fun1")
pass
def f2():
print("i am fun2")
pass
def f3():
print("i am fun3")
pass
def main():
li = [f1,f2,f3]
dic = {"hanshu1":f1,"hanshu2":f2,"hanshu3":f3}
li[0]()
dic["hanshu3"]()
十三、函数各种参数类型
13.1 默认参数
默认参数是一个可变数据类型
#默认参数是可变参数
def demo(a,li=[]):
li.append(a)
print(li)
def main():
demo('abc')
demo('cde')
13.2 不定参数
列表穿参数,但是最后会转换成元祖
# 不定参数
def fun1(name,age,*args):
print("name is:",name)
print("age is:",age)
print("args is:",args)
print("other is:",args[0])
print("other is:",args[1])
pass
def main():
y = ['a', 'b', 'c', 'd']
t = ('a','b','c','d') # 通过元祖或列表加个*,需要前面加*
fun1(*y) # 列表穿参数,但是最后会转换成元祖
print("----------------")
fun1(*t)
print("----------------")
fun1('a','b','c','d')
#print(*(1,2,3,4))
#print((1,2,3,4)) pass
13.3 字典参数
# 传字典参数
def fun2(**dic):
print(dic)
pass
def main():
dic1 ={"name" : "xiaoming","age" : 12 }
fun2(**dic1)
pass
13.4 多种参数
*args元祖,用于非关键字参数
**kwargs字典,用于关键字参数
#多种参数传递
def fun1(a,b,*args,**kwargs):
print(a)
print(b)
print(args)
print(kwargs)
def main():
fun1(1,2,3,4,5,name="n1",job="n2")
十四、作用域
14.1 locals()
locals()
本地(本函数)定义的所有变量都会以字典的形式存在这里
14.2 globals()
globals()
在外部定义的所有变量都会以字典的形式存在这里
全局变量在用之前,需要声明
# 全局变量
c = 100
def fun1():
# 声明要使用全局变量
global c
c = c+ 2
print(c)
pass
def main():
fun1()
但是列表、字典以及集合直接用,不用声明
li = [1,2,3]
dic = {"name":"xiaoming","age":"18"}
def fun1():
li.append(99)
print(li)
print(dic)
def main():
fun1()
14.3 仅使用上一层变量⭐⭐⭐
def add_b():
b = 1
def do_global():
b = 10 #b=30
def dd_nonlocal():
#使用上一层的b,上一层b以及做了修改
nonlocal b #b=10
b = b+20 #b=30
print(b)
pass
pass dd_nonlocal()
print(b)
pass
do_global()
print(b)
pass
def main():
add_b()
14.4 函数的嵌套
# 函数的嵌套
def mymax(x,y):
m = x if x > y else y
return m
def maxmax(a,b,c,d):
res1 = mymax(a,b)
res2 = mymax(res1,c)
res3 = mymax(res2,d)
return res3
def main():
ret = maxmax(23,156,78,200)
print(ret)
十五、闭包
分为两层,外函数和内函数
闭包可以直接调用外层参数和变量
15.1 闭包基础
# 外函数
def outer(a):
b = 10
# 内函数
def inner():
print(a+b)
#外函数返回值是内函数的引用(内存地址)
print(inner.__closure__) # 判断inner是否是闭包,如果是,就返回cell,如果不是就返回none
return inner
def main():
a = outer(15)
#print(a)
a()
#b = outer(17)
#b()
def wrapper():
money = 1000
def func():
name = "apple"
def inner():
print(name,money)
return inner
return func
def main():
f = wrapper()# 此时f应该是func的内存地址
i = f() #此时的i应该是inner的内存地址
i()
15.2 闭包传参
# 闭包传参
def func(a,b):
def inner(x):
return a*x+b
return inner
def main():
f = func(4,5) # f是inner的内存地址,并且此时这个inner里面4*x+5,等待传输x
print(f(2))
import time
def fun1():
time.sleep(3)
print("i am fun1")
def timer(fun):
def inner():
start = time.time()# 获取开始时间
fun()
print(time.time() - start)#结束时间-开始时间
return inner
def main():
a = timer(fun1)
a()
pass
15.3 装饰器
15.3.1 带参数
import time
# 带参数的装饰器
def timer(fun):
def inner(a): #闭包函数需要携带参数
start = time.time()
fun(a) #执行的时候也要携带参数
end = time.time()
print(end - start)
return inner
# 装饰器,在运行装饰器装饰的函数 (fun1) 的时候,会把目标函数(fun1)放到装饰器(timer)里运行
@timer
def fun1(a):
time.sleep(a)
print('hello world')
def main():
fun1(5)
15.3.2 带多种参数
import time
# 包含多种参数的装饰器
def timer(func):
def inner(*args,**kwargs):
func(args,kwargs)
return inner
@timer
def func(*args,**kwargs):
print(args,**kwargs)
def main():
func('a','b',123,124,name="haha1",age="18")
pass
15.3.3 额外知识
def func():
'''
我是注释的内容
''' print("i am fun1")
def main():
print(func.__doc__) #打印函数中的注释内容
print(func.__name__)#打印函数名
15.3.4 装饰器传参
def outer(flag):
def timer(func):
def inner(a):
if flag:
print("函数开始执行")
func(a)
print("函数执行结束")
else:
print("请开启flag")
return inner
return timer
@outer(True) # flag = True
def func1(a):
print("haha---",a)
def main():
func1("haha nihao")
15.3.5 多个装饰器
# 多个装饰器,注意多个装饰器的启动和结束规律:
# 1开始 2开始 运行 2结束 1结束
# 关于函数自身运行对称
def wrapper1(func):
def inner():
print("装饰器1号启动")
func()
print("装饰器1号结束")
return inner
def wrapper2(func):
def inner():
print("装饰器2号启动")
func()
print("装饰器2号结束")
return inner
@wrapper1
@wrapper2
def func1():
print("haha")
十六、迭代器
16.1 手工迭代
li = [1,2,3,4,5]
#开始使用迭代器迭代
li_iter = li.__iter__()
#迭代一个,手工迭代
item1 = li_iter.__next__()
print(item1)
item2 = li_iter.__next__()
print(item2)
item3 = li_iter.__next__()
print(item3)
item4 = li_iter.__next__()
print(item4)
item5 = li_iter.__next__()
print(item5)
#没有东西可以迭代,所以报错
item6 = li_iter.__next__()
print(item6)
16.2 自动迭代
def main():
li = [1,2,3,4,5]
li_iter = li.__iter__()
#自动迭代
while True:
try:# 捕获异常,如果try里的东西出现异常,就直接执行except的内容
item = li_iter.__next__()
print(item)
except:
print("迭代结束")
break
十七 、生成器
主函数通过next去控制,
几个next就到几个yield
每一个yield就返回一个东西
17.1 手动生成器
yield 和 next 搭配 也可以是send()
# 生成器
def gen_func1():
a = 1
print("将a赋值")
yield a # 中断函数 并且return a,等待下一个next才会继续执行
b = 2
print("将b赋值")
yield b
def main():
g1 = gen_func1()
print(next(g1))
time.sleep(2)
print(next(g1))
17.2 自动生成器
17.2.1 方法一
#自动生成
def produce():
for i in range(100):
yield "生产了%s个包子"%(1+i)
def main():
p = produce()
num = 0
for i in p:#此时p.__next__()就是i
print(i)#相当于调用了yield
num += 1
if num == 12:
break
17.2.2 方法二
#自动生成
def produce():
for i in range(100):
yield "生产了%s个包子"%(1+i)
def main():
p = produce()
num = 0
for i in range(12):
print(p.__next__()) #相当于调用yield
17.3 yield传入参数
# yield 传入参数
def gen():
print(123)
content = yield 1 # 中断,return 1,外边send内容给content
print("========",content)
print(456)
yield 2
def main():
g = gen() # 拿到生成器,才可以去控制
ret1 = g.__next__() # ret1 = 1
print("第一个yield返回",ret1)
ret2 = g.send("haha i am coming") # 传入参数 给第一个yield发东西,发完自动执行next
print("第二个yield返回",ret2)
十八、推导式
用一句话来表达
18.1 列表推导式
#列表推导式
#列表里的数据都是i,i的范围是0~30,如果i整除3是0,则加入列表
mul = [ i for i in range(30) if i%3 is 0]
print(mul)
fruits = [['apple','banana','orange','almond','date','coconut'],['fig','hazel','grape','haw','greengage']]
#找到嵌套列表中包含2个a字母的水果的名字
# 一个大列表fruits 有两个小列表 lstprint([name for lst in fruits for name in lst if name.count('a')>=2])
18.2 函数列表推导式
def squared(x):
return x*x
def main():
mul = [ squared(i) for i in range(30) if i%3 is 0]
print(mul)
结果
[0, 9, 36, 81, 144, 225, 324, 441, 576, 729]
18.3 字典推导式
键值对调换
dic1 = {'a':1,'b':2}
dic2 = {dic1[k]:k for k in dic1}
"""
k dic[k]
'a' 1
'b' 2
"""
print(dic2)
18.4 集合推导式
li = [1,2,3,4,-1,-2]
s = {x**2 for x in li}
print(s)
十九、执行函数
19.1 eval
eval 执行字符串所代表的代码,并且返回结果
eval函数十分危险!因为会把传入的字符串当作Python代码执行
#因为用 ' ' 包裹起来所以是字符串,所以不会当作程序来执行
s = 'print("haha")'
print(s)
# 把s里面的字符串,当作python代码来执行
eval(s)
pass
19.1 exec
exec 与eval同样危险
s = 'os.system("ipconfig")'
exec(s)
二十、模块
每一个py文件都是一个模块
(对于py起的文件名,必须避开关键字)
20.1 导入全部模块
#import test123 #引入外部文件
def main():
#test123.func1() 如果用import test123
from test123 import * #引入test123中的所有函数
def main():
func1()
func2()
20.2 导入部分模块
from test123 import func1 #如果只需要引入某个函数
def main():
func1() #直接调用
20.3 取别名
import test123 as nn #给test123引入之后取一个别名,叫nn
def main():
nn.func1() #import test123 as nn
20.4 引用限制
__all__=['func1','func3'] #人家引用你的时候,最多只能用func1,func3
def func1():
print("func1")
def func2():
print("func2")
def func3():
print("func3")
20.5 Python自带模块
20.5.1 json模块
import json
def main():
#序列化
dic = {'k1':'v1','k2':'v2','k3':'v3'}
str = json.dumps(dic) #将一个字典转化为字符串
print(type(dic))
print(type(str))
#反序列化
dic2 = json.loads(str)
print(type(dic2))
20.5.2 加密模块
hashlib模块(MD5)
import hashlib
def main():
md5 = hashlib.md5() #使用md5对以后的数据进行摘要加密操作
md5.update('hahanihao'.encode('utf-8')) #对目标进行操作(对字符串加密之前要转为utf-8)
print(md5.hexdigest()) #结果就是字符串md5加密后的密文(十六进制)
20.5.3 配置文件
import configparser
def main():
#初始化
conf = configparser.ConfigParser()
conf['default'] = {'money':100,'go':'yes','weapon':'no'}
conf['home'] = {'island':'xiaodao1'}
with open('./config','w') as f:
conf.write(f) #配置文件的写入(固定的格式填入配置文件)
![[Pasted image 20260315110439.png]]
基本操作
import configparser
def main():
#初始化
conf = configparser.ConfigParser()
conf.read('config') #读取配置文件
print('home' in conf) #判断是否存在
#遍历所有的key
for key in conf['default']:
print(key)
#获取键对应的值
print(conf.get('default','money')) #section 键
#获取所有的键值对 # option 条目
print(conf.items('default'))
#获取所有的键
print(conf.options('default'))
#增加键
conf.add_section('tank')
#删除键
conf.remove_section('home')
#删除条目
conf.remove_option('default','weapon')
#修改条目
conf.set('default','money','777')
conf.write(open('config.new','w'))
20.5.4 坐标系模块
from collections import namedtuple #坐标系
def main():
#定义一个名为point的坐标,坐标两个参数分别叫x,y
point = namedtuple('point',['x','y','z'])
p = point(7,8,9)
print(p.x,p.y,p.z)
20.5.5 时间模块
import time
def main():
print("start")
time.sleep(2)
print("end")
import time
def main():
#输出当前时间戳(从1970-1-1 0:0:0 一直到现在的秒数)
print(time.time())
#输出当前的24小时时间
print(time.strftime('%y-%m-%d %X'))
print(time.strftime('%y/%m/%d %H:%M'))
20.5.6 日期模块
import datetime
import time
def main():
sjc = time.time()
print(sjc)
#显示当前日期时间
now = datetime.datetime.now()
print(now)
#3周后的时间
print(datetime.datetime.now() + datetime.timedelta(weeks=3))
print(now.replace(year = 1977,month=1,day=1))
#时间戳转为当前时间
print(datetime.date.fromtimestamp(sjc))
二十一、包
模块可以是一个文件,但是一个包可以是很多模块
![[Pasted image 20260315100131.png]]
新建文件夹,文件夹里必须包含文件名为__init__.py!的文件
![[Pasted image 20260315100658.png]]
二十二、随机数
#随机数
import random
def main():
# 输出0-1之间的小数
print(random.random())
# 取0-4之间的小数
print(random.uniform(0,4))
# 取1-5之间的整数
print(random.randint(1,5))
#取1-10之间的奇数
print(random.randrange(1,10,2))
# 取1-10之间的偶数
print(random.randrange(0,10,2))
#随机选择一张牌
ret = random.choice(['梅花4','黑桃Q','方块K'])
print(ret)
#随机选择两张牌
a,b = random.sample(['梅花A','梅花2','梅花3','梅花4','方块A'],2)
print(a,b)
item = ['梅花A','梅花2','梅花3','梅花4','方块A']
random.shuffle(item)
print(item)
22.1 生成验证码
生成验证码小程序
import random
def v_code():
code = ''
for i in range(4):
num = random.randint(0,9)
Alf = chr(random.randint(65,90)) #chr(65) chr(65) = A
alf = chr(random.randint(97,122))
add = random.choice([num,Alf,alf]) #在0-9和A-Z子母中随便选一个
code = "".join([code,str(add)]) #加入到code里面
return code
def main():
yzm = v_code()
print(yzm)
二十三、正则表达式 ⭐⭐⭐
23.1 查找
23.1.1 re.findall()
查找字符串中匹配条件的内容,搜索整个字符串
`r '关键字'`
查找某一个关键字
import re
def main():
str1 = "fjasopefjkl210-48239-rtfujawp[e12-=e4145j39r" #目标
s = r'jkl' #寻找jkl,如果找到,会将其加入list,正则表达式
print(re.findall(s,str1))
`r't[io]p'` 不知道具体关键字,但是知道部分
r'^abc' 寻找以abc开头
寻找范围:在整个目标语句中,不被空格或其他干涉
`r'486$'` 寻找以abc结尾
寻找范围:在整个目标语句中,不被空格或其他干涉
`r'^q\$y'`
寻找以 q$y 开头的
利用转义字符 \ ,将本会被计算识别的`$`(结尾),识别成正常的 `$`
\ 转义字符,如果\接符号,转为正常意思
如果\接字母,具体对待
`r'\d'` 寻找所有的数字
`r'\D'`寻找所有的非数字(包括空格之类的)
`r'\s'`匹配空字符
`r'S'`匹配非空字符
`r'\w'` 匹配字母和数字
`r'\W'` 匹配非字母和数字
r'^010-\d{8}' 以 010- 开头并且后面跟了8个数字的东西
r'ab*' * 匹配0到多次
r'ab+’ + 匹配 1到多次
r'ab?' ? 匹配0或者1
r'ab{2,4}' 匹配b出现2-4次
r'ab\d{1,2}' 匹配ab后面跟了1-2个随机数字
'<(\w*)>.*</\1>' 匹配 <h1>haha</h1> 使用search()
r'a.b' . 匹配任意字符一次
.* 贪婪匹配
23.1.2 re.match().group()(邮箱,手机号)
从头开始搜,开头没有就没有,相当于 search ^xxxx
r'[a-zA-Z0-9]{4,20}@(163|126|qq|sohu|gmail)\.com$'
s = r'[a-zA-Z0-9]{4,20}@(126|163|sohu|qq|gmail)\.com$'
str = "480181612@qq.com"
print(re.match(s,str).group())
23.1.3 re.search().group()
search 搜索整个字符串
s = r'<(\w*)>.*</\1>'#.* 贪婪匹配,
# . 匹配除换行符(\n、\r)之外的任何单个字符,相等于 [^\n\r]# * 匹配0到多次
# \w 匹配字母,数字,下划线
str1 = "wadfawsdfaw<h1>haha</h1>wafaefeafw"
print(re.search(s,str1).group())
![[Pasted image 20260319093840.png]]
23.2 替换
23.2.1 sub()
s = r'\d+'
str1 = "阅读数:7777"
#print(re.search(s, str1).group(2))
#sub 替换
print(re.sub(s,"100",str1)) #替换
23.3 编译
#正则表达式的编译
obj = re.compile('\d{2}')
print(obj.search("abcd123hahaha").group())
print(obj.search("a6725123442523hah124").group())
23.4 迭代
#正则表达式+迭代器
ret = re.finditer('\d{3}','fvaef15648123565')
print(ret)
#print(next(ret).group())
#print(next(ret).group())
print([i.group() for i in ret])
23.5 爬虫
爬取标签+内容
s = r'<(\w+)>.*</\1>'
ret = re.finditer(s,str1)
print(next(ret).group())
爬取内容
<p><code class = "bjh-p"> 是 Python 正则表达式处理中非常强大且高效的工具,特别是当你需要处理大量文本或者需要获取详细匹配信息(如位置索引)时,它是首选。</code></p>
爬取标签内的内容
a = r'<code class = ".*?">(.*?)</code>'
print(re.findall(a, str1))
s = r'<a .*?>(.*?)</a>'
print(re.findall(s,str1))
爬取链接内的内容
str1 = '<div><a href="https://www.baidu.com" title="to baidu">去百度看</a> <a href="https://www.qq.com" title="to tengxun">去腾讯看</a></div>'
s = r'<a.*?href="(.*?)".*?>.*?</a>'
#(.*?) 加括号表示 “捕获这部分内容”,re.findall 会只返回捕获组里的内容,这就是为什么结果只显示链接,而不是整个 <a> 标签。
print(re.findall(s,str1))
二十四、异常处理
![[Pasted image 20260319170325.png]]
def main():
s1 = "index"
try:
#int(s1)
#dic = {"name":"xiaoming"}
#dic["age"]
#C
print("pay 100")
raise ValueError("请充值") #创造一个异常,主动出发
print("pay 200")
except ValueError as e:
print('valueerror',e)
except KeyError as e:
print('keyerror',e)
except IndexError as e:
print('indexerror',e)
except Exception as e:
print("未知异常")
finally:
print("不管怎么样,都要执行")
二十五、面向对象编程
25.1 类
# 定义一个类
class Human: #开辟了一个内存空间,只属于Huamn这个类
mind = "思想" #类变量
#自动创建的函数,初始化函数
def __init__(self,name,sex,age,money): #括号内是外部输入进来的变量
self.name = name #self.xxx 是函数里面的变量
self.sex = sex
self.age = age
self.money = money
#类函数
def work(self): #self:自己,在类里面定义的函数,会自动定义self,证明函数是类函数
print(self.name + '会工作')
def tools(self):
print(self.name + "会使用工具")
def main():
obj = Human('小明','boy','18',"99") #实例化一个对象
print(obj.name)
print(obj.sex)
print(obj.age)
print("======================")
print("赚钱之前是" + str(obj.money))
obj.money = 777
print("赚钱之后" + str(obj.money))
print("======================")
print(obj)
obj.work() #谁会工作
obj.tools() #谁会使用工具
25.2 类空间
25.2.1 类属性的添加
class A:
def __init__(self,name):
self.name = name
def func(self,sex):
self.sex = sex
def func1(self):
A.bbb = self
def main():
obj = A("xiaoming")
obj.age = 18 #外部添加
obj.func("boy")
print(obj.age)
print(obj.sex)
A.aaa = 'test'#外部添加
A.func1('123')
print(obj.__dict__)
print(A.__dict__)
25.2.2 类的依赖关系
#类的依赖
class Elephant:
def __init__(self,name):
self.name = name
def open(self,obj1):
#打开门
print(self.name,"要开门了")
obj1.open_door()
def close(self,obj1):
#关上门
print(self.name,"要关门了")
obj1.close_door()
pass
class Refrigerator:
def open_door(self):
print("门打开了")
def close_door(self):
print("门关上了")
def main():
el1 = Elephant("大象1号")
haier = Refrigerator()
el1.open(haier)
"""
el1是Elephant的一个实例化,haier是Refrigerator的一个实例化
Elephant.open存在形参obj1 是一个对象,el1.open传入了一个实参haier 是一个对象
这样就形成了依赖,可以让el1.open自由调用haier里的方法,也就是obj1.open_door()
""" el1.close(haier)
pass
25.2.3 类的关联关系
#类的关联
class Boy:
def __init__(self,name,girlFriend = None):
self.name = name
self.girlFriend = girlFriend
def have_a_dinner(self):
if self.girlFriend:
print("%s 和 %s 一起吃完饭"%(self.name,self.girlFriend.name))
else:
print("自己吃饭")
class Girl:
def __init__(self,name):
self.name = name
def main():
b = Boy("青山")
b.have_a_dinner()
xue = Girl("小雪")
b.girlFriend = xue
b.have_a_dinner()
b = Boy("青山",xue)
b.have_a_dinner()
class school:
def __init__(self,name,address):
self.name=name
self.address=address
self.teacher_list = []
def append_teacher(self,teacher):
self.teacher_list.append(teacher)
class teacher:
def __init__(self,name,school):
self.name=name
self.school=school
def main():
s1 = school("北京校区","北京")
s2 = school("南京校区","南京")
t1 = teacher("T1",s1)
t2 = teacher("T2",s2)
t3 = teacher("T3",s1)
s1.append_teacher(t1.name)
s2.append_teacher(t2.name)
s2.append_teacher(t3.name)
print(s1.teacher_list)
print(s2.teacher_list)
print(s2.__dict__)
25.2.4 类的组合
将一个类的对象,封装到另一个类的属性中
#类的组合
class GameRole:
def __init__(self,name,ad,hp):
self.name = name
self.ad = ad
self.hp = hp
def attack(self,p1):
p1.hp = p1.hp - self.ad
print(" %s 攻击了 %s , %s 掉了 %s 血,还剩 %s 血"%(self.name,p1.name,p1.name,self.ad,p1.hp))
#类的组合 将Weapon整个类塞入equip_weapon
#捡起武器
def equip_weapon(self,Weapon):
self.Weapon = Weapon
class Weapon:
def __init__(self,name,ad):
self.name = name
self.ad = ad
def weapon_attack(self,p1,p2):
p2.hp = p2.hp - self.ad - p1.ad
print("%s 使用了 %s , 攻击了 %s , %s 还剩 %s 血"%(p1.name,self.name,p2.name,p2.name,p2.hp))
def main():
man = GameRole("人物1",10,100)
dog = GameRole("狼狗",5,50)
dog.attack(man)
man.attack(dog)
m4a1 = Weapon("m4a1",30)
man.equip_weapon(m4a1)
man.Weapon.weapon_attack(man,dog)
print(man.Weapon.name,man.Weapon.ad)
25.3 类的继承
class Animal:
type_name = "动物类"
def __init__(self,name,sex,age):
self.name = name
self.sex = sex
self.age = age
def eat(self,x):
print("吃",x)
class Person(Animal):
pass
class Dog(Animal):
pass
class Cat(Animal):
pass
def main():
"""
print(Person.type_name) Person.eat("meat") """ p1 = Person("青山","boy",18)
print(p1.__dict__)
print(Person.type_name)
Person.type_name = "人类"
print(Person.type_name)
p1.eat('meat')
class Ren:
name = 'name1'
age = 20
sex = 'None'
__bag = 'weapon' # 加 __ 是私有变量,只能类内访问
@classmethod #装饰器,加上去之后,Ren.run()可以直接使用,不用初始化
def run(self,x):
print("running",x)
print("i have :",self.__bag)
#构造函数,当类被初始化的时候,构造函数运行
def __init__(self,name,sex,age):
print("这个人被制造出来了")
self.name=name
self.sex=sex
self.age = age
# 析构函数,当类消亡的时候,析构函数运行
def __del__(self):
print("我死了",flush=True)
#内部类
class Bad:
name = "bad person"
def badman(self):
print("kill you")
def __init__(self,name):
self.name= name
print("坏人出现了",self.name)
def __del__(self):
print("坏人消失了",flush=True)
class childRen(Ren):
def __init__(self):
print("孩子出生了")
def __del__(self):
print("孩子死了",flush=True)
def pao(self,x):
super().run(x) #继承父类的方法
def main():
Ren.run("我没有被创建")
ren1 = Ren("青山","bot",18)
ren1.run("hi")
#print(ren1.__bag)
print("=========================")
ren2 = childRen()
ren2.pao("555")
print("=========================")
ren3 = Ren.Bad("皇帝")
ren3.badman()
pass
25.4 类的约束
#类的约束
class Payment:
#我负责制定标准,谁继承我,必须拥有这些方法
def pay(self,money):
raise Exception('你没有实现我的pay方法')
class QQpay(Payment):
def pay(self,money):
print("使用QQ钱包付费",money)
class ALipay(Payment):
def fuqian(self,money): #这里没按照约束条件写,所以会报错
print("使用支付宝",money)
class WeChat(Payment):
def pay(self,money):
print("使用微信支付",money)
def pay(obj,money):
obj.pay(money)
def main():
a = ALipay()
b = WeChat()
pay(a,100)
pay(b,200)
25.5 静态方法
独立的单纯的函数
import time
#静态方法
class TimeTest:
def __init__(self,hour,minute,second):
self.hour = hour
self.minute = minute
self.second = second
@staticmethod #静态方法,直接使用
def showTime():
#print(self.hour)
#hour minute second return time.strftime("%H:%M:%S")
def main():
#静态方法的使用,直接一条
print(TimeTest.showTime())
25.6 property方法
执行一段功能,然后返回值
class People:
def __init__(self, name,weight,height):
self.name = name
self.weight = weight
self.height = height
@property
def bmi(self):
return self.weight / (self.height * self.height)
def main():
p1 = People("青山",75,1.85)
print(p1.bmi) #加了property属性之后,不需要使用 () 调用了
25.7 类方法
类内使用,而且无须实例化
#类方法
class Student:
__num = 0
def __init__(self, name,age):
self.name = name
self.age = age
Student.addNum()
@classmethod #类方法,可以直接调用
def addNum(self):
self.__num += 1
@classmethod
def getNum(self):
return self.__num
def main():
st1 = Student("s1",20)
st2 = Student("s2",21)
st3 = Student("s3",19)
print(Student.getNum())
class Goods:
def __init__(self):
#原价
self.original_price = 100
#折扣
self.discount = 0.8
@property
def price(self):
#实际价格
new_price = self.original_price * self.discount
return new_price
#以下setter和deleter都是配合property使用
@price.setter #如果obj.price = 200有接收参数的,就用setter去接受,此时默认的original_price就被修改了
def price(self, value):
self.original_price = value
@price.deleter #把original_price恢复
def price(self):
del self.original_price
def main():
obj = Goods()
#print(obj.original_price)
print(obj.price)
obj.price = 200
print(obj.price)
del obj.price
obj.price = 300
print(obj.price)
25.8 对象反射
class Foo:
f = "haha"
def __init__(self,name,age):
self.name = name
self.age = age
def say_hi(self):
print("hi")
def main():
obj = Foo("xiaoming",18)
#检查obj里是否有say_hi这个方法
print(hasattr(obj,"say_hi"))
#获取方法内存地址
n = getattr(obj,"say_hi","这个方法不存在")
print(n)
#删除属性
print(obj.name)
#delattr(obj.name)
#print(obj.name) 此时是会报错的,因为name已经被删除了
#设置属性
setattr(obj,"job","cooker")
print(obj.job)
25.9 魔法方法 len和call
len和call
class B:
def __len__(self):
return 666
def __call__(self,*atgs,**kwargs):
print("calling")
def main():
b = B()
#len()是测试一个长度,就会出发__len__方法
print(len(b))
#直接再对象后面加括号,就会触发__call__方法
b()
二十六、进程
from mutiprocessing import Process
26.1 概念
process
进程就是正在运行的程序的实例
进程具有一定独立功能的程序,关于某个数据进行运行活动
进程是一个实体
文本区域,数据区域,堆栈
特性:动态性 并发性 独立性 异步性
进程是一个资源分配的总和,线程是拿资源去执行
多进程多任务:多个资源,每个资源至少一个人做事
多线程多任务:一个资源,多个人做事
26.2 进程调度
进程调度:
FCFS 先来先服务 利于长作业
SJF/SPF 短作业优点调度 利于短作业
RR(round robin)时间片轮转
就绪状态 → 运行状态 → 阻塞状态 → 就绪状态
运行状态 → 就绪状态
![[Pasted image 20260321200628.png]]
print("程序开始执行") #运行状态
name = input(">>>>>") #阻塞状态
print(name) #运行状态
time.sleep(1) #阻塞状态 → 就绪状态
print("程序结束运行") #运行状态 → 结束状态
26.3 多进程
import multiprocessing
import os
import time
def test1(a):
print("test1 start",a)
print("test1 的进程id",os.getpid()) #查看当前进程的id
print("test1 的父进程id",os.getppid()) #查看当前进程的父id
time.sleep(5)
def test2(a):
print("test2 start",a)
print("test2 的进程id",os.getpid()) #查看当前进程的id
print("test2 的父进程id",os.getppid()) #查看当前进程的父id
time.sleep(5)
def main():
print("main函数的进程id是",os.getpid())
#创建进程
t1 = multiprocessing.Process(target = test1,args=("haha",))
t2 = multiprocessing.Process(target = test2,args=("nihao",))
#target = 执行的函数 , agrs = 执行函数的参数
#test1后面不需要接 () #args=("haha",) , 即使后面没东西,也要加 ,
#启动进程 同时启动
t1.start()
t2.start()
print("haha")
[[问题]]
![[Pasted image 20260323011954.png]]
26.3 模块
join:阻塞当前进程,直到调用join的方法的进程执行完毕,再继续执行当前进程
import time
from multiprocessing import Process
import os
def test1():
print("test1 start")
#print(os.getppid())
time.sleep(5)
print("test1 end")
def test2():
print("test2 start")
#print(os.getppid())
time.sleep(2)
print("test2 end")
def main():
print("main start")
#print(os.getpid())
t1 = Process(target=test1)
t2 = Process(target=test2)
t1.start()
t2.start()
t2.join() #阻塞
t1.join() #阻塞
print("main end")
26.4 守护进程
一定要在start之前开启,设置True就是守护进程开启
在父进程代码结束之后,守护进程立马停止运行
import time
from multiprocessing import Process
def foo():
print("foo start")
time.sleep(5)
print("foo stop")
def bar():
print("bar start")
time.sleep(5)
print("bar stop")
def main():
print("main start")
t1 = Process(target=foo)
t2 = Process(target=bar)
t1.daemon = True #开启守护进程
t2.daemon = True #开启守护进程
#一定要在start之前开启,设置True就是守护进程开启
#在父进程代码结束之后,守护进程立马停止运行
t1.start()
t2.start()
time.sleep(0.1)
print("main stop")
26.5 队列
26.5.1 FIFO
import queue
q = queue.Queue() #先进先出
import queue
q = queue.LifoQueue() #先进后出
import queue
q = queue.PriorityQueue() #优先级队列,越小越优先
q.put(20,'1')
q.put(10,'2')
q.put(40,'3')
q.put(30,'4')
#输出 2143
from mutiprocessing import Queue
from multiprocessing import Queue
def main():
q = Queue(3) #定义一个叫q的队列,队列容量:3
q.put("x1")
q.put("x2")
q.put("x3")
#q.put("x4") #如果队列满了,程序就会停在这里,等待数据被人取走,再将数据放入队列
try:
q.put_nowait("x4") #可以使用put_nowait,如果队列满了就不会阻塞,但是会报错
except:
print("队列满了,不能放")
print(q.full()) #判断一下队列是否满了
#print(q.get())
#print(q.get()) #print(q.get()) for i in range(3): # 同put方法一样,如果队列已经空了,就会继续出现阻塞
num = q.get()
print(num)
try:
print(q.get_nowait())
except:
print("队列已经空了")
print(q.empty())
26.6 进程间传递数据
生产者消费者模型
import time,os,random
from multiprocessing import Process,Queue
import os
def customer(q):
while True:
res = q.get() #从队列取出包子
if res is None:break
time.sleep(random.randint(1,3))
print("%s 吃 %s"%(os.getpid(),res))
def producer(q):
for i in range(10):
time.sleep(random.randint(1,3))
res = "包子 %s 号" % i
q.put(res) #把包子加入队列中
print("%s 生成了 %s"%(os.getpid(),res))
q.put(None) #发出结束讯号
def main():
q = Queue()
p1 = Process(target=producer, args=(q,))
p2 = Process(target=customer, args=(q,))
p1.start()
p2.start()
print("main")
结束信号None,不一定要由生产者进程发送,可以主进程等生产者完成后,由主进程发送
import time,os,random
from multiprocessing import Process,Queue
import os
def customer(q):
while True:
res = q.get() #从队列取出包子
if res is None:break
time.sleep(random.randint(1,3))
print("%s 吃 %s"%(os.getpid(),res))
def producer(q):
for i in range(10):
time.sleep(random.randint(1,3))
res = "包子 %s 号" % i
q.put(res) #把包子加入队列中
print("%s 生成了 %s"%(os.getpid(),res))
def main():
q = Queue()
p1 = Process(target=producer, args=(q,))
p2 = Process(target=customer, args=(q,))
p1.start() #生产者
p2.start() #消费者
p1.join()
q.put(None) #发出结束讯号
print("main")
import time,os,random
from multiprocessing import Process,Queue
import os
def customer(q):
while True:
res = q.get() #从队列取出包子
if res is None:break
time.sleep(random.randint(1,3))
print("%s 吃 %s"%(os.getpid(),res))
def producer(name,q):
for i in range(10):
time.sleep(random.randint(1,3))
res = "%s 的 %s 号" %(name,i)
q.put(res) #把包子加入队列中
print("%s 生成了 %s"%(os.getpid(),res))
def main():
q = Queue()
#多个厨师
p1 = Process(target=producer,args=("包子",q,))
p2 = Process(target=producer,args=("骨头",q,))
p3 = Process(target=producer,args=("牛肉",q,))
#多个消费者
c1 = Process(target=customer,args=(q,))
c2 = Process(target=customer,args=(q,))
#循序无所谓
p1.start()
p2.start()
p3.start()
c1.start()
c2.start()
#必须保证生产者都处理完毕,才能发出结束信号
p1.join()
p2.join()
p3.join()
#有几个消费者发出几个结束信号
q.put(None)
q.put(None)
q.put(None)
26.7 共享进程队列
import time,os,random
from multiprocessing import Process,JoinableQueue
import os
#共享进程队列
#JoinableQueue 创建一个可连接的共享队列
#允许项目的使用者通知生产者,项目已经被成功处理了
def customer(q):
while True:
res = q.get()
if res is None:break
time.sleep(random.randint(1,3))
print("%s 使用 %s"%(os.getpid(),res))
q.task_done() #向q.join发送一次信号
#证明数据已经被取走了
def producer(name,q):
for i in range(10):
time.sleep(random.randint(1,3))
res = "%s 的 %s 号"%(name,i)
q.put(res)
print("%s 生产了 %s"%(os.getpid(),res))
def main():
q = JoinableQueue()
#生产者们
p1 = Process(target=producer, args=("包子",q,))
p2 = Process(target=producer, args=("牛肉",q,))
p3 = Process(target=producer, args=("酒",q,))
#消费者们
c1 = Process(target=customer, args=(q,))
c2 = Process(target=customer, args=(q,))
c1.daemon = True
c2.daemon = True
#开始
p_1 = [p1,p2,p3,c1,c2]
for p in p_1:
p.start()
#等待厨师完成
p1.join()
p2.join()
p3.join()
# 关键:等待队列中所有数据被消费者处理完
q.join() #生产完毕,使用这个方法进行阻塞。
#目的是:直到队列中所有东西被处理
print("main")
主进程等 p1,p2,p3 c1,c2
p1,p2,p3结束了,证明c1,c2全都收完了p1,p2,p3的数据 q.task_done()
如果没接收完p1,p2,p3,会等他们搞定
搞定完成之后,c1,c2就没有价值了,p1,p2,p3的join也结束了,所以主进程继续执行,
主进程结束之后,顺便使用daemon把c1,c2给关掉
26.8 进程锁
进程之间数据相对独立,一般不实现数据通信,而是通过数据库来实现
如果硬是要实现,一般是进程锁(只能作为临时的解决方案)
from multiprocessing import Manager,Lock
def work(d,lock):
with lock:
d['count'] -= 1
def main():
lock = Lock() #进程锁
with Manager() as m:
dic = m.dict({'count':100})
p_l = []
for i in range(98):
p = Process(target=work,args=(dic,lock,))
p_l.append(p)
p.start()
for p in p_l:
p.join()
print(dic)
26.9 进程池
限制任务去开启进程做事情
池子 – 固定数量的进程
有事情了,从池子里拿一个进程出来做事情,做完事情,不关闭进程!
放回池子里继续等待下一个任务
如果池子里的进程数量不够,任务就需要等待,等什么时候有空闲的进程就继续执行(是被允许的)
from multiprocessing import Pool,Process
import time
#单进程:0.2668149471282959
#多进程:2.0607948303222656
def func(n):
for i in range(10): #把1-100每个数字打印10次
print(n+1)
def main():
start = time.time() #记录开始时间
#单进程
pool = Pool(5) #池子里五个进程
pool.map(func,range(100)) #定义100个任务
"""
#多进程
p_l = []
for i in range(100):
p = Process(target=func, args=(i,))
p_l.append(p)
p.start()
for p in p_l:
p.join()
"""
t2 = (time.time()-start)
print(t2)
pass
26.9.1 同步调用
from multiprocessing import Pool,Process
import os,time
#同步调用
def work(n):
print("%s run"%(os.getpid()))
time.sleep(3)
return n**2 #n*n
def main():
p = Pool(3) #进程池从无到有,创建3个进程
res_l = []
for i in range(10):
res = p.apply(work,args=(i,)) #同步调用,直到拿到结果为止,不管任务是否存在阻塞,同步调用都会原地等着
res_l.append(res)
print(res_l)
26.9.2 异步调用
#异步调用
def work(n):
print("%s run"%(os.getpid()))
time.sleep(3)
return n**2 #n*n
def main():
p = Pool(3) #进程池从无到有,创建3个进程
res_l = []
l = []
for i in range(10):
res = p.apply_async(work,args=(i,)) #异步调用,进程不会同时开启,也不会同时结束,也不会互相等待
res_l.append(res)
p.close() #关门,不再接受新的进程
p.join() #异步提交任务,主进程需要使用join,等待进程池里任务都处理完后,可以用get取搜集结果
#主进程等所有进程结束 #如果不用join,主进程结束,进程池还没来得及执行,就跟着结束
print(res_l)
for r in res_l:
a = r.get() #需要使用get获取apply_async的结果,因为apply没有get方法,
# 因为apply同步执行,立即获取结果,无需get
l.append(a) #l无返回值,不能写成 l = l.append(a) print(l)
二十七、网络编程基础
同一台电脑,可以使用配置文件
不同电脑可以使用平台
软件:
– 应用类
qq 微信 百度云 优酷
– web类
百度 知乎
webview技术 只能浏览唯一网址
1.架构 从用户层面划分
c/s(Client/Server)
- Client 客户端:你下载的 APP、软件
- Server 服务器:远端的电脑,提供数据
b/s(Browser/Server)
- Browser 浏览器:Chrome、Edge、Safari
- Server 服务器:网页所在的电脑
27.1 协议 = 标准
27.1 OSI七层模型 理论模型
OSI七层模型
理论模型
** 物 数 网 传 会 表 应**
物理层 数据链路层 网络层 传输层 会话层 表示层 应用层
7 应用层 Application
给软件用的协议
- HTTP、HTTPS、FTP、DNS、SMTP
- QQ、浏览器、微信用的就是这一层
6 表示层 Presentation
数据翻译、加密、压缩
- 把文字→编码,图片→格式
- SSL/TLS 加密也在这层
5 会话层 Session
建立、管理、断开对话
- 保证连接不断、不乱序
4 传输层 Transport
负责端到端传输
- TCP(可靠、慢)
- UDP(快、不可靠)
- 端口号在这里
3 网络层 Network
负责寻址、找路
- IP 协议
- 路由器工作在这层
2 数据链路层 Data Link
负责相邻设备传输
- MAC 地址
- 交换机工作在这层
1 物理层 Physical
硬件传输
- 网线、光纤、无线电波
- 只传 0 和 1
![[Pasted image 20260324235511.png]]
27.2 TCP/IP协议栈
TCP/IP协议栈
真实互联网
应用层
传输层
网络层
网络接口层
4 应用层
(对应 OSI 上三层:应用层 + 表示层 + 会话层)
- 负责软件之间的通信
- 常见协议:
- HTTP / HTTPS(网页)
- DNS(域名解析)
- FTP(文件传输)
- SMTP / POP3(邮件)
- QQ、微信自定义协议也在这层
3 传输层
- 负责端到端传输,用端口号区分程序
- 两个核心协议:
- TCP:可靠、面向连接、不丢包(打电话)
- UDP:不可靠、快、无连接(发短信)
2 网络层
- 负责寻址、路由,找到目标主机
- 核心协议:
- IP 协议(IPv4 / IPv6)
- ICMP(ping 命令用这个)
1 网络接口层(数据链路层 + 物理层)
- 负责跟硬件打交道:网卡、网线、交换机
- 基于 MAC 地址传输
用户进程代表一个程序:比如 QQ 微信,淘宝
用户进程需要使用Socket抽象层来跟TCP/UDP通信
不论是什么协议,TCP/UPD/ICMP/IGMP,最后都需要跟IP去联系起来
因为只有IP才和硬件有联系 硬件就是网卡
Socket 套接字
分为两种 基于文件 和 基于网络
基于文件
af_unix
unix一切都是文件
基于网络
af_inet(ipv4)
af_inet6(ipv6)
![[Pasted image 20260324235613.png]]
27.1.3 TCP/UDP
TCP 可靠的传输,面向连接(打电话),可靠传输但是传输效率低,全双工通信,有拥塞机制(有先来后到)
web浏览器,文件传输,邮件
单工通信 收音机
半双工通信 对讲机
全双工通信 电话
UDP 不可靠的传输,无连接的服务,传输效率高(发送延时小),一对一,一对多,多对一,多对多
面向报文(数据包),尽最大努力服务,无拥塞机制
域名系统(dns),视频,语言
![[Pasted image 20260325002459.png]]
一般同时启用Socket,不过都是服务端先启动
服务器端:
bind()绑定ip地址
listen()监听哪些端口
accpet()开始允许用户连接,此时会阻塞直到用户连接
客户端
connect()建立连接
服务器端
read()读取,证明有人连接,读取客户端write()发来的数据,并且通过write()回应数据给客户端的read()
客户端
write()给服务器发送数据,并用read()接受服务器传来的数据
客户端write() → 服务器read() → 服务器write() →客户端read() 循环
![[Pasted image 20260325003023.png]]
客户端
close()结束
服务端
read()收到来自客户端的结束请求,最后用close()结束
27.2 通信实现
27.2.1 基础C/S架构
服务端:
# /usr/bin/python
# coding:UTF-8
#服务端程序
import socket
def main():
s = socket.socket() #导入socket模块
host = socket.gethostname() #获取自己的IP地址
port = 12345 #一会使用12345端口通信
s.bind((host,port)) #绑定ip地址和端口
s.listen(5) #等待用户连接,最多5个人
c,addr = s.accept() #建立和客户端的连接 c = 对方的套接字, addr=对方的ip地址和对方的端口以元祖的形式存在
print("对方连接地址是",addr)
c.send("welcome".encode("utf-8")) #通过客户的套接字发送welcome给对方,utf-8编码
print(c.recv(1024).decode("utf-8")) #c相当于管道,接受客户信息
c.close()
pass
客户端:
# /usr/bin/python
# coding:UTF-8
#客户端程序
import socket
def main():
s = socket.socket()
host = '192.168.31.7' #你要连接谁的ip地址
port = 12345
s.connect((host,port)) #连接服务端
msg = input("您要发送的信息:")
s.send(msg.encode("utf-8"))#发送信息
print(s.recv(1024).decode("utf-8")) #接收信息
s.close()
pass
27.2.2 循环网络通信
服务端
#服务端程序
import socket
def main():
#socket.AF_INET 使用ipv4通信,socket.SOCK_STREAM使用tcp通信
tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#绑定端口
tcp_server_socket.bind(('',8080))
#允许多数人连接我
tcp_server_socket.listen(128)
#循环为多个客户服务多次
while True:
#等待用户连接,保存用户的socket和ip地址
new_client_socket,client_address = tcp_server_socket.accept()
print("the %s connecting"%(str(client_address)))
#给客户发送信息
new_client_socket.send("welcome".encode("utf-8"))
#循环为一个客户服务
while True:
# 接收来自客户的数据
recv_data = new_client_socket.recv(1024)
if recv_data:
print(recv_data.decode("utf-8"))
else:
print("断开连接")
break
#关闭套接字
new_client_socket.close()
tcp_server_socket.close()
客户端:
#客户端程序
import socket
def main():
tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_ip = '192.168.31.7'
server_port = 8080
server_add = (server_ip,server_port)
#连接服务器
tcp_socket.connect(server_add)
#接受第一次发来的数据
first_data = tcp_socket.recv(1024)
print(first_data.decode("utf-8"))
while True:
#持续发送数据
send_data = input("send---->")
tcp_socket.send(send_data.encode("utf-8"))
tcp_socket.close()
二十八、线程(Thread)
进程
只能在同一时间干一件事情
执行过程中,如果阻塞,比如等待输入,这个适合整个进程是挂起
地址空间相对独立
线程
同一个进程里的各个线程之间共享数据
调度和切换速度快
注意:进程是资源分配的基本单位
线程是CPU调度的最小单位,每个进程中至少一个线程
==================
全局解释锁 GIL
同一时刻只有一个线程在运行
28.1 线程的使用
#多线程
from threading import Thread
import time
def sayHi(name):
time.sleep(2)
print("%s say hello"%(name))
def main():
t = Thread(target=sayHi,args=("xiaoming",))
t.start()
print("主线程")
线程是进程的一部分
#多线程
from threading import Thread
from multiprocessing import Process
import time,os
def work():
print("hello",os.getpid())
def main():
T1 = Thread(target=work)
T2 = Thread(target=work)
T1.start()
T2.start()
print("主线程pid:",os.getpid())
P1 = Process(target=work)
P2 = Process(target=work)
P1.start()
P2.start()
28.2内存数据共享实验
#内存数据共享实验
from threading import Thread
from multiprocessing import Process
import time,os
def work_for_Process():
global n
n = 0
def work_for_Thread():
global n
n = 0
def main():
n = 100
p = Process(target=work_for_Process)
p.start()
p.join()
print(n) #0
a = 9
t = Thread(target=work_for_Thread)
t.start()
t.join()
print(a) #9
28.3 多线程其他函数
from threading import Thread
import threading,time
def work():
time.sleep(3)
print(threading.current_thread().getName()) #获取线程的名字
def main():
T1 = threading.Thread(target = work)
T2 = threading.Thread(target = work)
T1.start()
T2.start()
# 查看主线程的名字
print(threading.current_thread().getName()) # MainThread
# 查看有谁在运行
print(threading.enumerate())
# 查看一共有多个线程在运行
print(threading.active_count()) # 3
from threading import Thread
import threading,time
def work():
time.sleep(3)
print(threading.current_thread().getName()) #获取线程的名字
def main():
T1 = threading.Thread(target = work)
T1.start()
print(T1.is_alive()) #判断线程是否存活
T1.join()
print("main")
print(T1.is_alive()) #判断线程是否存活
28.4 守护线程
#守护线程
from threading import Thread
import threading,time
def foo():
print("123")
time.sleep(1)
print("end123")
def bar():
print("456")
time.sleep(3)
print("end456")
def main():
t1 = Thread(target=foo)
t2 = Thread(target=bar)
t1.daemon = True
t2.daemon = True
t1.start()
t2.start()
print("main")
#123
#456main
pass
if __name__ == '__main__':
main()
28.5 多线程同步锁
lock.acquire() #加锁
... #对数据操作的时候,前后加解锁
lock.release() #解锁
会让程序从并发执行变成串行,牺牲效率保证数据安全(一般用数据库来完成)
from threading import Thread,Lock,current_thread
import time,os
n = 100
def work(lock):
lock.acquire()
global n
temp = n
time.sleep(0.1)
n = temp -1
lock.release()
print("%s is running %s"%(current_thread().getName(),n))
def main():
l = []
lock = Lock()
start_time = time.time()
for i in range(100):
T = Thread(target=work,args=(lock,))
l.append(T)
T.start()
for p in l:
p.join()
print(n)
stop_time = time.time()
print("主%s %s"%(stop_time - start_time,n))
if __name__ == '__main__':
main()
二十九、协程
生成器(yield)= 协程的底层实现
进程是资源分配的最小单位
线程是CPU调度的最小单位
单线程实现并发
协程 – 用户态的轻量级线程
单线程如果遇到 IO , 就会从应用程序级别进行控制和切换
优点:
切换开销更小(属于程序级别的切换,操作系统感知不到)
单线程实现并发效果
一个进程放多个线程,不行
那就一个线程放多个协程
缺点:
本质还是在单线程下运行,无法利用电脑CPU多核
一个程序开启多个进程,每个进程开启多个线程,每个线程开启多个协程
协程都是基于单线程的
以但协程出现阻塞,就会阻塞整个线程
29.1 协程原理
def create_num(all_num):
print("---1---")
a,b = 0,1
current_num = 0
while current_num < all_num:
print("---2---")
ret = yield a
print("---ret---",ret)
print("---3---")
a,b = b,a+b #第二次 a=1,b=2 current_num += 1
def main():
obj = create_num(10)
ret = next(obj)
print(ret) #a
ret = obj.send("haha") # next() 和 send() 都是「唤醒开关」
#生成器暂停后,只有两个办法能让它继续跑:
#next(生成器) → 唤醒,但不传值
#生成器.send(值) → 唤醒,同时传一个值
print(ret) #1
if __name__ == '__main__':
main()
29.2 协程多任务
import time
from scipy.constants import year
def task_1():
while True:
print("---1---")
time.sleep(1)
yield
def task_2():
while True:
print("---2---")
time.sleep(2)
yield
def main():
t1 = task_1()
t2 = task_2()
while True:
next(t1)
next(t2)
29.3 greenlet
import time
from greenlet import greenlet
#切换时,只有第一次需要传参,之后无需传参,数据未丢失
def main():
def eat(name):
print("%s eat 1" % name) #小明 eat 1
g2.switch("小红") #第二步、参数名是小红,函数是play,切换到 print("%s play 1" % name)
print("%s eat 2" % name)
g2.switch() #第四步、默认参数名是小红,函数是play,切换到 print("%s play 2" % name) ,结束
def play(name):
print("%s play 1" % name)
g1.switch() #第三步、默认参数小明,函数是eat,切换到 print("%s eat 2" % name) print("%s play 2" % name)
#切换
g1 = greenlet(eat) #执行eat函数并且执行切换
g2 = greenlet(play)
g1.switch("小明") #第一步、将参数 小明 带入eat
if __name__ == '__main__':
main()
import time
from greenlet import greenlet
#切换时,只有第一次需要传参,之后无需传参,数据未丢失
def f1():
res = 1
for i in range(1000):
res += 1
time.sleep(1)
print(res)
g2.switch()
def f2():
res = 1
for i in range(2000):
res += 2
time.sleep(1)
print(res)
g1.switch()
g1 = greenlet(f1)
g2 = greenlet(f2)
def main():
start = time.time()
g2.switch() #从 def f2() 开局
stop = time.time()
print(stop-start)
if __name__ == '__main__':
main()
29.4 gevent
因为greenlet没有解决效率问题,只是解决了切换问题
gevent可以理解为协程池,greenlet的封装
import time
#必须放在最前面!在 import time、socket、requests 之前!
from gevent import monkey;monkey.patch_all() #必须打上补丁,如果不用gevent.sleep(1)
import gevent
import threading
def eat(name):
# Dummy-1 伪线程
print(threading.current_thread().getName())
print("%s eat 1"%name)
#gevent.sleep(2)
time.sleep(1)
print("%s eat 2"%name)
def play(name):
print(threading.current_thread().getName())
print("%s play 1"%name)
#gevent.sleep(2) #模拟拥塞
time.sleep(2)
print("%s play 2"%name)
def main():
#spawn 创建协程对象 spawn(函数名,参数)
g1 = gevent.spawn(eat,"小明")
g2 = gevent.spawn(play,"小红")
#g1.join()
#g2.join() gevent.joinall([g1,g2])
print("主")
if __name__ == '__main__':
main()
29.5 协程同步和异步
import time
#必须放在最前面!在 import time、socket、requests 之前!
from gevent import monkey;monkey.patch_all() #必须打上补丁,如果不用gevent.sleep(1)
import gevent
import threading
def task(pid):
time.sleep(0.5)
print("task %s done" % pid)
def main():
"""
#同步 串行,一步一步走
for i in range(10): task(i) """ #异步 并发,同时进行
g_l = [gevent.spawn(task,i) for i in range(10)]
gevent.joinall(g_l)
print("main done")
if __name__ == '__main__':
main()
257

被折叠的 条评论
为什么被折叠?



