python语法

一 基础语法

1 基本操作

输出:

1
2
3
4
print("每日增长系数:%.1f,经过%d天的增长后,股价达到了:%0.2f" % (stock_price_daily_growth_factor, 
growth_days,stock_price_daily_growth_factor ** growth_days * stock_price))

print(f"公司:{name},股票代码:{stock_code},当前股价:{stock_price}")

输入:input()

1
2
name = input("请告诉我你是谁?\n")
print(f"我知道了,你是:{name}")

变量类型查看:type(num)

注释:

1
2
3
4
5
6
7
# 单行注释

"""
多行
注释
"""

2 数据容器

2.1 列表

image-20241015102741282

2.2 元组

元组如下特点:

  • 可以容纳多个数据
  • 可以容纳不同类型的数据(混装)
  • 数据是有序存储的(下标索引)
  • 允许重复数据存在
  • 不可以修改(增加或删除元素等)
  • 支持for循环

多数特性和list一致,不同点在于不可修改的特性

2.3 字符串

字符串常用操作

QQ_1728993503669

作为数据容器,字符串有如下特点:

  • 只可以存储字符串
  • 长度任意(取决于内存大小)
  • 支持下标索引
  • 允许重复字符串存在
  • 不可以修改(增加或删除元素等)
  • 支持for循环

序列的操作——切片

QQ_1729253002333 QQ_1729404550833

2.4 集合

特点:

  • 可以容纳多个数据
  • 可以容纳不同类型的数据(混装)
  • 数据是无序存储的(不支持下标索引)
  • 不允许重复数据存在
  • 可以修改(增加或删除元素等)
  • 支持for循环
QQ_1729405849701

2.5 字典

QQ_1729408491876

特点:

  • 可以容纳多个数据
  • 可以容纳不同类型的数据
  • 每一份数据是KeyValue键值对
  • 可以通过Key获取到Value,Key不可重复(重复会覆盖)
  • 不支持下标索引
  • 可以修改(增加或删除更新元素等)
  • 支持for循环,不支持while循环

3 数据容器特点对比

数据容器可以从以下视角进行简单的分类:

  • 是否支持下标索引
    • 支持:列表、元组、字符串-序列类型
    • 不支持:集合、字典-非序列类型
  • 是否支持重复元素
    • 支持:列表、元组、字符串-序列类型
    • 不支持:集合、字典-非序列类型
  • 是否可以修改
    • 支持:列表、集合、字典
    • 不支持:元组、字符串
QQ_1729409879651

使用场景:

QQ_1729409922983

sorted(容器,[reverse = True])

4 函数操作

4.1 多种参数使用形式

1
2
3
4
def user_info(name, age, gender):
print(f'您的姓名是{name},年龄是:{age},性别是:{gender}')

user_info("tom", 20, "男")

位置参数不定长:传进的所有参数都会被args变量收集,它会根据传进参数的位置合并为一个元组(tuple),args是元组类型,这就是位置传递

1
2
3
4
def user_info(*args):
print(args)

user_info("tom", 20, "男")

关键字参数不定长:参数是“键=值”形式的形式的情况下,所有的“键=值”都会被kwargs接受,同时会根据“键=值”组成字典

1
2
3
4
5
def user_info3(**kwargs):
print(kwargs)


user_info3(name="tom", age=20, gender="男")

4.2 匿名函数

4.2.1 函数作为参数传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 调用一个函数,接受另一个函数作为传入参数
def test_func(mult_func):
# 确定mult_func是函数
result = mult_func(2, 2)
print(f"计算的结果是:{result}")


# 定义一个函数,准备作为参数传入另一个函数
def mult_func(x, y):
return x * y


# 调用,并传入函数
test_func(mult_func)

4.2.2 lambda函数

函数的定义中

  • def键字,可以定义带有名称的函数
  • lambda关键字,可以定义匿名函数(无名称)

有名称的函数,可以基于名称重复使用

无名称的匿名函数,只可临时使用一次

匿名函数定义语法:

1
lambda 传入参数:函数体(一行代码)
  • lambda 是关键字,表示定义匿名函数
  • 传入参数表示匿名函数的形式参数,如:x,y表示接收2个形式参数
  • 函数体,就是函数的执行逻辑,要注意:只能写一行,无法写多行代码
1
2
3
4
5
6
7
8
# 调用一个函数,接受另一个函数作为传入参数
def test_func(mult_func):
# 确定mult_func是函数
result = mult_func(2, 2)
print(f"计算的结果是:{result}")

# 调用,并传入函数
test_func(lambda x, y: x * y)

二 文件操作

2.1 基本概念

在Python,使用open函数,可以打开一个已经存在的文件,或者创建一个新文件,语法如下:

1
open(name,mode,encoding)

name:是要打开的目标文件名的字符串(可以包含文件所在的具体路径)。

mode:设置打开文件的模式(访问模式):只读、写入、追加等。

QQ_1729420889601

encoding:编码格式(推荐使用UTF-8)

示例代码:

1
2
f = open('python.txt','r',encoding="UTF-8")
#encoding的顺序不是第三位,所以不能用位置参数,用关键字参数直接指定

2.2 读取相关操作

read()方法:

1
文件对象.read(num)

num表示要从文件中读取的数据的长度(单位是字节),如果没有传入num,那么就表示读取文件中所有的数据

readlines()方法:

readlines可以按照行的方式把整个文件中的内容进行一次性读取,并且返回的是一个列表,其中每一行的数据为一个元素。

1
2
3
4
# 通过在with open的语句块中对文件进行操作
# 可以在操作完成后自动关闭close文件,避免遗忘掉close方法
with open("python.txt", "r") as f:
f.readlines()
QQ_1729422292042

2.3 写入相关操作

覆盖用w

2.写入的方法有:

  • wirte(),写入内容
  • flush(),刷新内容到硬盘中

3.注意事项:

  • w模式,文件不存在,会创建新文件

  • w模式,文件存在,会清空原有内容

  • close()方法,带有flush()方法的功能

追加用a

三 异常

3.1 异常概念

捕获异常的作用在于:提前假设某处会出现异常,做好提前准备,当真的出现异常的时候,可以有后续手段。

1
2
3
4
try:
print(name)
except NameError as e:
print('name变量名称未定义错误')

异常的finally

finally表示的是无论是否异常都要执行的代码,例如关闭文件。

1
2
3
4
5
6
7
8
try:
f= open('test.txt', 'r')
except Exception as e:
f= open('test.txt', 'w')
else:
print('没有异常,真开心')
finally:
f.close()

异常的传递

异常是具有传递性的

当函数func01中发生异常,并且没有捕获处理这个异常的时候,异常会传递到函数func02,当func02也没有捕获处理这个异常的时候main函数会捕获这个异常,这就是异常的传递性

提示:当所有函数都没有捕获异常的时候,程序就会报错

3.2 模块

什么是模块?

Python 模块(Module),是一个Python 文件,以.py 结尾。模块能定义函数,类和变量,模块里也能包含可执行的代码

模块的作用:python中有很多各种不同的模块,每一个模块都可以帮助我们快速的实现一些功能,比如实现和时间相关的功能就可以使用time模块。我们可以认为一个模块就是一个工具包,每一个工具包中都有各种不同的工具供我们使用进而实现各种不同的功能。

大白话:模块就是一个Python文件,里面有类、函数、变量等,我们可以拿过来用(导入模块去使用)

1
2
3
4
5
6
7
8
# 模块块在使用前需要先导入 导入的语法如下
[from 模块名] import[模块 | 类 | 变量 | 函数 |*][as 别名]
# 常用的组合形式如:
import 模块名
from 模块名 import 类、变量、方法等
from 模块名 import *
import 块名 as别名
from 模块名 import 功能名 as 别名

name__main变量使用

if name ==“main ”表示,只有当程序是直接执行的才会进入if内部,如果是被导入的,则if无法进入

03_my_module_use.py

1
2
3
import my_module

print(my_module.add(1, 4))

my_module.py

1
2
3
4
5
def add(a, b):
return a + b

if __name__ == '__main__':
print(add(7, 2))

3.3 Python包

3.3.1 自定义包

创建包必须要有文件

QQ_1729496934323

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
"""
演示python包
"""


# 创建一个包

# 导入自定义包中的模块,并使用
# import my_package.my_module1
# import my_package.my_module2
#
# my_package.my_module1.info_print1()
# my_package.my_module2.info_print2()

