Python

导论

一共会分为4个板块

入门

  • 数据类型
  • 语法
  • 容器
  • 函数
  • 文件交互
  • 异常和包

类和对象

  • 类的基础
  • 魔术方法
  • 继承复写
  • 类型注解
  • 多态
  • 数据库

pyspark大规模分布式计算

  • 构建对象
  • 数据输入
  • 数据计算
  • 数据输出

进阶

  • 闭包
  • 装饰器
  • 设计模式
  • 多线程编程
  • 网络编程
  • 正则表达式
  • 递归

Python入门

字面量

字面量就是值,包括整数,浮点数,字符串等

注释

单行:#

多行:””” “””

变量

不同于C语言,在Python中,变量不需要定义类型,直接定义变量名并赋值即可

注意:在Python中,语句之间不用使用分号隔开

1
2
money = 10
print ("余额:",money)

数据类型

虽然在Python中定义变量不用定义数据类型,但是会根据输入的值自动定义数据类型,是一种弱数据类型的编程语言

我们可以通过**type()**函数获取变量的数据类型并返回

1
2
3
money = 1
A = type(money)
print(A)

数据类型转化

在Python中,可以通过对应函数将数据类型进行转化,如:

1
2
3
4
str(111) #将111转化成字符串
A = 3.14
int(A) #将浮点数转化成整数,会丢失精度
float(A) #将整数转化成浮点数

标识符

同其它编程语言一样,Python在给变量,方法,函数等命名的时候

不可以使用

  • 1.数字开头
  • 2.关键字

不建议使用中文

运算符

运算符 作用 效果
// 取整除 9//4 = 2
% 取余 9%2 =1
** 指数 2**3 =8
+= 累加 C=0; C += 2 C=2
//= 累整除 C=10; C//=2 C=5
%= 累取余 C=10; C%=2 C=0
**= 累指数 C=10; C//=2 C=100
累~ 就是将值运算之后再赋给本身

字符串

定义方法:

  1. 使用单引号
  2. 使用双引号
  3. 使用三对双引号(必须有变量,不然就是注释)
1
2
3
'111'
"111"
A = """ 111 """

在字符串内使用单引号或者双引号:

  1. 嵌套法
  2. 使用转义字符 \
1
2
"  '1111'   "     #会输出'1111'
" \'1111 " #会输出'1111

字符串拼接

通过+号可以将字符串拼接到一起

1
print ("sdsa"+"sdada")

字符串格式化

通过占位符格式将字符串和其它数据类型拼接到一起

%表示占位

  • s表示将数据变成字符串代替s
  • d表示将数据变成整数代替d
  • f表示将数据变成浮点数代替f

数字精度控制:

m.n f/d:m为整数长度,n为小数长度,整数少于m时m生效

1
2
3
4
5
print ("名字是:%s先生 ,电话是 %s"%("张三",123456788))
print ("名字是:%s先生 ,电话是 %d"%("张三",123456788))
print ("名字是:%s先生 ,电话是 %3.2f"%("张三",88.1))
#输出 名字是:张三先生 ,电话是123456788
#输出 名字是:张三先生 ,电话是088.10

快速格式化

通过f{变量/表达式}格式

1
2
A=1,B=2
print (f"名字是:{A}先生 ,电话是{12*13}")

输入语句

input(“提前输出的内容”)

1
2
A = input("你是?");
print (f"你是:{A}先生")

布尔类型

在Python中,布尔类型不用定义,直接将布尔值赋值给变量即可

1
A = "123" == "123"

if语句

在Python中,通过缩进来判断语句的级别,而不使用;

语法: if 判断语句 :真时执行语句 else :假时执行语句

1
2
3
4
5
6
7
8
A = 30
if A > 18 :
print("123")
elif A>10:
print("1234")
else:
print("321")
print ("000")

while循环

while 条件 : 循环语句

break可跳出循环

1
2
3
while 1:
print ("名字是:%s先生 ,电话是 %3.2d"%("张三",123456788))
break

for循环

和C语言不同,Python的for循环是将序列的每一项数据提取进行处理,序列包括:字符串,列表,元组deng

for 临时变量 in 序列 : 执行语句

注意:用于Python靠缩进来进行语句分级,所以x在for循环外依然可以被使用,但是并不规范

1
2
3
4
5
6
7
8
A = "123456"
for x in A:
print (x)
#结果会循环6次,每次获取A的一位进行处理 输出
1
2
3
....

range语句

用来生成序列,搭配for循环使用

  • range(10):生成0-9
  • range(5,11):生成5-10
  • range(1,10,2):生成1,3,5,7,9
1
2
3
for X in range(10):
print (x)
#循环10次

练习:乘法表

1
2
3
4
5
for a in range(1,10):
for b in range(1,10):
if b<=a:
print (f"{b}*{a}={a*b}\t",end='')
print()

print()可以作为回车符使用

\t 表示空一格

end=’ ‘表示不用换行

break和continue

break表示结束

continue表示跳过

1
2
3
4
5
6
7
for i in range(10):
if i==5:
continue
print (i)
if i==8:
break
#输出1234678

函数

定义:def 函数名 (形参):函数体 返回值

1
2
3
4
5
6
7
8
def AAA (a):
if a>18:
return 1
else:
return None

if not AAA(13):
print("未成年")

注意:

  • 如果不返回值的话,会返回None,表示空,并表示什么都不返回
  • None = flase
  • not None = true

拓展:

返回多个值 可以 return 1,2,并使用两个变量接收

1
2
3
def AAA ():
return 1,"SSS"
x,y =AAA()

传参方式:

在Python中,除了常用的位置传参外还可以通过关键字,缺省参数(默认),不定长参数(*位置和**关键字)

注意:位置不定长参数传入为元组,关键字不定长参数以键值对传入为字典,这两种方式都没有规定传入参数的数量

1
2
3
4
5
6
7
8
9
10
11
12
def AAA (a,b,c=3):#位置,关键字,缺省参数
return a,b,c,
x,y,z=AAA(1,b=2)
print(x,y,z)

def BBB (*A):#位置不定长参数
return A
print(BBB(1,2,3,4,5))

def CCC (**A):#关键字不定长参数
return A
print(CCC(A=1,B=2,C=3))

函数逻辑作为参数

在一些时候,函数里面的数据是固定的,但是需要不同的处理逻辑,因此我们可以把函数作为参数传入另一个参数,实际上是传入了函数的逻辑算法

1
2
3
4
5
6
7
def A(a,b):
return a+b
def C(a,b):
return a*b
def B (X):
print(X(1,2))
B(A)

匿名函数:

在一些只需要使用一次的函数,我们可以定义为匿名函数,匿名函数默认返回值,并且只可以使用一次

lambda 参数 :函数体(只一行)

1
2
3
4
5
6
7
def A(a,b):
return a+b
def C(a,b):
return a*b
def B (X):
print(X(1,2))
B(lambda a,b:a*b*b+a*a-b)

global转化为全局变量

在python中,无论是否传入形参,函数里面的变量都为形参,不影响实参,也就是局部变量不影响全局变量,

global相当于指针函数,在函数内的形参变量前面添加global,则可以影响到实参(全局变量)