# from my_package import my_module1
# from my_package import my_module2
#
# my_module1.info_print1()
# my_module2.info_print2()

# from my_package.my_module1 import info_print1
# from my_package.my_module2 import info_print2
#
# info_print1()
# info_print2()
# 通过__all__变量,控制import
from my_package import *

my_module1.info_print1()
my_module2.info_print2()

3.3.2 安装第三方包

什么是第三方包?

我们知道,包可以包含一堆的Python模块,而每个模块又内含许多的功能。所以,我们可以认为:一个包,就是一堆同类型功能的集合体。在Python程序的生态中,有许多非常多的第三方包(非Pvthon官方),可以极大的帮助我们提高开发效率,如:

  • 科学计算中常用的:numpy包
  • 数据分析中常用的:pandas包
  • 大数据计算中常用的:pyspark、apache-flink包
  • 图形可视化常用的:matplotlib、pyecharts
  • 人工智能常用的:tensorflow

这些第三方包,极大的丰富了python的编程生态,提高了我们的开发效率

安装方法:

由于pip是连接的国外的网站进行包的下载,所以有的时候会速度很慢我们可以通过如下命令,让其连接国内的网站进行包的安装:

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 包名称

pip install 包名称

四 可视化

4.1 基本介绍

4.1.1 json数据格式

  1. json:是一种轻量级的数据交互格式,采用完全独立于编程语言的文本格式来存储和表示数据(就是字符串)

    Python语言使用ISON有很大优势,因为:JSON无非就是一个单独的字典或一个内部元素都是字典的列表,所以JSON可以直接和

    Python的字典或列表进行无缝转换。

  2. json格式数据转化

    通过 json.dumps(data)方法把python数据转化为了 json数据

    data= json.dumps(data)

    如果有中文可以带上:ensure ascii-False参数来确保中文正常转换通过json.loads(data)方法把josn数据转化为了python列表或字典

4.1.2 pyecharts模块介绍

Echarts 是个由百度开源的数据可视化,凭借着良好的交互性,精巧的图表设计,得到了众多开发者的认可。而 Python 是门富有表达立的语言,很适合用于数据处理。当数据分析遇上数据可视化时pyecharts 诞生了

set _global opts方法(全局配置)

1
2
3
4
5
6
7
line.set_global_opts(
title_opts = Title0pts("测试", pos_left = "center", pos_bottom = "1%"),
legend_opts = Legendopts(is_show = True),
toolbox_opts = Toolbox0pts(is_show = True)
visualmap_opts = VisualMapOpts(is_show = True)
tooltip opts = Tooltipopts(is_show = True),
)

4.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
71
"""
演示可视化需求1:折线图开发
"""
import json
from pyecharts.charts import Line
from pyecharts.options import *

# 处理数据
f_us = open("utils/美国.txt", "r", encoding="utf-8")
us_data = f_us.read() # 美国的全部数据

f_jp = open("utils/日本.txt", "r", encoding="utf-8")
jp_data = f_jp.read() # 日本的全部数据

f_in = open("utils/印度.txt", "r", encoding="utf-8")
in_data = f_in.read() # 印度的全部数据

# 去掉不合JSON规范的开头
us_data = us_data.replace("jsonp_1629344292311_69436(", "")
jp_data = jp_data.replace("jsonp_1629350871167_29498(", "")
in_data = in_data.replace("jsonp_1629350745930_63180(", "")

# 去掉不合JSON规范的结尾
us_data = us_data[:-2]
jp_data = jp_data[:-2]
in_data = in_data[:-2]

# JSON转Python字典
us_dict = json.loads(us_data)
jp_dict= json.loads(jp_data)
in_dict = json.loads(in_data)

# 获取trend key
us_trend_data = us_dict['data'][0]['trend']
jp_trend_data = jp_dict['data'][0]['trend']
in_trend_data = in_dict['data'][0]['trend']

# 获取日期数据,用于x轴,取2020年(到 314 下标结束)
us_x_data = us_trend_data['updateDate'][:314]
jp_x_data = jp_trend_data['updateDate'][:314]
in_x_data = in_trend_data['updateDate'][:314]

# 获取确认数据,用于y轴,取2020年(到 314 下标结束)
us_y_data = us_trend_data['list'][0]['data'][:314]
jp_y_data = jp_trend_data['list'][0]['data'][:314]
in_y_data = in_trend_data['list'][0]['data'][:314]

# 生成图表
line = Line()

# 添加x轴数据
line.add_xaxis(us_x_data) # x轴数据是公用的,使用一个国家即可

# 添加y轴数据
line.add_yaxis("美国确诊人数", us_y_data, label_opts=LabelOpts(is_show=False))
line.add_yaxis("日本确诊人数", jp_y_data, label_opts=LabelOpts(is_show=False))
line.add_yaxis("印度确诊人数", in_y_data, label_opts=LabelOpts(is_show=False))

# 设置全局选项
line.set_global_opts(
title_opts=TitleOpts(title="2020年美日印三国确诊人数对比折线图", pos_left="center", pos_bottom='1%')
)


# 调用render方法生成图表
line.render(path="03_折线图.html")

# 关闭文件对象
f_us.close()
f_jp.close()
f_in.close()

4.3 地图可视化

地图现在版本更新必须将其补全

4.3.1 全国地图

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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :05_全国疫情可视化地图开发.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/10/23 19:45
"""
import json

from pyecharts.charts import Map
from pyecharts.options import TitleOpts, VisualMapOpts

import json
import os

# 读取原始数据文件
with open("疫情.txt", "r", encoding="utf-8") as f:
data = json.load(f)

lastUpdateTime = data["lastUpdateTime"]
lastUpdateTime = str(lastUpdateTime)
chinaTotal = data['chinaTotal']
chinaAdd = data["chinaAdd"]
isShowAdd = data["isShowAdd"],
print(isShowAdd)
showAddSwitch = data["showAddSwitch"],

# 更改需要的数据
province_list = data["areaTree"][0]["children"]

# 遍历省份列表,对全称进行补全
for province in province_list:
# 如果是几个直辖市后面直接写市
if province["name"] in ["北京", "上海", "天津", "重庆"]:
province["name"] += "市"
# 如果是港澳台,后面直接写特别行政区
elif province["name"] in ["香港", "澳门", ]:
province["name"] += "特别行政区"
elif province["name"] in ["内蒙古", "西藏"]:
province["name"] += "自治区"
elif province["name"] == "广西":
province["name"] = "广西壮族自治区"
elif province["name"] == "新疆":
province["name"] = "新疆维吾尔自治区"
elif province["name"] == "宁夏":
province["name"] = "宁夏回族自治区"

# 其他省份后面直接写省
else:
province["name"] += "省"

# 重新组织数据,生成新的 JSON 字符串
new_data = {
"lastUpdateTime": lastUpdateTime,
"chinaTotal": chinaTotal,
"chinaAdd": chinaAdd,
"isShowAdd": isShowAdd,
"showAddSwitch": showAddSwitch,
"areaTree": [data["areaTree"][0]]
}
new_data["areaTree"][0]["children"] = province_list
new_data_str = json.dumps(new_data, ensure_ascii=False, indent=4)

# 写回文件
with open("疫情.txt", "w", encoding="utf-8") as f:
f.write(new_data_str)

完成前期准备工作之后:

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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :05_全国疫情可视化地图开发.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/10/23 19:45
"""
import json

from pyecharts.charts import Map
from pyecharts.options import TitleOpts, VisualMapOpts

# 读取数据文件
f = open("utils/疫情.txt", "r", encoding="utf-8")
data = f.read()

# 关闭文件
f.close()
# 取到各省数据,并转换为字典
data_dict = json.loads(data)
province_data_list = data_dict["areaTree"][0]["children"]
# 组装每个省份和确诊人数为元组,并各个省的数据都封装入列表内
data_list = [] # 存放每个省份的数据
for province_data in province_data_list:
province_name = province_data["name"]
province_confirm = province_data["total"]["confirm"]
data_list.append((province_name, province_confirm))