1
2
3
4
5
6
A=100
def B ():
global A
A=200
B()
print (A)

数据容器

序列-列表(类似数组)

定义

列表名 =[元素,元素…] [“assda”,112233,True,]

列表可以储存不同的数据类型,可以嵌套

通过下标可以索引到对应的数据,下标从0开始

反向索引:从后面开始,开始下标为-1,然后-2

注意:字符串表示也是一种列表可以使用下标索引对应字符

1
2
3
4
5
A = ["assda",112233,True]
B = ["sadsa",A, ["ASD",236] ]
print (B)
print (B[1][1]) #输出112233
print (B[-2][-2]) #输出112233

列表的方法

查询元素的下标:列表.index(元素) 没有则报错

修改:列表[下标] = 新值

插入:列表[下标, 值] 下标原来的数据自动往后

追加元素:列表.append(元素),在最后面追加元素

追加数据容器(批量):列表.expend(容器),在最后面追加列表等数据容器的值,不是嵌套

删除

  1. del 列表[下标] 直接删除,会自动补位
  2. 列表.pop(下标) 返回元素并删除
  3. 列表.remove(元素) 删除第一个匹配的元素

清空:列表.clear()

统计

  1. 列表.count(元素) 统计指定元素的数量
  2. len(列表) 统计全部元素的数量

列表案例

已知列表[23,24,25,26]

要求追加27和[28,29],取出第一个和最后一个元素

遍历该列表

1
2
3
4
5
6
7
8
9
10
11
12
A = [23,24,25,26]
B = [28,29]
A.append(27)
A.extend(B)
print (A[0],A[6])
C =range(len(A))
for i in C:
print(A[i])
i=0
while i<len(A):
print(A[i])
i +=1

序列-元组

在python中,元组就是只读的列表,一旦定义就不可修改

定义:

元组名 = (元素,元素,元素…)

空元组: 元组名= () 或者 元组名= tuple()

元组可以嵌套,如:A =((1,2,3),(4,5,6))

通过下标可以索引到对应的数据,下标从0开始

注意:如果元组中只有一个元素,需要在元素后面加逗号,不然就是字符串

元组的方法

查询元素的下标:元组.index(元素) 没有则报错

统计

  1. 元组.count(元素) 统计指定元素的数量
  2. len(元组) 统计全部元素的数量

特殊情况:如果元组里面嵌套了列表,则可以修改列表里面的内容

1
2
3
A =((1,2,3),[4,5,6])
A[1][2]=7
print(A[1][2])

序列-字符串

字符串也是数据容器,同样适用数据容器的规则,同时并不可修改,空格也算字符

方法:

查询元素的起始下标:字符串名.index(“元素”) 没有则报错

替换元素:字符串名.replace(”要替换的元素”,”新的元素”)替换之后需要新的变量接收,本身并不会改变

按照指定的元素把字符串进行切割成列表:字符串名.split(“指定元素”) 切割之后需要新的变量接收,本身并不会改变

去除前后的指定元素:字符串名.strip(“指定元素”) 或者如果没有参数,字符串名.strip() 去除前后的空格和换行符

统计

  1. 字符串名.count(元素) 统计指定元素的数量
  2. len(字符串名) 统计全部元素的数量
1
2
3
4
5
6
7
8
9
10
11
12
13
A ="I IS ABC"
B =A.index("IS")
print(B)
C =A.replace("ABC","大帅哥")
print(C)
D =C.split(" ")
print(D)
E=C.strip("I")
print(E)
E =C.count("I")
print(E)
E =len(C)
print(E)

序列的切片

在python中,可以对序列进行切片截取

语法:序列名[起始下标:结束下标:步长] [起始下标:结束下标]

步长:截取的距离,如果是1(可不写),则一个一个取,如果是2,则间隔1个再取

起始下标为空表示从头开始,结束下标为空表示到结尾再结束,步长为空表示没有间隔

注意:步长为负表示反向取,起始下标,结束下标也要为负

1
2
3
4
5
6
7
8
9
A ="I IS ABC"
B=A[0::3]
print(B)
A =[[1,2],3,4,5,6]
B=A[::3]
print(B)
A =[[1,2],3,4,5,6]
B=A[::-1]
print(B)

切片案例

字符串987654321,获取456

1
2
3
A ="987654321"
B =A[::-1][3:6]
print (B)

集合

和序列不同,集合是无序的(不支持下标索引访问),不可重复的

定义:集合名={元素,元素,…} 空集合 = set()

修改方法:

添加:集合名.add(元素)

移除:集合名.remove(元素)

随机取出一个元素,并移除:集合名.pop()

清空:集合名.clear()

取差集(不同):C=集合A.difference(集合B) 取A中和B的不同并返回,不影响A和B

消除交集(相同):集合A.difference_update(B) 删除A中和B相同的元素,不影响B

合并:C=集合A.unior(B) 合并A和B并返回,不影响A和B

统计元素个数:len(集合)

遍历:for i in 集合:prant(i)

集合案例—信息去重

列表[1,2,3,4,5,6,1,2,3,4,5,6,7]

1
2
3
4
5
6
A =[1,2,3,4,5,6,1,2,3,4,5,6,7]
B =set()
for i in A:
B.add(i)
for i in B:
print(i)

字典

字典是键值对的集合,可以通过键去检索值(不可下标索引)

定义:

字典名 = {key1:值,key2:值….}

空字典:

  • 字典名={}
  • 字典名=dict()

注意:key不可重复,如果重复,则值取最后一个key的值

使用:

1
2
3
A= {"ab":66,"bc":77,"bc":88}
B=A["bc"]
print(B)

关于嵌套:key不可以为字典,值可以为任何类型

方法:

新增/修改:字典名[key]=值 如果没有这个key,则新增

删除:字典名.pop(key)

清空:字典名.clear()

获取全部key:字典名.keys(),遍历时,也可以直接in字典名,也是遍历所有key

统计元素(键值对)数量:len(字典名)

嵌套字典案例—学生的成绩

查看张三的语文成绩

张三的语文成绩修改为99

删除张三的英语,添加日语成绩92

查看所有人的成绩

语文 数学 英语
张三 100 88 77
李四 75 75 75
王五 0 36 100
1
2
3
4
5
6
7
8
A= {"张三":{"语文":100,"数学":88,"英语":77},"李四":{"语文":75,"数学":75,"英语":75},"王五":{"语文":0,"数学":36,"英语":100}}
print (A["张三"]["语文"])
A["张三"]["语文"]=99
A["张三"].pop("英语")
A["张三"]["日语"]=92
print (A["张三"])
for i in A:
print(f"{i}:{A[i]}")

容器的通用方法

len(容器):获取元素数量

max(容器):获取元素最大值 通过对比每一位字符的ASCII码表比较,字符串比字符,字典比key

min(容器):获取元素最小值

文件交互

计算机通过编码将信息转化为二进制,我们日常使用编码格式为 UTF-8

打开文件

通过f = open(“文件地址名称”,“打开方式”,encoding=”编码格式”)创建一个对象

打开方式 意思 效果
r 只读(默认) 打开文件之后只可读,指针在最前
w 只写 文件存在则删除重新写入,不存在则创造文件写入
a 追加 文件存在则在最后追加写入,不存在则创造文件写入

方法

只读取指针后,封装成字符串:f.read() 如果只读取指针后对应字节f.read(10)

读取指针后全部行,并封装到列表中:f.readlines()

读取指针后一行,并封装到列表中:f.readlines()

遍历每一行:for i in f:print(i)

关闭文件:f.close() 包含写入硬盘f.flush()

文件自动关闭语法:with open(“文件地址名称”,“打开方式”,encoding=”编码格式”) as f:操作

写入内存:f.write(“?????”)

写入硬盘:f.flush()

文件睡眠:f.sleep(50) 文件睡眠50秒,期间文件会在运行无法外部操作

文件交互案例

1
2
3
4
张三 100 花费
李四 123 收入
王五 456 测试
张三 122 花费

读取文件,将测试删除,然后备份

1
2
3
4
5
6
7
8
9
10
11
f = open("123.txt","r",encoding="UTF-8")
x = open("123备份.txt","a",encoding="UTF-8")
for i in f:
a = i.strip()
b =a.count("测试")
if b==0:
x.write(i)
else:
continue
f.close()
x.close()

异常处理

异常捕获

在Python中,如果程序出现bug,那么程序就会停止运行,如果我们可以捕获bug,并给出处理方案,那么程序就不会停止运行

通过 try:可能出现bug的语句 except:补救方案可以实现对应补救

1
2
3
4
5
try:
f = open("1234.txt","r",encoding="UTF-8")
except:
print("没有这个文件,改为写入创造文件")
f = open("1234.txt", "w", encoding="UTF-8")

捕获指定异常:我们可以只捕获指定的异常,并提供解决方案

try:可能出现bug的语句 except (指定异常1,2) as i:补救方案 i记录了异常信息

1
2
3
4
try:
print(a)
except NameError as i:#NameError是变量未定义的异常
print(i)

捕获全部异常:我们可以捕获全部的异常,并提供解决方案

  • try:可能出现bug的语句 except:补救方案
  • try:可能出现bug的语句 except Exception as i:补救方案 是一种顶级异常捕获

没有捕获到异常:可以使用else继续执行代码

无论有没有异常都要执行:可以所用finally代码

1
2
3
4
5
6
7
8
try:
print("11")
except Exception as i:
print(i)
else:
print("22")
finally:
f.close()

异常的传递性

如果异常发生在函数调用的时候,那么异常可以在调用的时候被捕获

1
2
3
4
5
6
7
8
def a():
n=1/0
def b ():
try:
a()
except Exception as i:
print(i)
b()

模块

模块是工具包,库函数,需要导入才可以使用

方法:

  • import 模块名

    导入全部功能,需要以 模块名.功能名方式使用

  • from 模块名 import 指定模块里的类函数变量等

    只能使用指定的功能,需要以 模块名.功能的方式使用

  • from 模块名 import *

    导入全部功能。可以直接以功能名使用

  • import 模块名 as 别名

    导入全部功能,需要以 别名.功能的方式使用

  • from 模块名 import 功能名 as 别名

    只能使用指定的功能,需要以 别名的方式使用

自定义模块

新建py文件,在py里面编写内容,再导入即可,模块名就是文件名

注意:在自定义模块的时候,用于在导入的时候会执行一次模块的文件,如果模块里面有调用函数,则会被执行,我们可以使用main然后快捷输入

1
2
if __name__ == '__main__':
调用的函数

文件在执行的时候会判断是否以主函数执行,如果是的话,就执行,如果是被导入的话,就是在别的文件被调用,自定义模块的__name__就不是'__main__',就不会被执行

以*号导入全部的时候,也可以只导入我们准备的内容,可以通过在模块中添加

1
__all__ = [ '函数1']

那么,我们使用*导入的时候就只能使用函数1

在Python中,模块就相当于mod,包就是模组,包用于集中管理模组,避免麻烦和遗漏

创建包:

创建一个Python package文件夹(文件自动包含init.py文件管理模块)

将模块都放入文件夹

导入模块

  • import 包.模块
  • import 包.模块.功能
  • from 包 import 模块
  • from 包.模块 import 功能

通过from导入的,使用的时候不用通过.

安装第三方包

通过终端

数据可视化案例

JSON 模块

JSON是一种轻量的数据交互格式,可以将数据按照指定的方式封装保存(本质上是一个带有特殊格式的字符串)

功能:可以实现在各个语言中的数据交互,每个语言的数据容器不一样,如C++中的数组,Python中的字典(作为翻译官使用)

JSON的储存格式为:字典 或者 列表里面包含字典

1
2
{"name":"张三","phone":12345678910}
["name":"张三","phone":12345678910},"name":"李四","phone":12345678910}]

使用:

在Python中导入json模块

1
import json

将Python数据转化为json,通过json.dumps(数据)

1
2
A ={"name":"张三","phone":12345678910}
A = json.dumps(A)

将json数据转化为Python,通过json.loads(数据)

1
A = json.loads(A)

懒人工具-json在线解析

pyecharts模块

pyecharts模块是百度提供的数据图形可视化模块

官方文档地址

画廊展示

安装

1
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyecharts

制作成图表:

去除3个json前面和后面的错误

将2020年美国印度日本的疫情确诊数据制作成图表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import json
import pyecharts.options as opts
from pyecharts.charts import Line

YD = open("印度.txt","r",encoding="UTF-8")
US = open("美国.txt","r",encoding="UTF-8")
RB = open("日本.txt","r",encoding="UTF-8")

#读取文件为字符串,删除不规范的内容
YD_SJ = YD.read().strip("jsonp_1629350745930_63180(",)
US_SJ = US.read().strip("jsonp_1629344292311_69436(")
RB_SJ = RB.read().strip("jsonp_1629350871167_29498(")
#从-2开始读取到最前,删除最后的2个不规范分号
YD_SJ =YD_SJ[:-2]
US_SJ =US_SJ[:-2]
RB_SJ =RB_SJ[:-2]

#json转成python
YD_SJ = json.loads(YD_SJ)
US_SJ = json.loads(US_SJ)
RB_SJ = json.loads(RB_SJ)

#获取国家
US_name = US_SJ["data"][0]["name"]
YD_name = YD_SJ["data"][0]["name"]
RB_name = RB_SJ["data"][0]["name"]

#获取时间
US_trend_time = US_SJ["data"][0]["trend"]["updateDate"][:314]
YD_trend_time = YD_SJ["data"][0]["trend"]["updateDate"][:314]
RB_trend_time = RB_SJ["data"][0]["trend"]["updateDate"][:314]
#获取确诊
US_trend_list_qz = US_SJ["data"][0]["trend"]["list"][0]["data"][:314]
YD_trend_list_qz = YD_SJ["data"][0]["trend"]["list"][0]["data"][:314]
RB_trend_list_qz = RB_SJ["data"][0]["trend"]["list"][0]["data"][:314]

#获取治愈
US_trend_list_zy = US_SJ["data"][0]["trend"]["list"][1]["data"][0]
#获取死亡
US_trend_list_sw = US_SJ["data"][0]["trend"]["list"][2]["data"][0]
#获取新增
US_trend_list_xz = US_SJ["data"][0]["trend"]["list"][3]["data"][0]