print(data_list)
# 创建地图对象
map = Map()
# 添加数据
map.add("各省份确诊人数", data_list, "china")
# 设置全局配置,定制分段视觉映射
map.set_global_opts(
TitleOpts(title="全国疫情可视化地图"),
visualmap_opts=VisualMapOpts(
is_show=True,
is_piecewise=True,
pieces=[
{"min": 1, "max": 99, "label": "1-99人", "color": "#CCFFFF"},
{"min": 100, "max": 999, "label": "100-999人", "color": "#FFFF99"},
{"min": 1000, "max": 4999, "label": "1000-4999人", "color": "#FF9966"},
{"min": 5000, "max": 9999, "label": "5000-9999人", "color": "#FF6666"},
{"min": 10000, "max": 99999, "label": "10000-99999人", "color": "#CC3333"},
{"min": 100000, "label": "10000人以上", "color": "#990033"},
]
)

)
# 绘图
map.render("05_全国疫情可视化地图.html")

4.3.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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :06_省级疫情可视化开发.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/10/25 15:38
"""
import json

from pyecharts.charts import Map
from pyecharts.options import *

# 读取文件
f = open("../utils/疫情.txt", "r", encoding="UTF-8")
data = f.read()
# 关闭文件
f.close()
# 获取河南省数据
data_dict = json.loads(data)
cities_data = data_dict["areaTree"][0]["children"][1]["children"]

data_list = []
# 准备数据为元组并放入list
for city_data in cities_data:
city_name = city_data["name"] + "市"
city_confirm = city_data["total"]["confirm"]
data_list.append((city_name, city_confirm))

# 构建地图
map = Map()
map.add("江苏省疫情分布", data_list, "江苏").set_global_opts(
TitleOpts(title="全国疫情可视化地图"),
visualmap_opts=VisualMapOpts(
is_show=True,
is_piecewise=True,
pieces=[
{"min": 1, "max": 9, "label": "1-9人", "color": "#CCFFFF"},
{"min": 10, "max": 99, "label": "10-99人", "color": "#FFFF99"},
{"min": 100, "max": 199, "label": "100-199人", "color": "#FF9966"},
{"min": 200, "max": 299, "label": "200-299人", "color": "#FF6666"},
{"min": 300, "max": 399, "label": "300-399人", "color": "#CC3333"},
{"min": 400, "label": "400人以上", "color": "#990033"},
]
)
)

# 绘图
map.render("06_省级疫情可视化开发.html")

4.4 柱状图

4.4.1 基础柱状图

设置步骤:

  1. 通过Bar()构建一个柱状图对象
  2. 和折线图一样,通过add_xaxis()和add_yaxis()添加x和y轴数据
  3. 通过柱状图对象的:reversal_axis(),反转x和y轴
  4. 通过label_opts=LabelOpts(position=”right”)设置数值标签在右侧显示
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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :07_基础柱状图开发.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/10/25 16:57
"""

from pyecharts.charts import Bar
from pyecharts.options import *

# 使用Bar构建基础柱状图
bar = Bar()

# 添加X轴
bar.add_xaxis(["英国", "美国", "中国"])

# 添加Y轴
bar.add_yaxis("GDP", [100, 200, 300], label_opts=LabelOpts(position="right"), color="#990033")

# 反转X和Y轴
bar.reversal_axis()

# 绘图
bar.render("07_基础柱状图.html")

4.4.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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :08_基础时间线柱状图开发.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/10/25 17:45
"""

from pyecharts.charts import *
from pyecharts.options import *
from pyecharts.globals import *

bar1 = Bar()
bar1.add_xaxis(["英国", "美国", "中国"])
bar1.add_yaxis("GDP", [10, 20, 80], label_opts=LabelOpts(position="right"))
bar1.reversal_axis()

bar2 = Bar()
bar2.add_xaxis(["英国", "美国", "中国"])
bar2.add_yaxis("GDP", [40, 50, 90], label_opts=LabelOpts(position="right"))
bar2.reversal_axis()

bar3 = Bar()
bar3.add_xaxis(["英国", "美国", "中国"])
bar3.add_yaxis("GDP", [70, 100, 200], label_opts=LabelOpts(position="right"))
bar3.reversal_axis()

# 构建时间线对象
timeline = Timeline(
# 设置主题
{"theme": ThemeType.LIGHT}
)

# 在时间线内添加柱状图
timeline.add(bar1, "2017年")
timeline.add(bar2, "2018年")
timeline.add(bar3, "2019年")
# 自动播放设置
timeline.add_schema(
is_auto_play=True,
play_interval=1000,
is_loop_play=True,
is_timeline_show=True
)
# 时间线播放间隔
# 主题设置

# 绘图
timeline.render("08_基础时间线柱状图.html")

4.4.3 动态图绘制

列表的sort方法

使用方式:

列表.sort(key=选择排序依据的函数,reverse=TruelFalse)

参数key,是要求传入一个函数,表示将列表的每一个元素都传入函数中,返回排序的依据

参数reverse,是否反转排序结果,True表示降序,False表示升序

python版本3.7之后字典就开始排序了

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
81
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :10_GDP动态柱状图开发.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/10/25 18:25
"""
from pyecharts.charts import Bar, Timeline
from pyecharts.options import *
from pyecharts.globals import ThemeType

# 读取数据
f = open("../utils/1960-2019全球GDP数据.csv", "r", encoding="GB2312")
data_lines = f.readlines()

# 关闭文件
f.close()
# 删除第一条数据
data_lines.pop(0)

# 将数据转换为字典存储,格式为:
# {年份:[[国家,gdp],[国家,gdp],......],年份:[[国家,gdp],[国家,gdp],...... ],......}
data_dict = {}
for line in data_lines:
year = int(line.split(",")[0])
country = line.split(",")[1]
GDP = float(line.split(",")[2])

# 如何判断字典里面有没有指定的key讷?
try:
data_dict[year].append([country, GDP])
except KeyError:
data_dict[year] = []
data_dict[year].append([country, GDP])

# 创建时间线对象
timeline = Timeline({"theme": ThemeType.LIGHT})

# for循环每一年的数据,基于每一年的数据,创建每一年的bar对象
for year in data_dict.keys():
data_dict[year].sort(key=lambda element: element[1], reverse=True)
# 将每一年的数据按照gdp从大到小排序,取出前八
data_year = data_dict[year][0:8]

x_data = []
y_data = []

for element in data_year:
x_data.append(element[0])
y_data.append(element[1] / 1000000000)

# 创建bar对象
bar = Bar()
x_data.reverse()
y_data.reverse()

bar.add_xaxis(x_data)
bar.add_yaxis("GDP(亿)", y_data, label_opts=LabelOpts(position="right"))

# 反转x和y轴
bar.reversal_axis()

# 设置标题
bar.set_global_opts(
title_opts=TitleOpts(title=f"{year}年全球前8国家GDP数据")
)

# 在for中,将每一年的bar对象添加到时间线中
timeline.add(bar, str(year))

# 设置时间线自动播放
timeline.add_schema(
play_interval=1000,
is_auto_play=True,
is_loop_play=True,
is_timeline_show=True
)
# 绘图
timeline.render("10_1960-2019全球GDP前8国家.html")

五 面向对象

5.1 基本概念

5.1.1 成员变量

1
2
3
4
5
6
7
class student:
#学生的姓名
name = None
# 学生的年龄
age = None
def say_hi(self, msg):
print(f"Hi大家好,我是{self.name}{msg}")

5.1.2 类、对象和构造方法

类、对象:

1.现实世界的事物由什么组成?

  • 属性
  • 行为

类也可以包含属性和行为,所以使用类描述现实世界事物是非常合适的

构造方法:

Python类可以使用: –init–()方法,称之为构造方法。

可以实现:

  • 在创建类对象(构造类)的时候,会自动执行
  • 在创建类对象(构造类)的时候,将传入参数自动传递给 init 方法使用。
1
2
3
4
5
6
7
8
9
class Student:
name = None
age = None
tel = None

def __init__(self, name, age, tel):
self.name = name
self.age = age
self.tel =tel
QQ_1729862268576

例题:

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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :创建类对象.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/10/25 20:30
"""


class Student:
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address


# 通过for循环,配合input输入语句,并使用构造方法,完成学生信息的键盘录入
students = []

for i in range(3):
print(f"当前录入第{i + 1}位学生,总共需要录入3位")
# 输入学生姓名
name = input("请输入学生姓名:")
# 输入学生年龄
age = input("请输入学生年龄:")
# 输入学生成绩
address = input("请输入学生地址:")

# 创建学生对象
student = Student(name, age, address)
students.append(student)

# 打印学生信息
print(
{f"学生{i + 1}信息的信息录入完成,学生的信息为:【姓名:{student.name},年龄:{student.age},地址:{student.address}】"})

5.1.3 内置方法

魔术方法:

QQ_1729862337478
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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :02_内置方法.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/10/25 21:21
"""
from traceback import print_tb