#制图
x_data = US_trend_time
y_data = US_trend_list_zy
(
Line()
.add_xaxis(xaxis_data=x_data)
.add_yaxis(
series_name=US_name,
stack="确诊",
y_axis=US_trend_list_qz,
label_opts=opts.LabelOpts(is_show=False),
)
.add_yaxis(
series_name=YD_name,
stack="确诊",
y_axis=YD_trend_list_qz,
label_opts=opts.LabelOpts(is_show=False),
)
.add_yaxis(
series_name=RB_name,
stack="确诊",
y_axis=RB_trend_list_qz,
label_opts=opts.LabelOpts(is_show=False),
)

.set_global_opts(
title_opts=opts.TitleOpts(title="疫情确诊数据"),
tooltip_opts=opts.TooltipOpts(trigger="axis"),
yaxis_opts=opts.AxisOpts(
type_="value",
axistick_opts=opts.AxisTickOpts(is_show=True),
splitline_opts=opts.SplitLineOpts(is_show=True),
),
xaxis_opts=opts.AxisOpts(type_="category", boundary_gap=False),
)
.render("stacked_line_chart.html")
)

制作成地图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import json
from pyecharts.charts import Map
from pyecharts.options import *

f = open("疫情.txt","r",encoding="UTF-8")
A =f.read()
A =json.loads(A)
C =[]
S =A["areaTree"][0]["children"]
for i in S:
name = i["name"]
B = i["total"]["confirm"]
C.append((f"{name}省",B))
print(C)
map =Map()
map.add("中国确诊人数",C,"china")
map.set_global_opts(
title_opts= TitleOpts(title="全国疫情地图"),
visualmap_opts=VisualMapOpts(
is_show=True , #是否显示
is_piecewise=True, #是否分段
pieces=[ #自定义分段
{"min":1,"max":99,"lable":"1-99人","close":"#FFE7BA" },
{"min":100,"max":1000,"lable":"100-1000人","close":"#FA8072" },
{"min":1001,"max":10000,"lable":"1001-10000人","close":"#FF6347" },
{"min":10001,"max":50000,"lable":"10001-50000人","close":"#FF3030" },
{"min":50000,"lable":"50000以上","close":"#8B1A1A" }

]
)
)
map.render()

类和对象

在Python中,创建一个类和C一样,但是方法的定义不一样

self 相当于C中的this,表示类对象自己,用于在方法中访问自身的变量

1
2
3
4
5
class 类名 :
变量1
方法:
def 方法名 (self ,形参1,....):
print(self.变量1)

实例对象以及使用:

1
2
对象名 = 类名()
对象名.方法()

构造方法(函数):

1
2
def __init__(self,形参1.....):
函数体

魔术方法

在Python中,在类中内置了很多方法,和构造函数一样,魔术方法的特征就是_ ?_

字符串方法 str

如果我们实例了一个对象,并且直接输出对象的时候,就会输出对象的地址

通过字符串方法,我们可以将对象转化成字符串输出

1
2
3
4
5
6
7
8
9
10
11
12
class student:
def __init__(self,name,age):
self.name =name
self.age =age
student = student("张三",12)
print(student)
#<__main__.student object at 0x00000231C7726900>

def __str__(self):
return f"我是{self.name}{self.age}岁"
print(student)
#我是张三,12岁

对象比较方法 lt 和 le

两个对象之间正常情况下是不能比较的,但是通过魔术方法可以,类似于C++中的运算符重载

如果没有定义魔术方法,则不能进行比较, ==则会比较地址,一定会输出false

1
2
3
4
5
6
7
8
9
10
11
12
13
student1 = student("张三",12)
student1 = student("李四",16)

def __lt__ (self,other):#只能判断大小
return self.age <other.age
def __le__ (self,other):#能判断大小等于
return self.age <=other.age
def __eq__ (self,other):#能判断等于
return self.age ==other.age

print(student1<student2)
print(student1<=student2)
print(student1==student2)

私有变量和方法

定义私有属性可以防止对象使用,只能类内部使用

在变量或者方法名前面加__就可以

1
2
3
4
5
6
7
8
9
10
11
class student :
name = "asd"
__id =123
def A (self):
print(f"我的名字是{self.name}")
def __B(self):
print(f"我的身份证是{self.__id}")
def C(self):
self.__B()
A= student()
A.C()

继承

通过继承,可以将父类的一些属性继承给子类

  1. 如果继承多个父类,父类中相同的变量方法名,则左边优先(父类名1)
  2. 如果对父类中的属性不满意,可以进行复写
  3. 如果复写之后还想要使用父类的属性,则可以通过调用实现:
    • 父类名.成员变量
    • 父类名.成员方法(self)
    • super().成员变量
    • super().成员方法()
1
2
3
4
5
6
7
8
class 类名 父类名1:
A =1

class 类名(父类名1,父类名2): #左边优先
A =2 #复写
父类名1.A


类型注解

在我们调用函数或者传参的时候,如果是Python自带的则会提示我们要输入什么类型,如果是我们自己定义的,则不会,因此我们可以进行注解

方法1:直接加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
变量:
A : int = 10
B : float =3.14
C : bool =True
D : str = "asdf"

类对象:
class student :
pass
AA : student = student()

容器:
a : list = [1,2,3]
b : tuple = (1,2,3)
c : set ={1,2,3}
d : dict ={"asd":666}
e : str = "123dsa"

详细:
a : list[int] = [1,2,3]
b : tuple[int,str,bool] = (1,"a",True)
c : set[int] ={1,2,3}
d : dict[str,int] ={"asd":666}

方法2:在后面加上#type:类型,也可以具体

1
2
3
4
5
6
a = [1,2,3]	#type:list
b = (1,2,3) #type:tuple
c = {1,2,3} #type:set
d = {"asd":666}#type:dict[...]
e = "123dsa"#type:str
.......

在函数中,形参和返回值的注解:

1
2
3
4
5
形参:
def aaa(a : int ,b :class, c:list)

返回值类型:-> 类型 :
def aaa(a) -> int :

混合类型注解:

如果传入的类型不止一种,可以使用Union:

1
2
3
4
5
6
from typing import Union

a : list[Union[str,int]]= [1,2,"asd",3] #这样表示list里面可以是str,也可以是int ,二选一
d : dict[str,Union[str,int]] ={"asd":666,"阿是":"ASDD"}

def aaa(a : Union[str,int])->Union[str,int]:

多态和抽象类

多态就是一个方法的多个状态,如果子类对父类的方法进行了复写,那么如果一个函数的参数是父类,那么也是可以传入子类作为形参,导致函数执行子类的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
class A:
def speak(self):
pass #抽象类,不进行具体行为,只规定行为
class B(A):
def speak(self):
print("azxcv")
class S(A):
def speak(self):
print("123456")
def C (AAA:A):
A.speak()
C(B) #azxcv
C(S) #123456

类案例

将2个月份的数据制作成图表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import json
from pyecharts import options as opts
from pyecharts.charts import Bar

class js :
ma_1 = []
time_1 = ["01"]
def hq(self):
pass