class Student:
def __init__(self, name, age):
self.name = name
self.age = age

# __str__魔术方法
def __str__(self):
return f"Student类对象,name:{self.name},age:{self.age}"

# __lt__魔术方法
def __lt__(self, other):
return self.age < other.age

# __le__魔术方法
def __le__(self, other):
return self.age <= other.age

# __eq__魔术方法
def __eq__(self, other):
return self.age == other.age


student1 = Student("周杰伦", 30)
student2 = Student("邓紫棋", 20)

# __str__魔术方法
print(student1)

# __lt__魔术方法
print(student1 < student2)

# __le__魔术方法
student3 = Student("周杰伦", 30)
student4 = Student("邓紫棋", 33)

print(student3 <= student4)

# __eq__魔术方法
student5 = Student("周杰伦", 30)
student6 = Student("邓紫棋", 30)
print(student5 == student6)

5.2 封装

私有成员

类中提供了私有成员的形式来支持:私有成员变量;私有成员方法

定义私有成员的方式非常简单,只需要:

  • 私有成员变量:变量名以__开头(2个下划线)
  • 私有成员方法:方法名以__开头(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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :03_封装课后练习题.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/10/28 09:32
"""

# 设计一个类,用来描述手机
class Phone:
# 提供私有成员变量
__is_5g_enable = True
# 提供私有成员方法
def __check_5g(self):
if self.__is_5g_enable:
print("5g is enable")
else:
print("5g is disable")

# 提供公开的成员方法
def check_5g(self):
self.__check_5g()

phone = Phone()
phone.check_5g()

5.3 继承

5.3.1 单继承和多继承

  • 单继承:一个类继承另一个类
  • 多继承:一个类继承多个类,按照顺序从左向右依次继承

多继承中,如果父类有同名方法或属性,先继承的优先级高于后继承

pass关键字的作用是什么:

pass是占位语句,用来保证函数(方法)或类定义的完整性,表示无内容,空的意思

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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :04_继承.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/10/28 10:01
"""
from symtable import Class


class Phone:
IMEI = None
producer = "IT_CAST"

def call_by_5g(self):
print("5g通话已开启")

class NFCReader:
nfc_type = "第五代"
producer = "HM"

def read_card(self):
print("NFC读卡器已开启")

def wrire_card(self):
print("NFC写卡器已开启")

class RedRemoteControl:
rc_type = "红外遥控"

def control(self):
print("红外遥控器已开启")

class MyPhone(Phone, NFCReader, RedRemoteControl):
pass

phone = MyPhone()
phone.call_by_5g()
phone.read_card()
phone.wrire_card()
phone.control()
print(phone.producer)

5.3.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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :04_继承_复写.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/10/29 18:40
"""

class Phone:
IMEI = None
producer = "IT_CAST"

def call_by_5g(self):
print("5g通话已开启")

# 定义子类,复写父类方法
class MyPhone(Phone):
IMEI = "123456789012345"
producer = "Made in China"

def call_by_5g(self):
print("5g通话已开启,请拨打110")


myPhone = MyPhone()
print(myPhone.IMEI)
print(myPhone.producer)
myPhone.call_by_5g()

调用父类成员:

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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :04_继承_复写.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/10/29 18:40
"""

class Phone:
IMEI = None
producer = "IT_CAST"

def call_by_5g(self):
print("5g通话已开启")

# 定义子类,复写父类方法
class MyPhone(Phone):
IMEI = "123456789012345"
producer = "Made in China"

def call_by_5g(self):
print("开启单核模式,确保通话的时候省电")
# 调用父类方法方式一
print(f"父类的厂商是:{Phone.producer}")
Phone.call_by_5g(self)
print("----------------------")

# 调用父类方法方式二
print(f"父类的厂商是:{super().producer}")
super().call_by_5g()
print("关闭单核模式,确保通话的时候省电")


myPhone = MyPhone()
print(myPhone.IMEI)
print(myPhone.producer)
myPhone.call_by_5g()
image-20241029192021650

5.4 注解

5.4.1 类型注解

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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :05_类型注解.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/10/29 19:37
"""
import json
import random

# 基础数据类型注解
var_1: int = 10
var_2: str = "hello"
var_3: float = 10.0
var_4: bool = True


# 类对象类型注解
class Student:
pass


stu: Student = Student()
# 基础容器类型注解
My_list: list = [1, 2, 3]
my_tuple: tuple = (1, 2, 3)
my_dict: dict = {"name": "alaskaboo"}
my_set: set = {1, 2, 3}
# 容器类型注解即详细注解
my_list: list[int] = [1, 2, 3]
My_tuple: tuple[int, str, bool] = (1, "heima", True)
My_dict: dict[str, int] = {"name": 10}

# 在注释中进行类型注解
var_1 = random.randint(1, 10) # type: int
var_2 = json.loads('{"name": "alaskaboo"}') # type: dict[str, str]

def func():
return 10

var_3 = func() # type: int

类型注解主要功能在于:

帮助第三方IDE工具(如PyCharm)对代码导入类型推送,协助做代码提示

帮助开发者自身对变量进行类型注释(备注 )

5.4.2 形参注解

1
2
def 函数方法名(形参名:类型, 形参名:类型):
pass
1
2
3
4
5
def add(x:int, y:int):
return x + y

def func(data: list):
pass

5.4.3 Union类型

Union联合类型注解,在变量注解、函数(方法)形参和返回值注解中,均可使用。

1
2
3
4
5
6
7
8
9
from typing import Union

my_list: list[Union[str, int]] = [1, 2, "heima", "python"]
my_dict: dict[str, Union[str, int]] = {"name": "alaska", "age": 10}


# -> Union[int, str]是返回值
def func(data: Union[str, int]) -> Union[int, str]:
pass

5.5 多态

概念:多种状态,即完成某个行为时,使用不同的对象会得到不同的状态

image-20241029201529213
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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :06_多态.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/10/29 20:16
"""
class Animal:
def speak(self):
pass

class Dog(Animal):
def speak(self):
print("wang wang")

class Cat(Animal):
def speak(self):
print("miao miao")

def make_noise(animal: Animal):
animal.speak()

dog = Dog()
cat = Cat()
make_noise(dog)
make_noise(cat)
image-20241029201945720

空调例子:

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
# 演示抽象类
class AC:
def cool_wind(self):
"""制冷"""
pass

def hot_wind(self):
"""制热"""
pass

def swing_l_r(self):
"""左右摆风"""
pass


class Midea_AC(AC):
def cool_wind(self):
"""制冷"""
print("midea cool")

def hot_wind(self):
"""制热"""
print("midea hot")

def swing_l_r(self):
"""左右摆风"""
print("midea swing")


class GREE_AC(AC):
def cool_wind(self):
"""制冷"""
print("gree cool")

def hot_wind(self):
"""制热"""
print("gree hot")

def swing_l_r(self):
"""左右摆风"""
print("gree swing")

def make_coll(ac: AC):
ac.cool_wind()

Midea_AC = Midea_AC()
GREE_AC = GREE_AC()
make_coll(Midea_AC)
make_coll(GREE_AC)

综合案例

image-20241029203309792

data_define.py

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
# -*- coding: UTF-8 -*-
"""
@Project :定义数据类型
@File :data_define.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/10/29 20:36
"""


class Record:
def __init__(self, date, order_id, money, province):
# 订单日期
self.date = date
# 订单ID
self.order_id = order_id
# 订单金额
self.money = money
# 销售省份
self.province = province


# 将内存地址输出为对应的字符串
def __str__(self):
return f"{self.date}, {self.order_id}, {self.money}, {self.province}"

file_define.py

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
# -*- coding: UTF-8 -*-
"""
@Project :和文件相关的类定义
@File :file_define.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/10/29 20:42
"""
import json

from data_define import Record


# 先定义一个抽象类用来做顶层设计,确定有那些功能需要实现
class FileReader:

# 抽象方法,需要子类实现
def read_data(self) -> list[Record]:
"""
读取文件数据,将数据转换为Record对象,并将其list封装返回
:return:
"""
pass


# 定义一个具体的子类,实现抽象类的抽象方法
# 这个子类是用来读取文本文件的
class TextFileReader(FileReader):
def __init__(self, file_path):
# 文件路径
self.file_path = file_path

# 复写(实现抽象方法)父类的方法
def read_data(self) -> list[Record]:
f = open(self.file_path, 'r', encoding='utf-8')

record_list: list[Record] = []
for line in f.readlines():
# 消除数据中每一行的\n
line = line.strip()
data_list = line.split(",")
record = Record(data_list[0], data_list[1], int(data_list[2]), data_list[3])
record_list.append(record)

f.close()
return record_list


class JsonTextFileReader(FileReader):
def __init__(self, file_path):
# 文件路径
self.file_path = file_path

# 复写(实现抽象方法)父类的方法
def read_data(self) -> list[Record]:
f = open(self.file_path, 'r', encoding='utf-8')

record_list: list[Record] = []
for line in f.readlines():
data_dict = json.loads(line)
record = Record(data_dict['date'], data_dict['order_id'], int(data_dict['money']), data_dict['province'])
record_list.append(record)

f.close()
return record_list


if __name__ == '__main__':
text_file_reader = TextFileReader("utils/2011年1月销售数据.txt")
json_file_reader = JsonTextFileReader("utils/2011年2月销售数据JSON.txt")
list1 = text_file_reader.read_data()
list2 = json_file_reader.read_data()

for l in list1:
print(l)

for l in list2:
print(l)

main.py

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
# -*- coding: UTF-8 -*-
"""
@Project :面向对象,数据分析案例
@File :main.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/10/29 20:35
"""
from pyecharts.options import TitleOpts, LabelOpts

from file_define import *
from data_define import *
from pyecharts.charts import Bar
from pyecharts import *
from pyecharts.globals import ChartType

# 1.设计一个类,可以完成数据的封装
# 2.设计一个抽象类,定义文件读取的相关功能,并使用子类实现具体功能
# 3.读取文件,生产数据对象
# 4.进行数据需求的逻辑计算(计算每一天的销售额)
text_file_reader = TextFileReader("utils/2011年1月销售数据.txt")
json_file_reader = JsonTextFileReader("utils/2011年2月销售数据JSON.txt")

jan_data: list[Record] = text_file_reader.read_data()
feb_data: list[Record] = json_file_reader.read_data()

# 将两个数据合二为一
all_data: list[Record] = jan_data + feb_data

data_dict = {}
# 用字典数据计算
for record in all_data:
if record.date in data_dict.keys():
# 如果已经存在,则进行累加
data_dict[record.date] += record.money
else:

data_dict[record.date] = record.money
# 5.通过PyEcharts进行图形绘制
bar = Bar()
bar.add_xaxis(list(data_dict.keys()))
bar.add_yaxis("销售额", list(data_dict.values()), label_opts=LabelOpts(is_show=False))

bar.set_global_opts(
title_opts=TitleOpts(title="2011年1月-2月每日销售额"),
)
bar.render("2011年1月-2月每日销售额.html")

六 SQL

分组聚合

QQ_1730254829987

6.1 数据库连接

1.Python中使用什么第三方库来操作MySQL?如何安装?

  • 使用第三方库为:pymysql
  • 安装:pip install pymysql

2.如何获取链接对象?

  • from pymysqlimport Connection 导包
  • Connection(主机,端口,账户,密码)即可得到链接对象
  • 链接对象.close()关闭和MySQL数据库的连接

3.如何执行SQL查询

  • 通过连接对象调用cursor()方法,得到游标对象
  • 游标对象.execute()执行SQL语句
  • 游标对象.fetchall()得到全部的查询结果封装入元组内
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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :01_pymysql入门.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/11/04 18:50
"""

from pymysql import Connect

conn = Connect(
host='localhost',
port=3306,
user='root',
password='root',
charset='utf8'
)

# 执行非查询性质SQL
cursor = conn.cursor()
# 选择数据库
conn.select_db("test")

# 执行SQL
cursor.execute('SeLeCt * from student')

# 获取查询结果
result = cursor.fetchall()
for row in result:
print(row)
# 关闭连接
cursor.close()
conn.close()

6.2 数据插入

数据插入有两种方法:

方法一——使用conn.commit()方法

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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :02_数据插入.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/11/04 19:22
"""
from pymysql import Connect

conn = Connect(
host='localhost',
port=3306,
user='root',
password='root',
charset='utf8'
)

# 执行非查询性质SQL
cursor = conn.cursor()
# 选择数据库
conn.select_db("test")

# 执行SQL
cursor.execute('insert into student(name,addr,age,gender) values("Alaska","上海",24,"男")')
conn.commit()

cursor.close()
conn.close()

方法二——直接设置autocommit=True

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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :02_数据插入.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/11/04 19:22
"""
from pymysql import Connect

conn = Connect(
host='localhost',
port=3306,
user='root',
password='root',
charset='utf8'
autocommit=True
)

# 执行非查询性质SQL
cursor = conn.cursor()
# 选择数据库
conn.select_db("test")

# 执行SQL
cursor.execute('insert into student(name,addr,age,gender) values("Alaska","上海",24,"男")')

cursor.close()
conn.close()

6.3 综合案例

03_综合案例.py

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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :03_综合案例.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/11/04 19:29
"""
from file_define import *
from data_define import *
from pymysql import Connection

# 1.设计一个类,可以完成数据的封装
# 2.设计一个抽象类,定义文件读取的相关功能,并使用子类实现具体功能
# 3.读取文件,生产数据对象
# 4.进行数据需求的逻辑计算(计算每一天的销售额)
text_file_reader = TextFileReader("utils/2011年1月销售数据.txt")
json_file_reader = JsonTextFileReader("utils/2011年2月销售数据JSON.txt")

jan_data: list[Record] = text_file_reader.read_data()
feb_data: list[Record] = json_file_reader.read_data()

# 将两个数据合二为一
all_data: list[Record] = jan_data + feb_data

# 构建mysql数据库连接
conn = Connection(
host="localhost",
port=3306,
user="root",
password="root",
autocommit=True
)
# 获取游标对象
cursor = conn.cursor()
# 选择数据库
conn.select_db("py_sql")
# 组织sql语句
for record in all_data:
sql = (f"insert into orders(order_id, order_date, order_price, order_province)"
f" values('{record.order_id}','{record.date}', {record.money}, '{record.province}')")
print(sql)
# 执行sql语句

# 关闭连接对象
conn.close()

data_define.py

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
# -*- coding: UTF-8 -*-
"""
@Project :定义数据类型
@File :data_define.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/10/29 20:36
"""


class Record:
def __init__(self, date, order_id, money, province):
# 订单日期
self.date = date
# 订单ID
self.order_id = order_id
# 订单金额
self.money = money
# 销售省份
self.province = province


# 将内存地址输出为对应的字符串
def __str__(self):
return f"{self.date}, {self.order_id}, {self.money}, {self.province}"

file_define.py

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
# -*- coding: UTF-8 -*-
"""
@Project :和文件相关的类定义
@File :file_define.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/10/29 20:42
"""
import json

from data_define import Record


# 先定义一个抽象类用来做顶层设计,确定有那些功能需要实现
class FileReader:

# 抽象方法,需要子类实现
def read_data(self) -> list[Record]:
"""
读取文件数据,将数据转换为Record对象,并将其list封装返回
:return:
"""
pass


# 定义一个具体的子类,实现抽象类的抽象方法
# 这个子类是用来读取文本文件的
class TextFileReader(FileReader):
def __init__(self, file_path):
# 文件路径
self.file_path = file_path

# 复写(实现抽象方法)父类的方法
def read_data(self) -> list[Record]:
f = open(self.file_path, 'r', encoding='utf-8')

record_list: list[Record] = []
for line in f.readlines():
# 消除数据中每一行的\n
line = line.strip()
data_list = line.split(",")
record = Record(data_list[0], data_list[1], int(data_list[2]), data_list[3])
record_list.append(record)

f.close()
return record_list


class JsonTextFileReader(FileReader):
def __init__(self, file_path):
# 文件路径
self.file_path = file_path

# 复写(实现抽象方法)父类的方法
def read_data(self) -> list[Record]:
f = open(self.file_path, 'r', encoding='utf-8')

record_list: list[Record] = []
for line in f.readlines():
data_dict = json.loads(line)
record = Record(data_dict['date'], data_dict['order_id'], int(data_dict['money']), data_dict['province'])
record_list.append(record)

f.close()
return record_list


if __name__ == '__main__':
text_file_reader = TextFileReader("utils/2011年1月销售数据.txt")
json_file_reader = JsonTextFileReader("utils/2011年2月销售数据JSON.txt")
list1 = text_file_reader.read_data()
list2 = json_file_reader.read_data()

for l in list1:
print(l)

for l in list2:
print(l)

七 PySpark实战

7.1 基本概念

定义:Apache Spark是用于大规模数据(large-scala data)处理的统一(unified)分析引擎。Spark是一款分布式的计算框架,用于调度成百上千的服务器集群,计算TB、PB乃至EB级别的海量数据。

QQ_1730789118941 QQ_1730789168427
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :01_基础准备.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/11/04 21:18
"""

# 导包
from pyspark import SparkConf, SparkContext
# 创建SparkConf类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
# 创建SparkContext类对象
sc = SparkContext(conf=conf)
# 打印运行版本
print(sc.version)
# 停止SparkContext对象的运行
sc.stop()

7.2 RDD对象

如图可见,PySpark支持多种数据的输入,在输入完成后,都会得到一个:RDD类的对象

RDD全称为:弹性分布式数据集(ResilientDistributed Datasets)

PySpark针对数据的处理,都是以RDD对象作为载体,即:

  • 数据存储在RDD内
  • 各类数据的计算方法,也都是RDD的成员方法
  • RDD的数据计算方法,返回值依旧是RDD对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :02_spark文件读取.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/11/05 15:02
"""
from pyspark import *

conf = SparkConf().setMaster("local[*]").setAppName("test_park")

sc = SparkContext(conf=conf)

print(sc.textFile("utils/hello.txt").collect())

sc.stop()

7.3 RDD算子

7.3.1map和flatMap算子

功能:map算子,一条条处理(是将RDD的数据处理的逻辑 基于map算子中接收的处理函数),返回新的RDD

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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :02_spark文件读取.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/11/05 15:02
"""
from pyspark import SparkConf, SparkContext
import os
os.environ["PYSPARK_PYTHON"] = 'E:/Environment/python/python3.10.11/python.exe'

conf = SparkConf().setMaster("local[*]").setAppName("test_park")

sparkContext = SparkContext(conf=conf)

# 读取文件
# print(sc.textFile("utils/hello.txt").collect())

# 创建一个包含整数的 RDD
rdd = sparkContext.parallelize([1, 2, 3, 4, 5])


# 为每个元素执行的函数
def func(element):
return element * 10

# 应用 map 操作,将每个元素乘以 10,打印新的 RDD 中的内容
print(rdd.map(func).collect())

# 停止 PySpark 程序
sparkContext.stop()

改进lambda

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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :02_spark文件读取.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/11/05 15:02
"""
from pyspark import SparkConf, SparkContext
import os

os.environ["PYSPARK_PYTHON"] = 'E:/Environment/python/python3.10.11/python.exe'

conf = SparkConf().setMaster("local[*]").setAppName("test_park")

sparkContext = SparkContext(conf=conf)

# 读取文件
# print(sc.textFile("utils/hello.txt").collect())

# 创建一个包含整数的 RDD
rdd = sparkContext.parallelize([1, 2, 3, 4, 5])

# 应用 map 操作,将每个元素乘以 10,打印新的 RDD 中的内容
print(rdd.map(lambda x: x * 10).map(lambda x: x + 5).collect())

# 停止 PySpark 程序
sparkContext.stop()

flatMap:唯一不同就是对结果接触嵌套

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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :03_flatMap.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/11/05 16:09
"""
from pyspark import SparkConf, SparkContext
import os

os.environ["PYSPARK_PYTHON"] = 'E:/Environment/python/python3.10.11/python.exe'

conf = SparkConf().setMaster("local[*]").setAppName("test_park")

sparkContext = SparkContext(conf=conf)

# 创建一个包含整数的 RDD
rdd = sparkContext.parallelize(["itheima itcast hello", "hello world", "hello itheima"])

# 应用 map 操作,将每个元素乘以 10,打印新的 RDD 中的内容
print(rdd.map(lambda x: x.split(" ")).collect())
print(rdd.flatMap(lambda x: x.split(" ")).collect())

# 停止 PySpark 程序
sparkContext.stop()

7.3.2 reduceByKey

功能:针对KV型RDD,自动按照key分组,然后根据你提供的聚合逻辑,完成组内数据(value)的聚合操作

QQ_1730803927941
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :04_reduceByKey.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/11/05 18:53
"""
from pyspark import SparkConf, SparkContext
import os

os.environ["PYSPARK_PYTHON"] = 'E:/Environment/python/python3.10.11/python.exe'

conf = SparkConf().setMaster("local[*]").setAppName("test_park")

sparkContext = SparkContext(conf=conf)

# 创建一个包含整数的 RDD
rdd = sparkContext.parallelize([('男', 88), ('女', 99), ('男', 77), ('女', 66), ('男', 87)])

print(rdd.reduceByKey(lambda x, y: x + y).collect())

综合统计案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :05_综合案例.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/11/05 18:58
"""
from pyspark import *

import os

# 构建执行环境
os.environ["PYSPARK_PYTHON"] = 'E:/Environment/python/python3.10.11/python.exe'
conf = SparkConf().setMaster('local[*]').setAppName('account_spark')
sc = SparkContext(conf=conf)

# 读取数据文件
rdd = sc.textFile("utils/hello.txt")
# 取出全部单词将所有单词都转化成二元元组,单词为Key,Value设置为1
print(rdd.flatMap(lambda x: x.split(" ")).map(lambda x: (x, 1)).reduceByKey(lambda x, y: x + y).collect())
1
2
3
4
5
itheima itheima itcast itheima
spark python spark python itheima
itheima itcast itcast itheima python
python python spark pyspark pyspark
itheima python pyspark itcast spark

输出结果:[(‘itcast’, 4), (‘python’, 6), (‘itheima’, 7), (‘spark’, 4), (‘pyspark’, 3)]

7.3.3 filter、distinct和sortBy

filter:过滤掉不想要的,留下来的结果是想要的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :06_filter.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/11/05 19:19
"""
from pyspark import SparkConf, SparkContext
import os

os.environ["PYSPARK_PYTHON"] = 'E:/Environment/python/python3.10.11/python.exe'
conf = SparkConf().setMaster("local[*]").setAppName("test_park")
sparkContext = SparkContext(conf=conf)

# 创建一个包含整数的 RDD
rdd = sparkContext.parallelize([1, 2, 3, 4, 5])
# 过滤掉奇数,留下来的结果是偶数
print(rdd.filter(lambda x: x % 2 == 0).collect())

distinct:表示对RDD数据去重,返回新的RDD数据

1
2
3
4
# 创建一个包含整数的 RDD
rdd = sparkContext.parallelize([1, 2, 2, 3, 3, 4, 6, 9, 8, 1, 7, 5])
# 过滤掉奇数,留下来的结果是偶数
print(rdd.filter(lambda x: x % 2 == 0).distinct().collect())

sortBy:对数据进行排序,基于拟定的排序依据

1
2
3
4
rdd.sortBy(func, ascending=False, numPartitions=1)
# func:(T)→U :告知按照rdd中的哪个数据进行排序,比如 lambda x:x[1] 表示按照rdd中的第二列元素进行排序
# ascending True升序 False 降序
# numPartitions:用多少分区排序

综合案例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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :07_综合案例2.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/11/05 19:42
"""
from pyspark import *

import os, json

# 构建执行环境
os.environ["PYSPARK_PYTHON"] = 'E:/Environment/python/python3.10.11/python.exe'
conf = SparkConf().setMaster('local[*]').setAppName('account_spark')
sc = SparkContext(conf=conf)

# TODO 需求1:城市销售额排名
# 1.1 读取文件得到RDD
file_rdd = sc.textFile("utils/orders.txt")

# 1.2取出一个个JSON字符串
json_rdd = file_rdd.flatMap(lambda x: x.split('|'))

# 1.3将一个个JSON字符串转换为字典
dict_rdd = json_rdd.map(lambda x: json.loads(x))

# 1.4取出城市和销售额数据
city_with_money_rdd = dict_rdd.map(lambda x: (x['areaName'], int(x['money'])))

# 1.5按城市分组按销售额聚合,按销售额聚合结果进行排序
print("全国售卖商品销售额排序", city_with_money_rdd.reduceByKey(lambda x, y: x + y).sortBy(lambda x: x[1], ascending=False).collect())

# TODO 需求2:全部城市有哪些商品类别在售卖
# 2.1 取出全部的商品类别
print("全部售卖商品类别", dict_rdd.map(lambda x: x['category']).distinct().collect())

# TODO 需求3:北京市有哪些商品类别在售卖
# 3.1 取出北京市的商品类别
print("北京市售卖商品类别", dict_rdd.filter(lambda x: x['areaName'] == '北京').map(lambda x: x['category']).distinct().collect())

7.3.4 take、reduce和count、

reduce:按照传入的逻辑进行聚合

take:取出RDD的前N个元素,组成list返回

count:统计数据个数

7.4 算子写入文件

hadoop设置分区为1的两种方式:

方式1,SparkConf对象设置属性全局并行度为1

1
2
3
conf = SparkConf().setMaster('local[*]').setAppName('account_spark')
conf.set("spark.default.parallelism", "1")
sc = SparkContext(conf=conf)

方式2,创建RDD的时候设置(parallelize方法传入numSlices参数为1)

1
2
3
4
5
6
# 准备RDD1
rdd1 = sc.parallelize([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], numSlices=1)
# 准备RDD2
rdd2 = sc.parallelize([("hello", 3), ("Spark", 5), ("Hi", 7)], 1)
# 准备RDD3
rdd3 = sc.parallelize([[1, 3, 5], [6, 7, 9], [11, 13, 11]], 1)

综合案例

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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :09_综合案例3.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/11/06 08:39
"""
from pyspark import SparkContext, SparkConf
import os, json

os.environ["PYSPARK_PYTHON"] = 'E:/Environment/python/python3.10.11/python.exe'
os.environ['HADOOP_HOME'] = 'E:\Environment\hadoop-3.4.0'
conf = SparkConf(). \
setAppName("hotSearch"). \
setMaster("local[*]"). \
set("spark.default.parallelism", "1")
sc = SparkContext(conf=conf)

# 读取文件转换成RDD
rdd = sc.textFile("utils/search_log.txt")
# TODO 需求1: 热门搜索时间段Top3(小时精度)
# 1.1 取出全部的时间并转换为小时
# 1.2 转换为(小时,1)的二元元组
# 1.3 Key分组聚合Value
# 1.4 排序(降序)
# 1.5 取前3
result_rdd = rdd.map(lambda x: (x.split("\t")[0][:2], 1)). \
reduceByKey(lambda x, y: x + y). \
sortBy(lambda x: x[1], ascending=False, numPartitions=1). \
take(3)
print("需求1的结果是:", result_rdd)

# TODO 需求2:热门搜索词Top3
# 2.1 取出全部的搜索词
# 2.2 (词,1)二元元组
# 2.3 分组聚合
# 2.4 排序
# 2.5 Top3
search_rdd = rdd.map(lambda x: (x.split("\t")[2], 1)). \
reduceByKey(lambda x, y: x + y). \
sortBy(lambda x: x[1], ascending=False, numPartitions=1). \
take(3)
print("需求2的结果是:", search_rdd)
# TODO 需求3:统计黑马程序员关键字在什么时段被搜索的最多
# 3.1 过滤内容,只保留黑马程序员关键词
# 3.2 转换为(小时,1)的二元元组
# 3.3 Key分组聚合Value
# 3.4 排序(降序)
# 3.5 取前1
key_max_in_time_rdd = rdd.filter(lambda x: "黑马程序员" in x). \
map(lambda x: (x.split("\t")[0][:2], 1)). \
reduceByKey(lambda x, y: x + y). \
sortBy(lambda x: x[1], ascending=False, numPartitions=1). \
take(1)
print("需求3的结果是:", key_max_in_time_rdd)

# TODO 需求4:将数据转化为JSON格式,写到文件中
# 4.1 转化为JSON格式的RDD
# 4.2 写为文件
rdd.map(lambda x: x.split("\t")). \
map(lambda x: {"Time": x[0], "User_id": x[1], "Search_word": x[2],
"Search_count": x[3], "Clicks_count": x[4], "Search_URL": x[5]}). \
saveAsTextFile("search_log_json")

八 高阶学习

8.1 闭包

概念:为了改变全局变量有被修改的风险,在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数称为闭包。

优点,使用闭包可以让我们得到:

  • 无需定义全局变量即可实现通过函数,持续的访问、修改某个值
  • 闭包使用的变量的所用于在函数内,难以被错误的调用修改

缺点:

  • 由于内部函数持续引用外部函数的值,所以会导致这一部分内存空间不被释放一直占用内存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 简单闭包
def create_logo_printer(logo: str) -> callable:
"""
创建一个打印带有logo的消息的函数
:param logo: logo文本
:return: 一个打印带有logo的消息的函数logo_printer
"""

def logo_printer(msg: str) -> None:
"""
打印带有logo的消息
:param msg: 消息文本
:return: None
"""
return print(f"<{logo}>{msg}<{logo}>")

return logo_printer


fn1 = create_logo_printer("中国")
fn1("重庆")

使用nonlocal关键字修改外部函数的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 使用nonlocal关键字修改外部函数的值
def create_accumulator(initial_value: int) -> callable:
"""
Creates an accumulator function that adds a given increment to the initial value.

Args:
initial_value: The initial value of the accumulator.

Returns:
A function that takes an increment and returns the updated accumulator value.
"""

def accumulator(increment: int) -> int:
nonlocal initial_value
initial_value += increment
print(initial_value)

return accumulator


fn = create_accumulator(10)
fn(23)

ATM小案例

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
# ATM小案例
def create_account(initial_amount=0):
balance = initial_amount

def transaction(amount, deposit=True):
nonlocal balance
if deposit:
balance += amount
print(f"存款:+{amount}, 余额:{balance}")
else:
if balance >= amount:
balance -= amount
print(f"取款:-{amount}, 余额:{balance}")
else:
print("余额不足")

def get_balance():
return balance

return transaction, get_balance
account, get_balance = create_account(1000)
account(500, deposit=True) # 存款 500
account(200, deposit=False) # 取款 200
print(get_balance()) # 获取当前余额

8.2 装饰器

普通写法

1
2
3
4
5
6
7
8
9
# 装饰器一般写法(闭包)
def sleep():
import random
import time
print("sleeping...")
time.sleep(random.randint(1, 5))
print("I want to sleep")
sleep()
print("I have slept")

装饰器一般写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 装饰器一般写法(闭包)
def decorator(func):
def wrapper():
print("I want to sleep")
func()
print("I have slept")

return wrapper


def sleep():
import random
import time
print("sleeping...")
time.sleep(random.randint(1, 5))

# 使用`decorator`装饰器包装原函数`sleep`,并调用包装后的函数。
decorator(sleep)()

语法糖写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 装饰器的快捷写法
def decorator(func):
def wrapper():
print("I want to sleep")
func()
print("I have slept")

return wrapper

@decorator
def sleep():
import random
import time
print("sleeping...")
time.sleep(random.randint(1, 5))

sleep()

8.3 设计模式

8.3.1 单例模式

概念:单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

定义:保证一个类只有一个实例,并提供一个访问它的全局访问点

适用场景:当一个类只能有一个实例,而客户可以从一个众所周知的访问点访问它时。

单例模式_strTools.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :单例模式_strTools.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/11/07 20:17
"""
from 单例模式_strTools import str_tools

t1 = str_tools
t2 = str_tools
print(id(t1))
print(id(t2))

单例模式_strTools.py

1
2
3
4
5
6
7
8
9
10
11
12
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :单例模式_strTools.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/11/07 20:17
"""
class StrTools:
pass

str_tools = StrTools()

输出结果:相当于使用的一个实例化对象~

1
2
3
4
2199380285360
2199380285360

进程已结束,退出代码为 0

8.3.2 工厂模式

概念:当需要大量创建一个类的实例的时候,可以使用工厂模式。即,从原生的使用类的构造去创建对象的形式迁移到,基于工厂提供的方法去创建对象的形式。

QQ_1730982484566
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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :05_工厂模式.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/11/07 20:28
"""


class Person:
pass


class Worker(Person):
print("I am a worker")


class Student(Person):
print("I am a student")


class Teacher(Person):
print("I am a teacher")


class Factory:

def get_person(self, person_type):
if person_type == 'worker':
return Worker()
elif person_type == 'student':
return Student()
else:
return Teacher()


factory = Factory()
print(factory.get_person('worker'))
print(factory.get_person('student'))
print(factory.get_person('teacher'))

8.4 多线程

8.4.1 进程、线程和并行执行

进程:就是一个程序,运行在系统之上,那么便称之这个程序为一个运行进程,并分配进程ID方便系统管理。
线程:线程是归属于进程的,一个进程可以开启多个线程,执行不同的工作,是进程的实际工作最小单位。

并行执行:同一时间做不同的工作。

进程之间就是并行执行的,操作系统可以同时运行好多程序,这些程序都是在并行执行。

QQ_1730983615518

进程之间是内存隔离的,即不同的进程拥有各自的内存空间。这就类似于不同的公司拥有不同的办公场所。

线程之间是内存共享的,线程是属于进程的,一个进程内的多个线程之间是共享这个进程所拥有的内存空间的,

这就好比,公司员工之间是共享公司的办公场所。

8.4.2 多线程编程

QQ_1730986269110

单线程示例:

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

def sing():
while True:
print("I am singing....")
time.sleep(1)


def dance():
while True:
print("I am dancing....")
time.sleep(1)

if __name__ == '__main__':
sing()
dance()

多线程:

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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :06_多线程.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/11/07 21:33
"""

import time, threading

def sing(msg):
while True:
print(msg)
time.sleep(1)


def dance(msg):
while True:
print(msg)
time.sleep(1)

if __name__ == '__main__':
# 创建一个唱歌的进程,并传入参数args=('我在唱歌',),一定要带括号才是元组形式
sing_thread = threading.Thread(target=sing, args=('我在唱歌',))

# 创建一个跳舞的进程
dance_thread = threading.Thread(target=dance,kwargs={'msg':'我在跳舞'})
sing_thread.start()
dance_thread.start()

8.5 网络编程

socket(简称 套接字)是进程之间通信一个工具,好比现实生活中的插座,所有的家用电器要想工作都是基于插座进行,进程之间想要进行网络通信需要socket
Socket负责进程之间的网络数据传输,好比数据的搬运工。

8.5.1 服务端编程

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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :07_socket_服务端开发.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/11/08 18:33
"""
import socket

# 创建Socket对象
socket_server = socket.socket()
# 绑定ip地址和端口
socket_server.bind(('127.0.0.1', 8888))
# 监听端口,括号内的是服务器监听数量
socket_server.listen(5)
# 等待客户端连接
# result: tuple = socket_server.accept()
# conn = result[0]
# address = result[1]
conn, address = socket_server.accept()
print(f"接收到了客户端的连接,客户端的信息是:{address}")

while True:
# 接受客户端信息recv是缓冲区的大小,一般给定1024即可
data: str = conn.recv(1024).decode("utf-8")

print(f"客户端发来的消息是:{data}")
# 发送回复消息
msg = input("请输入你要和客户端回复的消息:")
if msg == "exit":
break
conn.send(msg.encode("utf-8"))

# 关闭链接
conn.close()
socket_server.close()

8.5.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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :08_socket_客户端开发.py.py
@IDE :PyCharm
@Author :AlaskaBoo
@Date :2024/11/08 19:08
"""

import socket
# 创建socket对象
socket_client = socket.socket()
# 连接到服务端
socket_client.connect(('127.0.0.1', 8888))
while True:
# 发送消息
msg = input("请输入要给服务器发送的消息:")
if msg == 'exit':
break
socket_client.send(msg.encode('utf-8'))
# 接收返回消息
receive_data = socket_client.recv(1024)
print(f"服务端回复的消息是:{receive_data.decode('utf-8')}")
# 关闭链接
socket_client.close()

8.6 正则表达式

8.6.1 基本概念

正则表达式,又称规则表达式(Regular Expression),是使用单个字符串来描述、匹配某个句法规则的字符串,常被用来检索、替换那些符合某个模式(规则)的文本。即字符串定义规则,并通过规则去验证字符串是否匹配。

比如,验证一个字符串是否是符合条件的电子邮箱地址,只需要配置好正则规则,即可匹配任意邮箱。

比如通过正则规则:(^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$)即可匹配一个字符串是否是标准邮箱格式

但如果不使用正则,使用ifelse来对字符串做判断就非常困难了

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

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

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

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

低阶使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :09_正则表达式.py
@IDE :PyCharm
@Author :AlaskaBoo
@Date :2024/11/08 19:53
"""
import re

s = 'python itheima itcast python python itheima'
# match 从头匹配
result = re.match("python", s)
print(result)

# search 从头开始搜索,找到第一个匹配项
result = re.search("itcast", s)
print(result)

# findall 返回所有匹配项的列表
result = re.findall("python", s)
print(result)

8.6.2 元字符匹配

字符 功能
. 匹配任意一个字符(除了\n),\.匹配点本身
[] 匹配[]中列举的字符
\d 匹配数字,即0-9
\D 匹配非数字
\s 匹配空白,即空格、tab键
\S 匹配非空白
\w 匹配单词字符,即a-z、A-Z、0-9、_
\W 匹配非单词字符

数量匹配:

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

边界匹配:

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

分组匹配:

字符 功能
| 匹配左右任意一个表达式
() 将括号中字符作为一个分组
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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :09_正则表达式_元字符匹配.py
@IDE :PyCharm
@Author :AlaskaBoo
@Date :2024/11/08 20:21
"""
import re

s = "itcast1 @@python131¥%R#$%^&*() !! 666 ##itheima3"

result = re.findall(r"[a-zA-Z0-9]", s)
print(result)
# 匹配账号,只能由字母和数字组成,长度限制6到10位
r = "^[a-zA-Z0-9]{6,10}$"
s = "itcast1"
s1 = '123456789990'
print(re.findall(r, s))
print(re.findall(r, s1))

print("-----------------------")
# 匹配QQ号,要求纯数字,长度5-11,第一位不为0
r = "^[1-9][0-9]{4,10}$"
s = "123456789"
s1 = '123456789990'
print(re.findall(r, s))
print(re.findall(r, s1))


# 匹配邮箱地址,只允许qq、163、gmail这三种邮箱地址
r = r"(^[\w-]+(\.[\w-]+)*@(163|qq|gmail)(\.[\w-]+)+$)"
s = "upchh@example.com"
s1 = 'anpch@126.com'
s2 = 'envkt@163.com'
s3 = 'envkt@qq.com'
s4 = 'envkt@gmail.com'
print(re.match(r, s))
print(re.match(r, s1))
print(re.match(r, s2))
print(re.match(r, s3))
print(re.match(r, s4))

8.7 递归

  1. 概念:在满足条件的情况下,函数自己调用自己的一种特殊编程

  2. 技巧递归需要注意什么?

    • 注意退出的条件,否则容易变成无限递归

    • 注意返回值的传递,确保从最内层,层层传递到最外层

  3. os模块的3个方法

    • os.listdir,列出指定目录下的内容
    • os.path.isdir,判断给定路径是否是文件夹,是返回True,否返回False
    • os.path.exists,判断给定路径是否存在,存在返回True,否则返回False
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
# -*- coding: UTF-8 -*-
"""
@Project :pythonProject
@File :10_递归.py
@IDE :PyCharm
@Author :Alaskaboo
@Date :2024/11/08 21:05
"""
import os


def test_os():
# 列出路径下的内容
# print(os.listdir("E:\Markdown"))
# 判断指定路径是不是文件夹
# print(os.path.isdir("E:\Markdown"))
# 判断指定路径是不是存在
print(os.path.exists("E:\Markdown"))


def get_files_recursion_from_dir(path):
"""
从指定的文件夹中使用递归的方式,获取全部的文件列表
:param path: 被判断的文件夹
:return: list,包含全部的文件,如果目录不存在或者无文件就返回一个空list
"""
print(f"当前调用的路径是:{path}")
# 初始化一个空list
file_list = []
if os.path.exists(path):
for f in os.listdir(path):
new_path = path + '/' + f
# 如果是文件夹,就递归调用
if os.path.isdir(new_path):
file_list += get_files_recursion_from_dir(new_path)
else:
# 如果是文件,就添加到列表中
file_list.append(new_path)

else:
print(f"指定文件目录{path},不存在")
return []
return file_list


if __name__ == '__main__':
test_os()
print(get_files_recursion_from_dir(r"D:\上工程文件"))


python语法
http://example.com/2024/06/25/python学习/
作者
Alaskaboo
发布于
2024年6月25日
更新于
2025年6月28日
许可协议