def hd2(self):
A = Bar()
A.add_xaxis(

self.time_1

)
A.add_yaxis("11", self.ma_1)
A.set_global_opts(
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=-15)),
title_opts=opts.TitleOpts(title="Bar-旋转X轴标签", subtitle="解决标签名字过长的问题"),
)
A.render("ba.html")

class js1(js):
def hq(self):
f = open("2011年1月销售数据.txt", "r", encoding="UTF-8")
m = 0
q = 0
for i in f:
t = i.split(",")[0][8::] # 获取时间
if self.time_1[q] == t:
b = i.split(",")[2]
b = int(b)
m = m + b
else:
self.time_1.append(t)
q += 1
self.ma_1.append(m)
m = int(i.split(",")[2])
self.ma_1.append(m)
print(self.time_1)
print(self.ma_1)

class js2(js):
def hq(self):
f = open("2011年2月销售数据JSON.txt", "r", encoding="UTF-8")
m = 0
q = 0
for i in f:
t = i.split(",")[0][18:20:] # 获取时间
if self.time_1[q] == t:
b = i.split(",")[2][9::]
b = int(b)
m = m + b
else:
self.time_1.append(t)
q += 1
self.ma_1.append(m)
m = int(i.split(",")[2][9::])
self.ma_1.append(m)
print(self.time_1)
print(self.ma_1)

def C (A:js):
A.hq()
A.hd2()

A =js2()
C(A)

数据库

可视化工具:DBeaver

创建表:create table 名称 (数据名称 数据类型)

1
2
sql
create table student (id int,name char(10),age int,sex char(5));
类型 指令 范围
整数 TINYINT -128到127
整数 SMALLINT -32768到32767
整数 MEDIUMINT -8388608到8388607
整数 INT -2147483648到2147483647
整数 BIGINT -9223372036854775808到9223372036854775807
小数 DECIMAL() 在存储时需要指定总位数和小数位数。示例:(10,2)
字符串 CHAR 定长字符串,存储0到255个字符
字符串 VARCHAR() 变长字符串,可以存储0到65535个字符,示例:(100)
字符串 TEXT 用于存储较长的文本数据,最大长度为65535个字符
日期 DATE 格式为YYYY-MM-DD。示例:“2022-05-15”
时间 TIME 格式为HH:MM:SS。示例:“12:30:45”
日期和时间 DATETIME 格式为YYYY-MM-DD HH:MM:SS。示例:“2022-05-15 12:30:45”
日期和时间 TIMESTAMP 自动记录最后修改的日期和时间。示例:“2022-05-15 12:30:45”
枚举 ENUM() 用于定义一组可能的值,只能选择其中的一个值。示例:ENUM(“Male”,“Female”),只能选择”Male”或”Female”
集合 SET() 定义一组可能的值,可以选择其中的多个值。示例:SET(“Red”,“Green”,“Blue”),可以选择”Red”、“Green”和”Blue”
布尔 bool 可以存储True或False

上述数据类型都支持一些属性,如指定默认值、是否允许为空、是否自增等。例:

  • 指定默认值:默认值属性用于在插入新行时为列指定一个默认值。示例:

    age INT DEFAULT 18,默认将年龄设置为18。

  • 是否允许为空:允许为空属性用于确定该列是否可以为空。示例:

    address VARCHAR(100) NULL,地址可以为空。

  • 是否自增:自增属性用于在每次插入新行时自动为列生成唯一的值。示例:

    id INT AUTO_INCREMENT PRIMARY KEY,id将自动递增,作为主键。

显示表结构:desc 表名

1
2
sql
desc student;

删除表:drop table 表名

1
2
sql
drop table student;

表结构修改:

数据表添加列:alter table 表名 add 列名 类型;

1
2
sql
alter table student add height int(10);

数据表删除列:alter table 表名 drop 列名;

1
2
sql
alter table student drop height;

数据列改名:alter table 表名 change column 原名 改名 类型

1
2
sql
alter table student change column height high int(3);

数据列修改数据类型:alter table 表名 modify column 列名 改后类型

1
2
sql
alter table student modify column high char(10);

修改表名:alter table 原名 rename to 改名

1
2
sql
alter table student rename to student_table;

插入数据项:insert into 表名(要添加的列名) value (对应的数据);(如果都添加可直接表名)

1
2
sql
insert into student(id,name,age,sex,high) value (001,"张三",10,"男",160);

删除数据项:delete from 表名 where 列名=?

1
2
sql
delete from student where high=140;

修改数据项:update 表名 set 修改的列名 =’1’ where 修改的对象 =’ ‘

1
2
sql
update 用户信息 set U_账号 ='1' where U_账号 ='15'

设置主键:

  1. 创建表时:

    1
    2
    sql
    primary key (列名)
  2. 现有的表:

    1
    2
    3
    sql
    ALTER TABLE 表名
    ADD PRIMARY KEY (列名);

自增主键:

  1. 创建表时:

    1
    2
    3
    sql
    CREATE TABLE 表名 (
    列名 类型 AUTO_INCREMENT PRIMARY KEY,);
  2. 现有的表:

    1
    2
    3
    sql
    ALTER TABLE 表名
    MODIFY 列名 类型 AUTO_INCREMENT PRIMARY KEY;

逻辑运算符(筛选)

筛选中间的值:
语法:select * from 表名 where 列名 between 最小值 and 最大值;

1
2
sql
select * from student where id between 2 and 5;

作用和使用><是一样的

1
2
sql
select * from student where id>2 and id<5;

筛选这一列为空的值:

语法:select * from 表名 where 列名 is null;

1
2
sql
select * from student where high is null;

筛选指定的值:
语法:select * from 表名 where 列名 in (值1,值2,…)

1
2
plaintext
select * from student where age in(9,12);

筛选包含有元素的值
通配符:

  • % 代表任意字符和数量
  • _ 一个下划线代替一个字符
    语法:select * from 表名 where 列名 like ‘通配符 特征 通配符’;
1
2
3
sql
select * from student where name like '张%'; =张死鬼, 张死,张鬼,张死鬼2
select * from student where name like '张_'; ==张死,张鬼

分组聚合

筛选之后进行求和最大最小值等

语法:select 列名,聚合函数 from 表名 [ where 条件 ] group by 列名(被分组的列)

1
2
3
4
5
6
7
select 年龄,sum(年龄) from 表名 group by 年龄
聚合函数:
sum(列) 求和
avg(列) 平均值
min(列) 最小
xam(列) 最大
count(列|*) 求数量

排序

对列进行排序

语法:正常查询的语法内容 order by 列 [函数]

1
2
3
4
select 年龄 from 表名 where 年龄>20 order by 年龄 asc;
函数:
asc 升序(从小到大)如果不写默认
desc 降序

查询条数

语法:正常查询的语法内容 limit n [,m]

1
2
select 年龄 from 表名 where 年龄>20 order by 年龄 asc limit 5    展示5
select 年龄 from 表名 where 年龄>20 order by 年龄 asc limit 5,10 从第五条开始展示10条(不包括5

Python操控数据库

安装第三方库

1
pip install pymysql

连接数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
from pymysql import Connection
#获取数据库连接的对象
CONN =Connection(
host= '主机名',
port=端口,
user='用户名',
password='密码'
autocommit=True#自动确认提交
)
#打印数据库信息
print(CONN.get_server_info())
#关闭数据库
CONN.close()

执行修改语句

1
2
3
4
5
6
7
8
9
10
11
12
#修改
#获取游标对象
cursor =CONN.cursor()
#选择数据库
CONN.select_db("数据库名")

#通过游标对象执行SQL语句
cursor.execute("sql语句")

#确认提交修改,如果设置了自动提交则不用
CONN.commit()

执行查询语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#查询
#获取游标对象
cursor =CONN.cursor()
#选择数据库
CONN.select_db("数据库名")

#通过游标对象执行SQL语句
cursor.execute("sql语句")

#获取查询结果(以元组进行保存)
results : tuple = cursor.fetchall()

#遍历查询结果
for i in results:
print(i)

spark

spark可以对海量数据进行大规模分布式计算

既可以在电脑计算,也可以在服务器集群进行分布式计算

安装myspark

1
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyspark

构建执行环境入口对象

SparkContex是执行的类,构建其对象来执行spark的所有命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#导入包
from pyspark import SparkConf,SparkContext

#创建sparkconf类对象,记录spark程序的运行模式和名字
conf = SparkConf().setMaster("local[*]").\ #"local[*]"表示在本机运行
setAppName("test_spark_app") #"test_spark_app"表示给pyspark程序起一个名称

#基于sparkconf类对象创建SparkContext类对象
sc = SparkContext(conf=conf)

#打印pyspark运行版本
print(sc.version)

#停止SparkContext对象的运行(停止pyspark程序)
sc.stop()

数据输入

RDD(弹性分布式数据集):pyspark支持多种数据容器输入,在输入完成之后,都会得到一个RDD类的对象

数据储存在RDD内,我们可以通过RDD的方法对数据进行计算,返回值依然是RDD,因此可以进行多次计算

读取容器

通过SparkContext类对象的paralleize方法传入数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
rdd = sc.parallelize(容器对象)

#输出RDD的内容
print(rdd.collect)

RDD1 = sc.parallelize([1,2,3,4])
RDD2 = sc.parallelize((1,2,3,4))
RDD3 = sc.parallelize("ASDDFF")
RDD4 = sc.parallelize({1,2,3,4})
RDD5 = sc.parallelize({"aa":1,"bb":2})
print(RDD1.collect())
print(RDD2.collect())
print(RDD3.collect())
print(RDD4.collect())
print(RDD5.collect())

[1, 2, 3, 4]
[1, 2, 3, 4]
['A', 'S', 'D', 'D', 'F', 'F']
[1, 2, 3, 4]
['aa', 'bb']

注意:

  • 字符串会被拆分成1个个字符储存到RDD
  • 字典只有key会被储存到RDD

读取文件转RDD对象

通过SparkContext类对象的textFile方法传入数据

1
RDD6 =sc.textFile(文件路径)

数据计算

在计算前,需要给spark提供Python解释器的地址

1
2
import os
os.environ["PYSPARK_PYTHON"]="D:\Python/python.exe"

map方法(无额外功能)

可以将RDD的每个数据交给指定的函数处理,并返回新的RDD

1
2
3
4
5
6
7
def AAA(A):
return A*10
RDD1 = sc.parallelize([1,2,3,4])
RDD2=RDD1.map(AAA)
RDD3=RDD2.map(lambda x:x+5)
print(RDD2.collect())#[10, 20, 30, 40]
print(RDD3.collect())#[15, 25, 35, 45]

flatMap方法(去嵌套)

有除去嵌套功能的Map方法

1
2
3
4
5
6
RDD1 = sc.parallelize(["1,2,3","4,5,6"])
RDD2=RDD1.flatMap(lambda x:x.split(","))
RDD3=RDD1.map(lambda x:x.split(","))

print(RDD2.collect())#['1', '2', '3', '4', '5', '6']
print(RDD3.collect())#[['1', '2', '3'], ['4', '5', '6']]

reduceByKey方法(分组聚合)

对KV类型(二元元组)的key进行分类,然后对V进行操作,然后返回V继续执行操作最后完成key1的操作返回(K,V),再完成key2…

1
2
3
4
RDD1 = sc.parallelize([("男",99),("男",88),("女",99),("女",69),("女",100)])
RDD2=RDD1.reduceByKey(lambda a,b:a+b)
print(RDD2.collect())
#[('男', 187), ('女', 268)]

注意:方法接收的函数只负责聚合,分组由方法自动完成

filter方法(筛选)

筛选数据,如果返回值是Ture,则保存

1
2
3
RDD1 = sc.parallelize([1,2,3,4,5,6])
RDD2=RDD1.filter(lambda a:a%2 == 0)
#[2, 4, 6]

distinct方法(去重)

无需传入函数

1
2
3
4
RDD1 = sc.parallelize([1,2,2,3,4,5,6,2,3,4,6,5,9])
RDD2=RDD1.distinct()
print(RDD2.collect())
#[1, 2, 3, 4, 5, 6, 9]

sortBy方法(排序)

语法:sortBy(函数,ascending=True/Flase,numPartitions=1)

函数的返回值是排序的关键,ascending=True(升序),Flase(降序),numPartitions=1表示一个分区(不用管)

1
2
3
4
RDD1 = sc.parallelize([(3,"a","一号"),(2,"b","二号"),(1,"c","三号")])
RDD2=RDD1.sortBy(lambda a:a[1],ascending=False,numPartitions=1)
print(RDD2.collect())
#[(3, 'a', '一号'), (2, 'b', '二号'), (1, 'c', '三号')]

数据输出

输出为Python容器

**collect()**方法可以将RDD转化为list(列表)

1
RDD2.collect()

reduce方法对RDD按照传入的逻辑进行聚合,返回值和传入的参数一致

1
2
3
4
RDD1 = sc.parallelize([1,2,3,4,5,6])
A=RDD1.reduce(lambda a,b:a+b)
print(A)
#21

take方法对RDD取前N个元素,组成list返回

1
2
3
4
RDD1 = sc.parallelize([1,2,3,4,5,6])
A=RDD1.take(3)
print(A)
#[1, 2, 3]

count方法对RDD进行计算有多少条数据,返回数字

1
2
3
4
RDD1 = sc.parallelize([1,2,3,4,5,6])
A=RDD1.count()
print(A)
#6

输出为文件

下载

HADOOP

  • 解压到任意文件夹

下载链接 提取码: iaee

  • 下载winutils.exe,并放入Hadoop解压文件夹的bin目录内
  • hadoop.dll,并放入:C:/Windows/System32 文件夹内

指向HADOOP路径

1
os.environ['HADOOP_HOME']="D:/C++笔记/hadoop-3.0.0"

将RDD分区设置为1

1
2
3
4
全局设置
conf.set("spark.default.parallelism", "1")
或者传入数据的时候在后面加1
RDD1 = sc.parallelize([1,2,3,4,5,6],1)

输出到文件夹saveAsTextFile(“路径”)

路径不可已存在

1
RDD1.saveAsTextFile("D:/C++笔记/python/123")

综合案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
00:00:00    2982199073774412   传智播客   8  3  http://www.itcast.cn
00:00:00 07594220010824798 黑马程序员 1 1 http://www.itcast.cn
00:00:00 5228056822071097 传智播客 14 5 http://www.itcast.cn
00:00:00 6140463203615646 博学谷 62 36 http://www.itcast.cn
00:00:00 8561366108033201 IDEA 3 2 http://www.itcast.cn
00:00:00 23908140386148713 传智专修学院 1 2 http://www.itcast.cn
23:00:00 1797943298449139 flume 8 5 http://www.itcast.cn
23:00:00 00717725924582846 itcast 1 2 http://www.itcast.cn
23:00:00 41416219018952116 bigdata 2 6 http://www.itcast.cn
23:00:00 9975666857142764 IDEA 2 2 http://www.itcast.cn
23:00:00 21603374619077448 酷丁鱼 1 6 http://www.itcast.cn
23:00:00 7423866288265172 bigdata 3 13 http://www.itcast.cn
23:00:00 0616877776407358 itcast 2 9 http://www.itcast.cn
.........

获取哪个小时搜索数量是最多的,前3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#导入包
from pyspark import SparkConf,SparkContext
import os
os.environ['PYSPARK_PYTHON']="D:/Python/python.exe"
os.environ['HADOOP_HOME']="D:/C++笔记/hadoop-3.0.0"
#创建sparkconf类对象,记录spark程序的运行模式和名字
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
conf.set("spark.default.parallelism", "1")

#基于sparkconf类对象创建SparkContext类对象
sc = SparkContext(conf=conf)


RDD1 = sc.textFile("search_log.txt")
RDD2 =RDD1.map(lambda a:a.split("\t")).\
map(lambda I:I[0][:2]).\
map(lambda a:(a,1)).\
reduceByKey(lambda a,b:a+b).\
sortBy(lambda a:a[1],ascending=False,numPartitions=1).\
take(3)
print(RDD2)
#停止SparkContext对象的运行(停止pyspark程序)
sc.stop()

将时间和用户id数据转化为json

1
2
RDD1 = sc.textFile("search_log.txt")
RDD1.map(lambda a:{"时间":a[0],"用户id":a[1]).saveAsTextFile("D:/C++笔记/python/123")

进阶

闭包

在程序中,如果设置了全局变量,那么全局变量很容易被别人修改

通过在外面嵌套一个函数,让全局变量作为外函数的参数参与内函数的使用则称为闭包

我们可以将外函数返回内函数赋给变量,以变量的形式使用内函数,那么外函数的参数则不容易被修改

1
2
3
4
5
6
def AAA(name):
def BBB(age):
print(f"{name}的年纪:{age}")
return BBB
f1 =AAA("张三")
f1(13)#张三的年纪:13

如果在闭包中,需要在内函数中修改外函数的参数:在内函数:nonlocal 参数名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def ATM(A=0):
def BBB(B,C:bool):
nonlocal A
if C:
A +=B
else:
A -=B
print(f"存款为:{A}")

return BBB
f1 =ATM()
f1(13,True)
f1(1000,True)
f1(560,False)

注意:如果使用闭包的话,那么内函数会持续引用外函数的值,会导致这部分的内存一直不被释放

装饰器

如果我们要为一个函数添加新的功能,但是不去破坏函数本身,那么我可以使用装饰器,装饰器本质上也是闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
def CCC(C):
def DDD():
print("欢迎使用ATM")
C()
print("拜拜")
return DDD

def ATM():
A =100
print(f"存款为:{A}")

WW =CCC(ATM)
WW()

方法2

在原来函数前面@闭包函数,本质上也是传入闭包函数,但是可以直接使用原来的函数名调用新的函数体

1
2
3
4
5
6
7
8
9
10
11
12
def CCC(C):
def DDD():
print("欢迎使用ATM")
C()
print("拜拜")
return DDD

@CCC
def ATM():
A =100
print(f"存款为:{A}")
ATM()

设计模式

单例模式

在很多时候,我们使用工具类的时候,往往是会不停的实例对象,这样会占用很多资源,这个时候我们可以使用单例模式,让类只有一个实例,所有的访问点都是访问这个实例对象,而不是创建新的对象

实现:

在创建类的时候,我们可以直接在类的文件中将类实例一个对象

1
2
3
4
5
ABC.py
class AAA:
pass

aaa =AAA()

在我们要使用这个类的时候,可以直接导入这个类的对象,用变量接收,那么这个变量就可以调用对象的一切功能

1
2
3
4
from ABC import aaa
s1 =aaa
s2 =aaa
s2.

工厂模式

如果我们需要大量创建对象的时候,我们可以使用工厂模式,创建一个工厂的类,在类里面统一管理实例对象

有统一的接口方便维护,当类的名称需要改变的时候,只需要修改工厂的接口即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class AAA :
pass

class student (AAA):
pass

class teachar(AAA):
pass

class gc ():
def asc(self,a):
if a =="s":
return student()
elif a =="t":
return teachar()

gc =gc()
s1 = gc.asc("s")
s2 = gc.asc("t")

多线程编程

在电脑中,程序的运行在系统中称之为进程,一个进程中有多个线程执行具体的任务

进程之间内容是相互隔离的,而线程之间内容是相互共享的

系统相当于一栋写字楼,进程相当于在写字楼的公司,每个公司之间是隔离开在不同的楼层的,线程相当于公司里面的员工,每个员工有具体的工作,员工在公司里面是共享信息和移动的

通过threading可以实现多线程编程

导入threading包

1
import threading

实例对象

thread_obj = threading.Thread([group [, target [, name [, args [, kwargs]]]]])

group:暂时无用,未来功能的预留参数
target:执行的目标任务名
args:以元组的方式给执行任务传参
kwargs:以字典方式给执行任务传参
name:线程名,一般不用设置

执行线程

thread_obj.start()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import threading
import time
from time import sleep

def sing (a):
while True :
print(a)
sleep(1)
def dance (a):
while True :
print(a)
sleep(1)
aaa =threading.Thread(target=sing,args =("我在唱歌",))
bbb =threading.Thread(target=dance,kwargs ={"a":"我在跳舞"})

aaa.start()
bbb.start()

网络编程

Socket是进程之间通讯的工具,进程之间需要进行网络通讯需要通过socket

两个进程之间通讯必须要有服务端和客户端

服务端

等待其他进程的连接,接收发来的信息,可以回复信息

1.导入包

1
import socket

2.创建Socket对象

1
socket_server =socket.socket()

3.绑定ip地址和端口

localhost代表本机

1
socket_server.bind(("localhost"8888))

4.监听端口连接的数量

1
2
3
socket server.listen(1)
# listen方法内接受一个整数传参数,表示接受的链接数量
# 等待客户端链接

5.监听端口的信息

1
2
3
4
5
6
7
conn,address=socket_server.accept()
# accept方法返回的是二元元组(链接对象,客户端地址信息)
#可以通过变量1,变量2=socket_server.accept()的形式,直接接受二元元组内的两个元素
#result : tuple=socket_server.accept()
#conn=result[0]# 客户端和服务端的链接对象
# address =result[1]# 客户端的地址信息
#accept()方法,是阻塞的方法,等待客户端的链接,如果没有链接,就卡在这一行不向下执行了

6.获取客户端发来的信息

1
print(f"接收到了客户端的链接,客户端的信息是:{address}")

7.处理客户端发来的信息

要使用客户端和服务端的本次链接对象,而非socket_server对象

1
2
3
4
data:str =conn.recv(1024).decode("UTF-8")
#recv接受的参数是缓冲区大小,一般给1024即可
#recy方法的返回值是一个字节数组也就是bytes对象,不是字符串,可以通过decode方法通过UTF-8编码,将字节数组转换为字符串对象
print(f"客户端发来的消息是:{data}")

8.发送回复消息

1
2
msg = input("请输入你要和客户端回复的消息:").encode("UTF-8") #encode可以将字符串编码为字节数组对象
conn.send(msg)

9.关闭链接

1
2
conn.close()
socket_server.close()

客户端

主动连接服务端,可以发送信息,可以接收信息

1.导入包及创建对象

1
2
import socket
socket_client = socket.socket()

2.连接到服务端

1
socket_client.connect(("localhost"8888))

3.发送消息

1
socket_client.send("你好呀".encode("UTF-8"))

4.接收返回消息

1
2
recv_data =socket client.recv(1024)#1024是缓冲区的大小,一般1024即可。同样recv方法是阻塞的
print(f"服务端回复的消息是:{recv_data.decode('UTF-8')}")

5.关闭链接

1
socket_client.close()

区别

服务端用于可以接收多个客户端的信息,所以需要创建不同的连接对象,通过连接对象和客户端进行通讯

客户端由于只和服务端进行通讯,所以只用创建一个本体对象即可

正则表达式(基础匹配)

正则表达式就是规则匹配表达式,利用正则表达式指定规则进行检索和修改字符串

例如:利用正则表达式检索电子邮箱是否符合规则

Python正则表达式,使用re模块,并基于re模块中三个基础方法来做正则匹配

分别是:match、search、findall 三个基础方法

match

语法:re.match(匹配规则,被匹配字符串)

从被匹配字符串开头进行匹配,匹配成功返回匹配对象(包含匹配的信息),匹配不成功返回空

1
2
3
4
5
6
7
8
9
10
import re
s ='python itheima python itheima python itheima'
result =re.match('python',s)
print(result)#<re.Match object;span=(0,6), match='python'>
print(result.span())#(0,6),匹配的字符串对应的下标
print(result.group())#python,匹配到的内容

s ='1python itheima python itheima python itheima'
result = re.match('python',s)
print(result)#None,如果开头不匹配,则不会继续匹配下去

语法:search(匹配规则,被匹配字符串)

搜索整个字符串,找出匹配的。从前向后,找到第一个后就停止,不会继续向后

1
2
3
4
5
6
7
8
9
10
11
import re
s ="1python666itheima666python666"
result = re.search("python",s)
print(result)#<re.Match object;span=(1,7),match='python'>
print(result.span())#(1,7)
print(result.group())# python

#整个字符串都找不到,返回None
s ="itheima666"
result = re.search('python',s)
print(result)#None

findall

语法:findall(匹配规则,被匹配字符串)

匹配整个字符串,找出全部匹配项

1
2
3
4
5
6
7
8
import re
s ="1python666itheima666python666"
result = re.findall('python',s)
print(result)#['python','python']

s ="1python666itheima666python666"
result =re.findall('itcast',s)
print(result)#[],如果找不到则返回空列表

正则表达式(元字符匹配)

单字符匹配

字符 功能
. 匹配任意1个字符(除了\n),**\ .**匹配点本身
[ ] 匹配[]中列举的字符
\d 匹配数字 0-9
\D 匹配非数字
\s 匹配空白,即空格,tab键
\S 匹配非空白
\w 匹配单词字符 a-z,A-Z,0-9,_
\W 匹配非单词字符
\n 匹配换行符
\t 匹配制表符
[^] 匹配不属于[]中列举的字符
\

案例

字符串的r标记,表示当前字符串是原始字符串,即内部的转义字符无效而是普通字符

找出全部数字

1
2
3
s="itheima1 @@python2!!666 ##itcast3"
A =re.findall(r'\d',s)
print(A)#['1', '2', '6', '6', '6', '3']

找出特殊字符

1
2
3
s="itheima1 @@python2!!666 ##itcast3"
A =re.findall(r'\W',s)
print(A)#[' ', '@', '@', '!', '!', ' ', '#', '#']

找出全部英文字母

1
2
3
s="itheima1 @@python2!!666 ##itcast3"
A =re.findall(r'[a-zA-Z]',s)
print(A)#['i', 't', 'h', 'e', 'i', 'm', 'a', 'p', 'y', 't', 'h', 'o', 'n', 'i', 't', 'c', 'a', 's', 't']

数字匹配

字符 功能
* 匹配前一个规则的字符出现0至无数次
+ 匹配前一个规则的字符出现1至无数次
匹配前一个规则的字符出现0次或1次
{m} 匹配前一个规则的字符出现m次
{m,} 匹配前一个规则的字符出现最少m次
{m,n} 匹配前一个规则的字符出现m到n次

边界匹配

字符 功能
^ 匹配字符串开头
$ 匹配字符串结尾
\b 匹配一个单词的边界
\B 匹配非单词的边界

分组匹配

字符 功能
| 匹配左右任意一个表达式
( ) 将括号中字符作为一个分组

贪婪匹配和惰性匹配

名称 字符 功能
贪婪匹配 .* 匹配尽可能多
惰性匹配 .*? 匹配尽可能少
1
2
3
4
5
我是大帅哥,我非常帅,大帅哥是我

我.*帅 会匹配到 我是大帅哥,我非常帅,大帅
我.*?帅 会匹配到 我是大帅

案例

匹配账号,数字和字母组成,长度6-10

1
2
3
4
import re
s="sdads2a"
A =re.findall(r'[a-zA-Z0-9]{6,10}',s)
print(A)

匹配qq,5-11位,第一位不为0

1
2
3
s="214566"
A =re.findall(r'^[1-9][0-9]{2,11}$',s)
print(A)

匹配电子邮箱

只允许qq,163,gmait

(可以数字,字母,_,-,.)@邮箱.内容

1
2
3
4
s="214566@qq.com"
r =r'(^[\w-]+(\.[\w-]+)*@(qq|163|gamil)(\.[\w-]+)+$)'
A =re.match(r,s)
print(A)

递归

递归就是函数调用自己

注意:递归必须要有结束条件

例如:一个获取文件夹的所以文件的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import os

def A (S):
AAA =[]
if os.path.exists(S): #判断路径是否存在
B =os.listdir(S) #列出文件夹的内容
for i in B:
C =S+ "/" +i
if os.path.isdir(C): # 判断路径是否是文件夹
AAA +=A(C)
else:
AAA.append((C,i))
else:
print("地址错误")
return AAA

print(A("D:/C++笔记/python/123"))

注意:

递归值要从内到外层层返回

完结撒花

11月16日至12月8日,历时22天