Appearance
python 基础语法笔记
数据类型
| 类型名 | 关键字 | 说明 | 例子 | type() 返回值 |
|---|---|---|---|---|
| 整数 | int | 没有小数的数值 | 42, -3 | <class 'int'> |
| 浮点数 | float | 有小数的数值 | 3.14, -0.5 | <class 'float'> |
| 字符串 | str | 文本数据 | 'hello' | <class 'str'> |
| 布尔值 | bool | 逻辑值 True 或 False | True, False | <class 'bool'> |
| 列表 | list | 有序的元素集合 | [1, 'a', 3.14] | <class 'list'> |
| 元组 | tuple | 有序的不可变元素集合 | (1, 'a', 3.14) | <class 'tuple'> |
| 字典 | dict | 键值对集合 | {'name': 'Alice', 'age': 25} | <class 'dict'> |
| 集合 | set | 无序的唯一元素集合 | {1, 2, 3} | <class 'set'> |
| 复数 | complex | 包含实部和虚部的数 | 3 + 4j | <class 'complex'> |
| 二进制 | bytes | 二进制数据 | b'\x00\x01' | <class 'bytes'> |
| 内存视图 | memoryview | 字节对象的内存视图 | memoryview(b'ABC') | <class 'memoryview'> |
| 自定义对象 | 无 | 使用类定义的对象实例 | MyClass() | <class '__main__.MyClass'> |
算术运算符
| 运算符 | 说明 | 例子 | 结果 |
|---|---|---|---|
+ | 加法 | 5 + 3 | 8 |
- | 减法 | 5 - 3 | 2 |
* | 乘法 | 5 * 3 | 15 |
/ | 除法 | 5 / 3 | 1.6666666666666667 |
// | 整除(向下取整) | 5 // 3 | 1 |
% | 取余(模运算) | 5 % 3 | 2 |
** | 幂运算 | 5 ** 3 | 125 |
+x | 正号(不变) | +5 | 5 |
-x | 负号(取反) | -(-3) | 3 |
定义字符串的方式
| 定义方式 | 例子 | 特点 |
|---|---|---|
| 单引号 | 'hello' | 适用于单行字符串。如果字符串中不包含单引号,可以使用单引号定义。 |
| 双引号 | "hello" | 适用于单行字符串。如果字符串中不包含双引号,可以使用双引号定义。 |
| 三引号 | '''hello''' 或 """hello""" | 适用于多行字符串。可以包含换行符、制表符等。常用于文档字符串、多行注释或诗歌等。三引号可以是三个单引号或三个双引号,也可以混合使用。 |
mermaid
graph TD
A-->Dif while for range
| 类型 | 关键字 | 说明 | 语法 | 示例代码 | 输出 |
|---|---|---|---|---|---|
| 判断语句 | if | 条件为真时执行的代码块 | if 条件表达式:代码块 | if x > 5:print("x is greater than 5") | "x is greater than 5" (如果 x > 5) |
elif | 如果之前的条件为假,当前条件为真时执行的代码块 | elif 条件表达式:代码块 | elif x == 5:print("x is equal to 5") | "x is equal to 5" (如果 x == 5) | |
else | 所有条件为假时执行的代码块 | else:代码块 | else:print("x is less than 5") | "x is less than 5" (如果 x < 5) | |
| 循环语句 | for | 遍历序列的元素 | for 变量 in 序列:代码块 | for fruit in ["apple", "banana", "cherry"]:print(fruit) | apple banana cherry |
while | 只要条件为真,就不断循环执行代码块 | while 条件表达式:代码块 | i = 1while i <= 5:print(i)i += 1 | 1 2 3 4 5 | |
range() | 生成一个整数序列,通常用于 for 循环 | range([start,] stop[, step]) | for i in range(1, 6):print(i) | 1 2 3 4 5 |
函数
| 特性 | 说明 | 语法/示例 |
|---|---|---|
| 定义 | 创建一个新函数 | def function_name(parameters):代码块 |
| 调用 | 使用函数名和参数列表来执行函数 | function_name(arguments) |
| 参数 | 函数定义中用于接收输入值的变量 | def add(a, b):return a + b |
| 返回值 | 函数执行完毕后返回的值 | def add(a, b):return a + b |
| 默认参数 | 给参数指定默认值,调用时可以不传递该参数 | def greet(name="World"):print("Hello, " + name) |
| 可变参数 | 允许函数接受任意数量的参数 | def add(*args):return sum(args) |
| 关键字参数 | 允许函数接受任意数量的关键字参数 | def create_dict(**kwargs):return kwargs |
| 命名关键字参数 | 允许函数接受一定数量的命名关键字参数 | def create_dict(name, age, **kwargs):return {"name": name, "age": age, **kwargs} |
| 函数说明 | 函数的第一行文本,用来解释函数的作用 | def add(a, b):"""Return the sum of a and b."""return a + b |
| 嵌套函数 | 在一个函数内部定义另一个函数 | def outer():def inner():print("Inside inner function")inner() |
| 函数属性 | 函数也是一个对象,可以有属性和方法 | def my_function():passmy_function.__name__ |
| 作用域 | 变量在函数内定义则为局部变量,定义在函数外则为全局变量 | x = 5def my_function():y = 10print(x) inside function prints 5, y inside function is local |
| global | 在函数内部声明变量为全局变量,允许修改全局变量的值 | x = 5def my_function():global xx = 10my_function()print(x) prints 10 |
| 多返回值 | 函数可以返回多个值 | def get_user_info():return name, age, email |
| 多传参方式 | 函数支持多种参数传递方式 | def my_func(a, b, *args, **kwargs):pass |
| 函数作为参数 | 函数本身可以作为另一个函数的参数 | def apply_func(func, a, b):return func(a, b) |
| 位置参数 | 调用函数时根据函数定义的参数位置来传递参数 | def func(a, b):print(a, b)func(1, 2) |
| 关键字参数 | 函数调用时通过“键=值”形式传递参数 | def func(**args):print(args)func(b=2, a=1) |
| 缺省参数 默认参数 | 定义函数时为参数提供默认值, 注意:所有位置参数必须出现在默认参数前,包括函数定义和调用) | def func(a, b=10):print(a, b) |
| 不定长参数 | 位置不定长传递以*号标记一个形式参数,以元组的形式接受参数,形式参数一般命名为args 关键字不定长传递以**号标记一个形式参数,以字典的形式接受参数,形式参数一般命名为kwargs | |
| 函数作为参数传递 | 就像上述代码那样,不仅仅是相加,相见、相除、等任何逻辑都可以自行定义并作为函数传入 | def test_func(compute): result compute(1,2) print(result) def compute(x, y): return X test_func(compute) #结果:2 |
| 匿名函数 | 使用 lambda 关键词创建的简洁函数注意:函数体只能写一行,无法写多行代码 | add = lambda a, b: a + bprint(add(2, 3))示例: def test_func(compute) : return = compute(1, 2) test_func(lambda x , y : x + y) # 结果为3 |
容器
容器总结
| 名称 | 关键字 | 特点 | 容器示例 | 常见方法 | 遍历方法 | 切片 | 切片示例 | 遍历示例 | 注意事项 |
|---|---|---|---|---|---|---|---|---|---|
| 列表 | list | 有序、可变、允许重复、可通过下标访问 | [1, 'a', 3.14] | append(x): 添加元素到列表末尾extend( iterable ): 扩展列表pop([index]): 删除并返回指定位置的元素remove(x): 移除列表中第一个匹配的元素index(x): 返回元素第一次出现的索引count(x): 返回元素在列表中出现的次数sort(key=None, reverse=False): 对列表进行排序reverse(): 反转列表 | 直接遍历 | 支持 | my_list[1:3] | for item in my_list: print(item) | 可以修改,可以包含不同类型的元素,支持嵌套 |
| 元组 | tuple | 有序、不可变、允许重复、可通过下标访问 | (1, 'a', 3.14) | index(x): 返回元素第一次出现的索引count(x): 返回元素在元组中出现的次数 | 直接遍历 | 支持 | my_tuple[1:3] | for item in my_tuple: print(item) | 创建后不可修改,可以包含不同类型的元素,支持嵌套 |
| 字符串 | str | 有序、不可变、元素唯一、可通过下标访问 | "hello" | index(x): 返回子字符串第一次出现的索引count(x): 返回子字符串在字符串中出现的次数strip(chars=None): 移除字符串首尾的空格或指定字符split(sep=None, maxsplit=-1): 按照指定分隔符分割字符串replace(old, new, count=-1): 替换字符串中的子字符串 | 直接遍历 | 支持 | "hello"[1:3] | for char in "hello": print(char) | 不可变,元素为字符,支持下标索引 |
| 集合 | set | 无序、可变、元素唯一、不可通过下标访问 | {1, 2, 3} | add(x): 向集合添加元素remove(x): 移除集合中指定元素discard(x): 移除集合中指定元素,如果不存在不报错clear(): 清空集合union(*iterables): 返回两个集合的并集intersection(*iterables): 返回两个集合的交集difference(*iterables): 返回两个集合的差集 | 直接遍历 | 不支持 | N/A | for item in my_set: print(item) | 元素唯一,无序,不可下标索引,可以进行集合运算 |
| 字典 | dict | 无序、可变、键值对、键唯一、不可通过下标访问 | {'name': 'Alice', 'age': 25} | get(x, default=None): 通过键获取值,如果键不存在返回默认值keys(): 获取字典中所有的键values(): 获取字典中所有的值items(): 获取字典中所有的键值对update(*args, **kwargs): 更新字典pop(k[, d]): 删除字典中指定键的键值对clear(): 清空字典 | 遍历键或项 | 不支持 | N/A | for key, value in my_dict.items(): print(key, value) | 键值对存储,键必须是不可变类型,如字符串或元组,不支持下标索引,但可以通过键访问 |
通用功能
| 功能 | 描述 |
|---|---|
| 通用for循环 | 遍历容器(字典是遍历key) |
| max | 容器内最大元素 |
| min() | 容器内最小元素 |
| len() | 容器元素个数 |
| list() | 转换为列表 |
| tuple() | 转换为元组 |
| str() | 转换为字符串 |
| set() | 转换为集合 |
| sorted(序列, [reverse=True]) | 排序,reverse=True表示降序 得到一个排好序的列表 |
切片
| 切片语法 | 说明 | 示例 | 结果 | 支持切片的容器 |
|---|---|---|---|---|
s[start:stop:step] | 从索引 start 开始到 stop 结束(不包括 stop),步长为 step | a = [0, 1, 2, 3, 4, 5]a[1:5:2] | [1, 3] | 列表、元组、字符串 |
s[start:] | 从索引 start 到序列末尾 | a = [0, 1, 2, 3, 4, 5]a[2:] | [2, 3, 4, 5] | 列表、元组、字符串 |
s[:stop] | 从序列开头到索引 stop(不包括 stop) | a = [0, 1, 2, 3, 4, 5]a[:3] | [0, 1, 2] | 列表、元组、字符串 |
s[:] | 复制整个序列 | a = [0, 1, 2, 3, 4, 5]a[:] | [0, 1, 2, 3, 4, 5] | 列表、元组、字符串 |
s[-step:] | 从序列末尾向前取 step 个元素 | a = [0, 1, 2, 3, 4, 5]a[-3:] | [3, 4, 5] | 列表、元组、字符串 |
s[:-step] | 取序列开头到索引 -step(不包括 -step)的元素 | a = [0, 1, 2, 3, 4, 5]a[:-3] | [0, 1] | 列表、元组、字符串 |
s[start:stop:-1] | 逆向切片,从索引 start 到 stop 逆向取元素 | a = [0, 1, 2, 3, 4, 5]a[3:0:-1] | [3, 2, 1] | 列表、元组、字符串 |
s[::-1] | 完全逆向切片,即反转序列 | a = [0, 1, 2, 3, 4, 5]a[::-1] | [5, 4, 3, 2, 1, 0] | 列表、元组、字符串 |
列表推导式
[expression for item in iterable]
python
"""
"""
original_list = [1, 2, 3, 4, 5]
squared_list = [x**2 for x in original_list] # == [1, 4, 9, 16, 25]
"""
带条件的
"""
original_list = [1, 2, 3, 4, 5]
even_squared_list = [x**2 for x in original_list if x % 2 == 0]
# even_squared_list == [4,16]
"""
嵌套使用for
"""
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened_list = [num for row in matrix for num in row]
"""
带占位符`_`
dp == [
[0, 0, 0, 0, 0], # 第0行
[0, 0, 0, 0, 0], # 第1行
[0, 0, 0, 0, 0], # 第2行
[0, 0, 0, 0, 0] # 第3行
]
"""
a = [1, 2, 3] # 假设a的长度为3
m = 4
dp = [[0] * (m + 1) for _ in range(len(a) + 1)]文件处理
| 操作类型 | 函数/方法 | 描述 | 模式 | 示例代码 |
|---|---|---|---|---|
| 打开文件 | open() | 打开文件并返回文件对象 | 可指定模式和编码 | f = open('example.txt', 'r', encoding='utf-8') |
| 读取文件 | read(size) | 读取指定数量的字节 | 读模式 'r' | content = f.read(10) |
readline() | 读取文件的一行 | 读模式 'r' | line = f.readline() | |
readlines() | 读取所有行,返回列表 | 读模式 'r' | lines = f.readlines() | |
| 写入文件 | write(string) | 将字符串写入文件 | 写模式 'w' | f.write('Hello, World!') |
flush() | 强制将缓冲区内容写入文件 | 写模式 'w' | f.flush() | |
| 关闭文件 | close() | 关闭文件对象 | 所有模式 | f.close() |
| 自动管理 | with open() as f | 自动打开和关闭文件 | 所有模式 | with open('example.txt', 'r') as f: content = f.read() |
| 追加文件 | open('file', 'a') | 追加内容到文件末尾 | 追加模式 'a' | with open('example.txt', 'a') as f: f.write('New line') |
| 文件编码 | encoding='utf-8' | 指定文件编码 | 所有模式 | f = open('example.txt', 'r', encoding='utf-8') |
| 错误处理 | try...except | 处理文件操作中的异常 | 所有模式 | try: f = open('example.txt', 'r') except FileNotFoundError: print('File not found') |
表格中的“模式”列指的是使用open()函数时可以指定的文件访问模式。每种模式适用于不同的文件操作场景。例如,如果你想要读取一个文件,应该使用读模式'r';如果你想要写入一个文件,并且如果文件已存在则覆盖它,应该使用写模式'w'。追加模式'a'允许你向现有文件的末尾添加内容,而不会删除现有内容。使用with open() as f语法可以确保文件在使用后正确关闭,即使在发生异常时也是如此。
异常
异常基础
- 异常(Exception):程序错误时抛出的对象,通常是
Exception类或其子类的实例。
异常处理结构
try块:包含可能引发异常的代码。except块:捕获并处理特定类型的异常。else块:当try块没有引发异常时执行。finally块:无论是否发生异常,都会执行,常用于资源清理。
异常处理语法
python
try:
# 可能引发异常的代码
except ExceptionType1:
# 处理ExceptionType1异常
except (ExceptionType2, ExceptionType3) as e:
# 同时处理ExceptionType2和ExceptionType3,e是异常实例
else:
# 如果没有异常发生
finally:
# 无论是否发生异常都会执行自定义异常
- 通过继承
Exception类创建自己的异常类型。
抛出异常
- 使用
raise语句手动抛出异常。
异常链
- 使用
raise ... from ...保留原始异常的上下文。
内置异常
- Python定义了许多内置异常,如
ValueError、TypeError、IndexError等。
异常层次结构
BaseException:所有异常的基类。Exception:大多数异常的基类。
异常传递关系
- 异常可以被传递到调用栈的上一层,直到被捕获处理。
- 未被捕获的异常会导致程序终止,并显示错误信息。
示例代码
python
try:
result = 10 / 0
except ZeroDivisionError:
print("不能除以零!")
except Exception as e:
print(f"发生了一个错误:{e}")
else:
print("一切正常!")
finally:
print("这是 finally 块。")模块 包
模块(Module)
定义与作用
- 模块:Python 中的模块是一个包含 Python 代码的文件,通常以
.py为文件扩展名。 - 作用:模块提供了一种组织 Python 代码的方式,允许将相关的函数和类封装在一起,便于重用和维护。
导入模块
导入整个模块
:
pythonimport math print(math.sqrt(16))从模块中导入特定内容
:
pythonfrom math import sqrt print(sqrt(16))导入模块中的所有内容
(不推荐):
pythonfrom math import * print(sqrt(16))为模块或功能设置别名
:
pythonimport math as m print(m.sqrt(16)) from math import sqrt as square_root print(square_root(16))
模块的导入机制
- 当使用
import语句时,Python 解释器会首先在sys.path列表中查找模块文件。 - 如果模块不在
sys.path中,会引发ImportError。
自定义模块
- 创建:创建一个
.py文件,文件名即为模块名。 - 使用:在其他 Python 文件中通过
import语句导入并使用。
__main__ 变量
- 当一个模块被直接运行时,
__name__变量被设置为'__main__'。 - 这允许模块在被直接运行时执行一些代码,而在被导入时不执行这些代码。
包(Package)
什么是包
- 定义:在 Python 中,包是组织模块的一种方式,它是一个包含一个
__init__.py文件的目录,这个文件可以为空,也可以定义包的初始化代码。 - 目的:包允许将相关的模块组织在一起,形成一个更大的结构,便于管理和重用。
包的结构
- 目录:一个包通常是一个包含多个
.py文件的目录,这些文件就是包内的模块。 __init__.py文件:这个文件的存在使得 Python 将目录视为一个包。它可以包含 Python 代码,用于初始化包或者定义包级别的变量。
创建包
- 步骤:
- 创建一个目录。
- 在目录中创建一个
__init__.py文件。 - 在目录中添加所需的
.py文件作为模块。
包的导入
导入包内的模块:
pythonimport package_name.module_name从包中导入特定模块:
pythonfrom package_name import module_name从包中导入所有模块(使用
__all__控制):pythonfrom package_name import *
__init__.py 文件的作用
- 初始化代码:可以包含包初始化时执行的代码。
- 控制可导入内容:通过定义
__all__列表,控制使用from package_name import *时哪些模块或对象被导入。
__all__ 变量
- 定义:在
__init__.py文件中定义,用于指定当使用from package_name import *时应该导入哪些模块或对象。 - 示例:python
__all__ = ['module1', 'module2']
包的安装和使用
- 第三方包:非 Python 官方提供的包,通常通过
pip命令安装。 - 安装第三方包:bash
pip install package_name - 使用国内镜像加速:bash
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple package_name
包的发布
- 准备:确保包内有
setup.py文件,这是一个用于安装、打包和分发包的脚本。 - 发布:通过
python setup.py sdist upload命令将包上传到 PyPI。
包的依赖管理
- 虚拟环境:使用
venv或conda创建虚拟环境,以隔离不同项目的依赖。 - 依赖文件:使用
requirements.txt文件列出项目依赖,便于安装和管理。
包的命名空间
- 作用:包可以有自己的命名空间,这允许在不同包中使用相同的模块名而不会发生冲突。
包的实际应用
- 项目结构:在大型项目中,包可以用来组织不同的功能模块,如 Web 应用的路由、模型、视图等。
- 重用:包可以被多个项目重用,提高了代码的可维护性和可重用性。
通过这些信息,你可以更好地理解 Python 包的概念、如何创建和使用它们,以及如何在项目中有效地组织代码。
可视化
折线图
- 概述
- 目的:通过数据可视化案例,巩固 Python 基础语法,锻炼编程能力。
- 工具:使用
pyecharts模块进行数据可视化。
- 数据来源
- 来源:数据来自百度疫情实时大数据报告和公开的全球各国 GDP 数据。
- 技术栈
- Echarts:由百度开源的数据可视化工具,具有良好交互性和精巧图表设计。 画廊 https://gallery.pyecharts.org/#/README
- Python:适合数据处理的编程语言。
- pyecharts:Echarts 的 Python 版本,用于生成数据可视化图表。
- 安装 pyecharts
- 命令:使用
pip install pyecharts安装。
- JSON 数据格式
- 定义:JSON 是一种轻量级的数据交换格式,本质上是一个特定格式的字符串。
- 用途:作为不同编程语言间数据传递的通用格式。
- 转换:
- Python 数据转 JSON:
json.dumps(data) - JSON 转 Python 数据:
json.loads(data)
- Python 数据转 JSON:
- pyecharts 快速入门
- 模块安装:
pip install pyecharts - 官方示例:访问 pyecharts 官方画廊
- 折线图创建
- 基础配置:使用
Line()类创建折线图,并通过.add_xaxis()和.add_yaxis()方法添加数据。
- 折线图配置项
- 初始化设置:
init_opts=opts.InitOpts(width="1600px", height="800px") - 添加 X 轴数据:
.add_xaxis(列表) - 添加 Y 轴数据:
.add_yaxis(series_name="图例名称", y_axis=[数据列表]) - 点大小:
symbol_size=10 - 标签设置:
label_opts=opts.LabelOpts(is_show=False) - 线条样式:
linestyle_opts=opts.LineStyleOpts(width=2)
- 全局配置选项
- 图标题:
title_opts=opts.TitleOpts(title="标题", pos_left="center") - X 轴配置:
xaxis_opts=opts.AxisOpts(name="时间") - Y 轴配置:
yaxis_opts=opts.AxisOpts(name="累计确诊人数") - 图例配置:
legend_opts=opts.LegendOpts(pos_left='70%')
- 数据处理
- 原始数据清洗:去除不符合 JSON 格式的字符,如
"jsonp_1629350871167_29498("和");" - 数据转换:将清洗后的数据转换为 JSON 格式,然后提取所需数据。
| 函数/方法 | 描述 |
|---|---|
json.dumps(data) | 将 Python 数据对象转换成 JSON 格式的字符串。 |
json.loads(data) | 将 JSON 格式的字符串解析成 Python 数据对象。 |
Line() | pyecharts 模块中用于创建折线图的类。 |
.add_xaxis(列表) | 向折线图中添加 X 轴数据。 |
.add_yaxis(series_name, y_axis) | 向折线图中添加 Y 轴数据,series_name 设置图例名称,y_axis 输入 Y 轴数据。 |
set_global_opts() | 设置全局配置项,如图表标题、图例、X/Y 轴配置等。 |
init_opts=opts.InitOpts(width, height) | 设置图表初始化时的宽度和高度。 |
title_opts=opts.TitleOpts(title, pos_left) | 设置图表标题和标题位置。 |
xaxis_opts=opts.AxisOpts(name) | 配置 X 轴的名称。 |
yaxis_opts=opts.AxisOpts(name) | 配置 Y 轴的名称。 |
legend_opts=opts.LegendOpts(pos_left) | 设置图例的位置。 |
symbol_size | 设置折线图上数据点的大小。 |
label_opts=opts.LabelOpts(is_show) | 设置是否显示数据点的标签。 |
linestyle_opts=opts.LineStyleOpts(width) | 设置折线图线条的宽度和样式。 |
python
import json
from pyecharts.charts import Line
from pyecharts.options import TitleOpts, LabelOpts
f_us = open("./data_sources/美国.txt", "r", encoding="utf-8")
f_jp = open("./data_sources/日本.txt", "r", encoding="utf-8")
f_in = open("./data_sources/印度.txt", "r", encoding="utf-8")
us_dict = json.load(f_us)
jp_dict = json.load(f_jp)
in_data = json.load(f_in)
f_us.close()
f_jp.close()
f_in.close()
# 获取trend key
us_trend_data = us_dict['data'][0]['trend']
jp_trend_data = jp_dict['data'][0]['trend']
in_trend_data = in_data['data'][0]['trend']
us_x_data = us_trend_data['updateDate'][:314]
jp_x_data = jp_trend_data['updateDate'][:314]
in_x_data = in_trend_data['updateDate'][: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()
line.set_global_opts(
# title
title_opts=TitleOpts(title="2020年美日印三国确诊人数折线图", pos_top="center", pos_bottom="1%")
)
line.add_xaxis(us_x_data)
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.render()地图
本案例介绍了如何使用Python的pyecharts库来构建地图可视化图表,特别是针对疫情数据的可视化。
- 基础地图使用
- 疫情地图:包括国内疫情地图和省级疫情地图。
- 核心技能
- 掌握使用pyecharts构建基础的全国地图可视化图表。
- 案例效果
- 展示疫情数据的分布情况,通过颜色深浅表示疫情的严重程度。
- 数据整理
- 获取数据:首先需要获取全国及各省的疫情数据。
- 数据结构:了解数据的整体结构,包括全国和省数据结构。
- 确诊数据:获取每个省份的确诊数据。
- 国内疫情地图
- 创建地图:使用pyecharts创建地图。
- 添加数据:将疫情数据添加到地图中。
- 设置全局配置选项:包括是否为分段型,自定义每一段的范围、文字和样式。
- 省疫情地图
- 效果展示:展示省级疫情地图的效果。
- 数据获取:以河南省为例,获取各市数据。
- 数据汇总:将各市数据汇总到一个列表中。
- 生成地图:参考国内疫情地图生成河南省疫情地图。
- 函数总结
| 函数 | 描述 |
|---|---|
set_global_opts | 设置全局配置选项,如视觉映射器的配置。 |
VisualMapOpts | 视觉映射器选项,用于定义颜色和数据范围的映射。 |
is_piecewise | 定义是否为分段型视觉映射。 |
pieces | 自定义分段的范围、标签和颜色。 |
- 代码示例
python
"""
演示河南省疫情地图开发
"""
import json
from pyecharts.charts import Map
from pyecharts.options import *
# 读取文件
f = open("D:/疫情.txt", "r", encoding="UTF-8")
data = f.read()
# 关闭文件
f.close()
# 获取河南省数据
# json数据转换为python字典
data_dict = json.loads(data)
# 取到河南省数据
cities_data = data_dict["areaTree"][0]["children"][3]["children"]
# 准备数据为元组并放入list
data_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))
# 手动添加济源市的数据
data_list.append(("济源市", 5))
# 构建地图
map = Map()
map.add("河南省疫情分布", data_list, "河南")
# 设置全局选项
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人", "color": "#CCFFFF"},
{"min": 100, "max": 999, "lable": "100~9999人", "color": "#FFFF99"},
{"min": 1000, "max": 4999, "lable": "1000~4999人", "color": "#FF9966"},
{"min": 5000, "max": 9999, "lable": "5000~99999人", "color": "#FF6666"},
{"min": 10000, "max": 99999, "lable": "10000~99999人", "color": "#CC3333"},
{"min": 100000, "lable": "100000+", "color": "#990033"},
]
)
)
# 绘图
map.render("河南省疫情地图.html")动态柱状图
- 案例效果
- 目标:通过pyecharts实现1960~2019年全世界各国GDP变化趋势的动态显示。
- 基础柱状图
- 目标:构建基础柱状图,反转x和y轴,设置数值标签在右侧。
- 时间线配置
- 目标:掌握基础的时间线配置动态图表,设置主题更改颜色样式。
- 需求分析
- GDP数据处理:处理为亿级。
- 时间轴:按年份设置。
- 数据筛选:每年数据只显示前8名国家。
- 标题动态:标题年份动态更改。
- 主题设置:设置为LIGHT。
- 列表的sort方法
- 功能:对列表进行排序,指定排序规则。
python
"""
扩展列表的sort方法
在学习了将函数作为参数传递后,我们可以学习列表的sort方法来对列表进行自定义排序
"""
# 准备列表
my_list = [["a", 33], ["b", 55], ["c", 11]]
# 排序,基于带名函数
# def choose_sort_key(element):
# return element[1]
#
# my_list.sort(key=choose_sort_key, reverse=True)
# 排序,基于lambda匿名函数
my_list.sort(key=lambda element: element[1], reverse=True)
print(my_list)- 数据处理
- 读取数据:删除第一条数据。
- 数据转换:转换为字典格式,方便处理。
- 准备时间线
- 功能:准备时间线以支持动态图表。
- 自动播放和绘图
- 功能:设置自动播放,绘制最终图表。
相关函数表格
| 函数/方法 | 描述 | 用途 |
|---|---|---|
Bar() | 构建柱状图对象 | 用于创建基础柱状图 |
add_xaxis() | 添加x轴数据 | 配置柱状图的x轴数据 |
add_yaxis() | 添加y轴数据 | 配置柱状图的y轴数据 |
reversal_axis() | 反转x和y轴 | 用于调整图表的显示方向 |
LabelOpts(position="right") | 设置标签位置 | 将数值标签显示在柱状图的右侧 |
Timeline() | 创建时间线对象 | 用于创建动态图表的时间线 |
sort(key=函数, reverse=True/False) | 列表排序 | 对列表进行排序,指定排序规则 |
ThemeType.LIGHT | 设置主题 | 将图表主题设置为LIGHT |
这些函数和方法是实现动态柱状图的关键,通过这些方法可以有效地构建和配置图表,实现数据的动态可视化。
python
"""
演示第三个图表:GDP动态柱状图开发
"""
from pyecharts.charts import Bar, Timeline
from pyecharts.options import *
from pyecharts.globals import ThemeType
# 读取数据
f = open("D:/1960-2019全球GDP数据.csv", "r", encoding="GB2312")
data_lines = f.readlines()
# 关闭文件
f.close()
# 删除第一条数据
data_lines.pop(0)
# 将数据转换为字典存储,格式为:
# { 年份: [ [国家, gdp], [国家,gdp], ...... ], 年份: [ [国家, gdp], [国家,gdp], ...... ], ...... }
# { 1960: [ [美国, 123], [中国,321], ...... ], 1961: [ [美国, 123], [中国,321], ...... ], ...... }
# 先定义一个字典对象
data_dict = {}
for line in data_lines:
year = int(line.split(",")[0]) # 年份
country = line.split(",")[1] # 国家
gdp = float(line.split(",")[2]) # gdp数据
# 如何判断字典里面有没有指定的key呢?
try:
data_dict[year].append([country, gdp])
except KeyError:
data_dict[year] = []
data_dict[year].append([country, gdp])
# print(data_dict[1960])
# 创建时间线对象
timeline = Timeline({"theme": ThemeType.LIGHT})
# 排序年份
sorted_year_list = sorted(data_dict.keys())
for year in sorted_year_list:
data_dict[year].sort(key=lambda element: element[1], reverse=True)
# 取出本年份前8名的国家
year_data = data_dict[year][0:8]
x_data = []
y_data = []
for country_gdp in year_data:
x_data.append(country_gdp[0]) # x轴添加国家
y_data.append(country_gdp[1] / 100000000) # y轴添加gdp数据
# 构建柱状图
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}年全球前8GDP数据")
)
timeline.add(bar, str(year))
# for循环每一年的数据,基于每一年的数据,创建每一年的bar对象
# 在for中,将每一年的bar对象添加到时间线中
# 设置时间线自动播放
timeline.add_schema(
play_interval=1000,
is_timeline_show=True,
is_auto_play=True,
is_loop_play=False
)
# 绘图
timeline.render("1960-2019全球GDP前8国家.html")面向对象
重要概念
- 封装:隐藏对象的内部状态和复杂性,仅暴露有限的接口。
- 继承:允许新创建的类从现有的类中获取属性和方法。
- 多态:不同对象可以共用一个接口,但各自的实现可以不同。
类和对象
类的定义
python
class Person:
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = addressclass关键字定义类。__init__是类的构造方法,用于初始化对象。
创建和使用对象
python
# 创建对象
person1 = Person("Alice", 30, "123 Wonderland")
# 使用对象的属性和方法
print(f"Name: {person1.name}, Age: {person1.age}, Address: {person1.address}")封装
- 使用私有变量(以双下划线开头)隐藏类的内部状态。python
class Person: def __init__(self, name, age, __address): self.name = name self.age = age self.__address = __address
继承
单继承
python
class Employee(Person):
def __init__(self, name, age, address, job_title):
super().__init__(name, age, address)
self.job_title = job_titlesuper()用于调用父类的构造方法。
多继承
python
class Engineer(Employee, Person):
def __init__(self, name, age, address, job_title, skills):
super().__init__(name, age, address, job_title)
self.skills = skills多态
多态的使用
python
class Animal:
def speak(self):
pass
class Dog(Animal):
def speak(self):
print("Woof!")
class Cat(Animal):
def speak(self):
print("Meow!")
def animal_sound(animal):
animal.speak()
# 多态性示例
dog = Dog()
cat = Cat()
animal_sound(dog) # Woof!
animal_sound(cat) # Meow!pass关键字
pass 是 Python 中的一个关键字,它在语法上用作占位符,表示“什么都不做”。它的主要作用是作为最小化的、空的语句,使得 Python 程序在语法上正确,但在逻辑上什么都不执行。
使用场景
- 作为占位符:当你编写了一个函数或类,但暂时还不想实现它的内容时,可以使用
pass作为占位符。 - 满足语法要求:在某些情况下,Python 语法要求必须有语句,即使没有实际的操作,这时候也需要使用
pass。
示例
空的类定义
python
class EmptyClass:
pass上面的代码定义了一个空的类,其中不包含任何属性和方法,pass 表示这个类不执行任何操作。
空的方法定义
python
class MyClass:
def do_nothing(self):
pass在这个例子中,do_nothing 方法是一个空方法,调用它不会有任何效果。
在条件语句中使用
python
if some_condition:
pass
else:
print("This will be printed.")如果 some_condition 为真,程序将执行 pass,即什么都不做。如果为假,则执行 else 块中的代码。
抽象类和抽象方法
在面向对象编程中,pass 常用于定义抽象类和抽象方法。抽象方法是一种没有具体实现的方法,通常用于定义接口或规范,要求子类必须实现这些方法。
python
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def make_sound(self):
pass
class Dog(Animal):
def make_sound(self):
print("Woof!")
# 尝试创建抽象类的实例将会引发错误
# animal = Animal()在这个例子中,Animal 是一个抽象类,它有一个抽象方法 make_sound,这个方法通过 pass 表示没有具体实现。任何继承自 Animal 的子类都必须实现 make_sound 方法,否则将不能实例化。
pass 是 Python 中一个简单但非常有用的关键字,它允许程序员在代码中预留位置,以便将来添加功能,或者在满足语法要求的同时不执行任何操作。在设计抽象类和方法时,pass 也扮演着重要的角色。
类内置方法和魔术方法
魔术方法
__init__:构造方法。__str__:定义对象的字符串表示。__lt__、__le__、__eq__:比较运算符方法。
示例
python
class Student:
def __init__(self, name, grade):
self.name = name
self.grade = grade
def __str__(self):
return f"Student Name: {self.name}, Grade: {self.grade}"
def __lt__(self, other):
return self.grade < other.grade
# 使用魔术方法
student1 = Student("Alice", 90)
student2 = Student("Bob", 85)
print(student1) # Student Name: Alice, Grade: 90
print(student1 < student2) # True类型注解
类型注解的使用
- Python 3.5+ 引入类型注解,用于提高代码可读性和IDE支持。
- 基本语法:
变量名: 类型
示例
python
def greet(name: str) -> str:
return f"Hello, {name}"
var: int = 10数据组织
对象的数据组织
- 使用对象代替简单变量,可以组织更加复杂的数据结构。
示例
python
class School:
def __init__(self):
self.students = []
def add_student(self, student: Student):
self.students.append(student)
def display_students(self):
for student in self.students:
print(student)
school = School()
school.add_student(Student("Alice", 90))
school.add_student(Student("Bob", 85))
school.display_students()综合案例:数据分析
示例代码
python
class FileReader:
def read_data(self, file_path):
with open(file_path, 'r') as file:
return file.readlines()
class DataAnalyzer:
def __init__(self, data):
self.data = data
def calculate_daily_sales(self):
# 计算每日销售额的逻辑
pass
def generate_chart(self):
# 使用pyecharts生成柱状图
pass
# 使用示例
file_reader = FileReader()
data = file_reader.read_data("sales_data.txt")
analyzer = DataAnalyzer(data)
analyzer.calculate_daily_sales()
analyzer.generate_chart()总结
- 面向对象提供了一种组织代码的强大方式,能够提高代码的可维护性和可扩展性。
- 类型注解和魔术方法是Python中增强代码表达能力的工具。
- 面向对象的核心在于将数据和行为封装在对象中,并通过继承和多态提高代码的复用性。
mermaid
graph TD
APython & MySQL
概述
- pymysql:Python中用于操作MySQL的第三方库。
- 安装:
pip install pymysql
连接配置
创建到MySQL的数据库连接
- 导入库:
from pymysql import Connection - 创建连接:python
conn = Connection(host='localhost', port=3306, user='root', password='yourpassword', db='yourdatabase')
执行SQL语句
非查询性质的SQL语句
- 执行语句:
cursor.execute(sql) - 提交更改:
conn.commit() - 关闭连接:
conn.close()
查询性质的SQL语句
- 获取游标对象:
cursor = conn.cursor() - 执行查询:
cursor.execute(sql) - 获取结果:
results = cursor.fetchall() - 关闭游标:
cursor.close()
示例代码
插入数据
python
import pymysql
# 创建数据库连接
conn = pymysql.Connection(host='localhost', port=3306, user='root', password='yourpassword', db='yourdatabase', charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor)
try:
with conn.cursor() as cursor:
# SQL 插入语句
sql = "INSERT INTO tablename (column1, column2) VALUES (%s, %s)"
cursor.execute(sql, ('value1', 'value2'))
# 提交到数据库执行
conn.commit()
finally:
conn.close()查询数据
python
import pymysql
# 创建数据库连接
conn = pymysql.Connection(host='localhost', port=3306, user='root', password='yourpassword', db='yourdatabase', charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor)
try:
with conn.cursor() as cursor:
# SQL 查询语句
sql = "SELECT * FROM tablename"
cursor.execute(sql)
results = cursor.fetchall()
for row in results:
print(row)
finally:
conn.close()自动提交
- 设置自动提交:
autocommit=True在创建连接时
示例:自动提交
python
import pymysql
# 创建数据库连接(自动提交)
conn = pymysql.Connection(host='localhost', port=3306, user='root', password='yourpassword', db='yourdatabase', autocommit=True, charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor)
try:
with conn.cursor() as cursor:
# SQL 插入语句
sql = "INSERT INTO tablename (column1, column2) VALUES (%s, %s)"
cursor.execute(sql, ('value1', 'value2'))
finally:
conn.close()PySpark
- PySpark简介
- 定义: Apache Spark是一个用于大规模数据处理的统一分析引擎,而PySpark是Spark的Python API。
- 特点: 支持分布式计算,能够处理TB甚至PB级别的数据。
- 应用场景: 大数据开发、人工智能。
- 安装PySpark
bash
pip install pyspark
# 或者使用国内源
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pysparkPySpark编程模型
数据输入: 通过
SparkContext读取数据,生成RDD。数据处理: 使用RDD的各种transformation和action操作进行数据处理。
数据输出: 将处理结果输出到文件、数据库等。
spark对象获取
python
# 导包
from pyspark import SparkConf, SparkContext
# 创建SparkConf类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
# 基于SparkConf类对象创建SparkContext对象
sc = SparkContext(conf=conf)
# 打印PySpark的运行版本
print(sc.version)
# 停止SparkContext对象的运行(停止PySpark程序)
sc.stop()- SparkContext与RDD
- SparkContext: 作为与Spark集群交互的主要入口,管理任务调度。
- RDD (Resilient Distributed Dataset): 基本的数据结构,支持并行操作。
PySpark算子函数
以下是PySpark中常用的算子函数的总结:
| 算子 | 描述 | 示例代码 |
|---|---|---|
map(func) | 对RDD中的每个元素应用func函数,返回一个新的RDD。 | rdd.map(lambda x: x * 2) |
flatMap(func) | 类似map,但每个输入元素可以映射到0或多个输出元素(因此可以"展平")。 | rdd.flatMap(lambda x: [x, x*2]) |
filter(func) | 返回一个新的RDD,其中包含满足func条件的所有元素。 | rdd.filter(lambda x: x > 10) |
reduceByKey(func) | 对RDD中的元素进行归约操作,通常用于键值对RDD。 | rdd.reduceByKey(lambda a, b: a + b) |
groupByKey() | 将具有相同键的值分组在一起。 | rdd.groupByKey() |
sortBy(func) | 根据func函数返回的值对RDD元素进行排序。 | rdd.sortBy(lambda x: x[1], ascending=False) |
distinct() | 返回一个新的RDD,其中所有元素都是唯一的。 | rdd.distinct() |
union(other) | 返回一个包含所有原始RDD和other RDD元素的新RDD。 | rdd.union(other_rdd) |
- 数据输入与输出
数据输入
从Python容器转换:
pythonsc = SparkContext() rdd = sc.parallelize([1, 2, 3, 4, 5])从文件读取:
pythonrdd = sc.textFile("path/to/file.txt")
数据输出
- 输出到文件:python
rdd.saveAsTextFile("path/to/output") - 转换为Python列表:python
result = rdd.collect()
- 综合案例:WordCount
python
from pyspark import SparkContext
sc = SparkContext()
# 读取文件
text_rdd = sc.textFile("path/to/file.txt")
# 切分单词
words = text_rdd.flatMap(lambda line: line.split())
# 计数
word_counts = words.map(lambda word: (word, 1)).reduceByKey(lambda a, b: a + b)
# 收集结果
print(word_counts.collect())- 分布式集群运行
提交命令:
bashbin/spark-submit --master yarn --num-executors 3 --queue root.teach --executor-cores 4 --executor-memory 4g /home/hadoop/demo.py
闭包
- 闭包的定义
闭包是在函数嵌套的情况下,内部函数引用了外部函数的变量,并且外部函数返回了内部函数,这样内部函数就被称为闭包。
- 闭包的作用
- 数据封装:闭包允许我们封装数据和相关操作,使得数据在函数外部不可见。
- 数据持久化:闭包可以持续访问外部函数的变量,即使外部函数已经执行完毕。
- 闭包的实现
- 简单闭包:返回内部函数,该内部函数引用了外部函数的变量。
- 修改外部变量:使用
nonlocal关键字,允许内部函数修改外部函数的局部变量。
- 闭包的优点
- 避免全局变量:通过闭包可以避免使用全局变量,使得代码更加模块化。
- 保护变量:闭包中的变量不直接暴露在外部,避免了被错误地修改。
- 闭包的缺点
- 内存占用:由于闭包持续引用外部变量,可能会增加内存的占用。
- 闭包的代码示例
python
def create_atm():
account_amount = 0 # 外部变量
def withdraw(amount):
nonlocal account_amount # 使用nonlocal声明
account_amount -= amount
return account_amount
def deposit(amount):
nonlocal account_amount
account_amount += amount
return account_amount
return withdraw, deposit
# 使用闭包
withdraw, deposit = create_atm()
print(withdraw(100)) # 取钱
print(deposit(200)) # 存钱- 注意事项
- 内存管理:注意闭包引用的变量可能会导致内存泄漏,尤其是当闭包作为回调函数时。
- 作用域链:理解闭包如何通过作用域链访问外部变量是非常重要的。
优点
- 数据封装:闭包提供了一种数据封装的手段,使得函数的状态(即变量)可以被保持。
- 模块化:闭包使得代码更加模块化,通过函数封装实现细节,外部只能通过闭包提供的接口与之交互。
- 避免全局变量:闭包提供了一种避免使用全局变量的方法,有助于减少全局命名空间的污染。
- 灵活性:闭包允许创建可以接受参数并返回新函数的函数,这增加了代码的灵活性。
缺点
- 内存消耗:由于闭包持续引用外部函数的局部变量,这可能会导致额外的内存消耗,因为这些变量不能被垃圾回收。
- 复杂性:过度使用闭包可能会使得代码难以理解和维护,尤其是对于初学者来说,闭包的概念可能比较抽象。
- 调试难度:闭包可能会使得调试变得更加困难,因为变量的作用域和生命周期与传统的函数调用模型不同。
装饰器
什么是装饰器
装饰器是 Python 中一个非常强大的功能,本质上是一种闭包,它允许用户在不修改原有函数代码的情况下,给函数增加新的功能。
装饰器的作用
- 增强函数的功能,如:日志记录、性能测试、事务处理、缓存、权限校验等。
- 装饰器可以带参数,使得装饰器更加灵活。
装饰器的基本写法
- 定义一个闭包函数,在这个闭包函数内部调用目标函数。
- 在闭包函数内部,执行目标函数之前和之后添加额外的代码,以实现额外的功能。
装饰器的语法糖
使用 @ 符号,将装饰器应用到目标函数上,简化了装饰器的使用。
装饰器的写法示例
python
def my_decorator(func):
def wrapper(*args, **kwargs):
print("Something before the function is executed")
result = func(*args, **kwargs)
print("Something after the function is executed")
return result
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()带参数的装饰器
装饰器本身也可以接收参数,使得装饰器更加通用和灵活。
装饰器带参数的写法
python
def repeat(num_times):
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
value = func(*args, **kwargs)
return value
return wrapper
return decorator_repeat
@repeat(num_times=3)
def greet(name):
print(f"Hello {name}")
greet("World")装饰器的应用场景
- 缓存:通过装饰器实现函数结果的缓存,避免重复计算。
- 日志:通过装饰器记录函数的调用信息,如时间、参数等。
- 权限控制:通过装饰器实现函数的访问权限控制。
- 事务处理:在数据库操作中,通过装饰器实现事务的提交和回滚。
注意事项
- 装饰器会改变原函数的一些属性,如
__name__、__doc__等,可以通过functools.wraps来保留这些属性。 - 装饰器可能会使代码的阅读和调试变得复杂,应谨慎使用。
通过学习装饰器,我们可以更加灵活和高效地扩展函数的功能,是 Python 编程中不可或缺的一部分。
设计模式
- 什么是设计模式
设计模式是一套被反复使用的、多数人知晓的、经过分类编目的代码设计经验的总结。它描述了软件设计过程中的通用问题以及解决这些问题的方案。
- 常见的设计模式
单例模式(Singleton Pattern)
- 定义:确保一个类只有一个实例,并提供一个全局访问点。
- 适用场景:当一个类只能有一个实例,且客户可以从一个众所周知的访问点访问它时。
- 特点:
- 节省内存。
- 节省创建对象的开销。
- 实现方式:
- 私有化构造函数。
- 提供一个静态方法来获取唯一的实例。
单例模式示例
python
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super(Singleton, cls).__new__(cls)
return cls._instance
# 使用
singleton1 = Singleton()
singleton2 = Singleton()
print(singleton1 is singleton2) # 输出 True工厂模式(Factory Pattern)
- 定义:定义一个创建对象的接口,让子类决定实例化哪一个类。工厂模式使一个类的实例化延迟到其子类。
- 适用场景:当需要大量创建一个类的实例时。
- 特点:
- 易于代码维护。
- 符合现实世界的模式。
- 实现方式:
- 工厂类负责创建对象。
- 通过工厂方法来创建具体类的对象。
工厂模式示例
python
class Person:
def __init__(self, name):
self.name = name
class Factory:
@staticmethod
def get_person(name):
return Person(name)
# 使用
person1 = Factory.get_person("Alice")
print(person1.name) # 输出 Alice- 设计模式的好处
- 提高代码的可重用性:设计模式提供了经过验证的解决方案,可以被重复应用到相似的问题上。
- 提高代码的可维护性:设计模式提供了清晰的结构,使得代码更易于理解和修改。
- 促进协作:设计模式是通用的,团队成员可以更容易地理解彼此的代码。
设计模式的注意事项
- 不要过度使用:设计模式应该在合适的场景下使用,过度使用可能会使系统变得复杂。
- 理解模式的本质:在使用设计模式之前,应该深入理解其背后的原理和适用场景。
设计模式是软件工程中的重要概念,它们提供了解决常见问题的通用方法。理解和掌握设计模式,可以提高编程的效率和质量。
多线程
- 什么是多线程
多线程是指在单个程序中可以同时运行多个线程执行不同的任务。线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。
- 进程与线程的区别
- 进程:操作系统进行资源分配和调度的基本单位。进程之间是内存隔离的,每个进程拥有独立的内存空间。
- 线程:是进程内部的一个实体,是被系统独立调度和分派的基本单位。线程自身基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如执行栈),但它可以与同属一个进程的其他线程共享进程所拥有的全部资源。
- 并行执行
- 多任务并行执行:操作系统可以同时运行多个进程,这些进程都在并行执行。
- 多线程并行执行:一个进程内的多个线程可以同时运行,实现在同一个进程内部的并行处理。
- Python多线程编程
Python的多线程可以通过threading模块来实现。threading模块提供了更多易用的高级API,用于多线程编程。
4.1 threading模块的使用
创建线程对象:
pythonimport threading thread_obj = threading.Thread(target=func)其中
func是线程要执行的函数。启动线程:
pythonthread_obj.start()
4.2 线程传参
- 通过
args传参:使用元组的形式,按照参数顺序传给线程函数。 - 通过
kwargs传参:使用字典的形式,传给线程函数。
4.3 线程同步
在多线程编程中,线程同步是一个重要的问题,需要防止多个线程同时访问共享资源造成数据错乱。可以使用锁(Lock)等机制来实现线程同步。
- 多线程编程实例
5.1 创建并启动线程
python
import threading
def print_numbers():
for i in range(1, 6):
print(i)
# 创建线程
thread1 = threading.Thread(target=print_numbers)
# 启动线程
thread1.start()5.2 传参给线程
python
def print_numbers_with_args(a, b):
print(f"Argument a: {a}, Argument b: {b}")
# 创建线程并传参
thread2 = threading.Thread(target=print_numbers_with_args, args=(10, 20))
# 启动线程
thread2.start()- python
""" 演示多线程编程的使用 """ import time import threading def sing(msg): print(msg) time.sleep(1) def dance(msg): print(msg) time.sleep(1) if __name__ == '__main__': # 创建一个唱歌的线程 sing_thread = threading.Thread(target=sing, args=("我要唱歌 哈哈哈", )) # 创建一个跳舞的线程 dance_thread = threading.Thread(target=dance, kwargs={"msg": "我在跳舞哦 啦啦啦"}) # 让线程去干活吧 sing_thread.start() dance_thread.start() 注意事项
- 全局解释器锁(GIL):由于Python的GIL问题,CPython解释器下的多线程可能不会带来计算密集型任务的性能提升。GIL确保同一时间只有一个线程执行Python字节码,因此多线程主要用于I/O密集型任务。
- 线程安全:当多个线程访问共享数据时,需要确保线程安全,避免数据竞争和不一致性。
- 多线程与多进程
- 多线程:适用于I/O密集型任务,资源消耗小,但受GIL影响,不适合计算密集型任务。
- 多进程:适用于计算密集型任务,不受GIL影响,但资源消耗大,进程间通信复杂。
- 结论
多线程编程是提高程序性能和响应能力的有效手段,特别是在I/O密集型任务中。通过threading模块,Python提供了丰富的接口来支持多线程编程。然而,开发者需要注意线程安全和GIL的影响,合理选择多线程和多进程的策略。
网络编程Socket
- 什么是Socket
Socket,简称“套接字”,是进程间通信的端点,可以看作是各个运行在不同主机上的进程之间进行双向通信的通道。Socket是网络编程的核心,负责进程间的网络数据传输。
- Socket的基本操作
服务端
- 创建Socket对象:首先需要创建一个Socket实例。
- 绑定地址:将Socket与特定的IP地址和端口号绑定。
- 监听连接:使Socket进入监听状态,等待客户端的连接请求。
- 接受连接:接受客户端的连接请求,建立连接。
- 接收和发送数据:通过Socket接收客户端发送的数据,或向客户端发送数据。
- 关闭连接:完成数据传输后,关闭Socket连接。
客户端
- 创建Socket对象:与服务端类似,首先创建一个Socket实例。
- 连接服务端:通过指定服务端的IP地址和端口号,发起连接请求。
- 发送和接收数据:连接成功后,可以向服务端发送数据,或接收服务端发送的数据。
- 关闭连接:数据传输完成后,关闭Socket连接。
- Socket编程示例
服务端示例
python
"""
演示Socket服务端开发
"""
import socket
# 创建Socket对象
socket_server = socket.socket()
# 绑定ip地址和端口
socket_server.bind(("localhost", 8888))
# 监听端口
socket_server.listen(1)
# listen方法内接受一个整数传参数,表示接受的链接数量
# 等待客户端链接
# result: tuple = socket_server.accept()
# conn = result[0] # 客户端和服务端的链接对象
# address = result[1] # 客户端的地址信息
conn, address = socket_server.accept()
# accept方法返回的是二元元组(链接对象, 客户端地址信息)
# 可以通过 变量1, 变量2 = socket_server.accept()的形式,直接接受二元元组内的两个元素
# accept()方法,是阻塞的方法,等待客户端的链接,如果没有链接,就卡在这一行不向下执行了
print(f"接收到了客户端的链接,客户端的信息是:{address}")
while True:
# 接受客户端信息,要使用客户端和服务端的本次链接对象,而非socket_server对象
data: str = conn.recv(1024).decode("UTF-8")
# recv接受的参数是缓冲区大小,一般给1024即可
# recv方法的返回值是一个字节数组也就是bytes对象,不是字符串,可以通过decode方法通过UTF-8编码,将字节数组转换为字符串对象
print(f"客户端发来的消息是:{data}")
# 发送回复消息
msg = input("请输入你要和客户端回复的消息:")
if msg == 'exit':
break
conn.send(msg.encode("UTF-8"))
# 关闭链接
conn.close()
socket_server.close()客户端示例
python
"""
演示Socket客户端开发
"""
import socket
# 创建socket对象
socket_client = socket.socket()
# 连接到服务端
socket_client.connect(("localhost", 8888))
while True:
# 发送消息
msg = input("请输入要给服务端发送的消息:")
if msg == 'exit':
break
socket_client.send(msg.encode("UTF-8"))
# 接收返回消息
recv_data = socket_client.recv(1024) # 1024是缓冲区的大小,一般1024即可。 同样recv方法是阻塞的
print(f"服务端回复的消息是:{recv_data.decode('UTF-8')}")
# 关闭链接
socket_client.close()- 注意事项
- 异常处理:网络编程中,需要对可能发生的异常进行处理,如连接失败、数据传输错误等。
- 资源清理:确保在数据传输完成后,及时关闭Socket连接,释放资源。
- 安全性:在网络通信中,要注意数据的安全性,如使用加密传输、验证通信双方的身份等。
- 测试工具
可以使用网络调试助手等工具模拟客户端与服务端进行通信,以测试Socket程序的正确性。
正则表达式
正则表达式(Regular Expression)是一种文本模式,包括普通字符(例如,字母a到z)和特殊字符(称为"元字符")。它用于检索、替换符合某个模式(规则)的文本。
- 文本搜索:在大量文本中搜索符合某个模式的字符串。
- 文本替换:在文本中替换符合某个模式的字符串。
- 验证输入:验证用户的输入是否符合特定格式(如邮箱、电话号码等)。
在Python中,正则表达式通过re模块实现。
3.1 基础方法
re.match():从字符串的起始位置匹配模式,如果匹配成功,返回一个匹配对象;否则返回None。re.search():扫描整个字符串并返回第一个成功的匹配。re.findall():找出字符串中所有匹配的子串,并返回一个列表。
3.2 高级方法
re.sub():替换文本中符合某个模式的字符串。re.compile():编译正则表达式,返回正则表达式对象,供后续使用。
匹配规则
单字符匹配
| 字符 | 功能 |
|---|---|
. | 匹配任意1个字符(除了\n),\.匹配点本身 |
[] | 匹配[]中列举的字符 |
\d | 匹配数字,即θ-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 | 匹配非单词边界 |
分组匹配
| 字符 | 功能 |
|---|---|
| ` | ` |
() | 将括号中字符作为一个分组 |
- 字符串的原始标记
在Python字符串前加上r或R,表示原始字符串,忽略字符串中的转义字符。
例如:
python
pattern = re.compile(r"\d+")- 正则表达式案例
6.1 匹配账号
账号由字母和数字组成,长度限制6到10位:
python
import re
pattern = re.compile(r"^[0-9a-zA-Z]{6,10}$")
result = pattern.match("user123")
print(result) # None or <re.Match object>6.2 匹配QQ号
QQ号要求纯数字,长度5-11,第一位不为0:
python
pattern = re.compile(r"^[1-9][0-9]{4,10}$")
result = pattern.match("10000")
print(result) # None or <re.Match object>6.3 匹配邮箱地址
只允许qq、163、gmail这三种邮箱地址:
python
pattern = re.compile(r"^[\w-]+(\.[\w-]+)*@(qq|163|gmail)(\.[\w-]+)+$")
result = pattern.match("user@gmail.com")
print(result) # None or <re.Match object>- 注意事项
- 性能问题:复杂的正则表达式可能会降低程序性能。
- 可读性:过于复杂的正则表达式可能会降低代码的可读性。
- 特殊字符:在正则表达式中,某些字符具有特殊含义,如
.、*等,需要使用\进行转义。
- 结论
正则表达式是一种强大的文本处理工具,通过掌握其基本语法和元字符规则,可以有效地进行文本搜索、替换和验证等操作。在实际应用中,合理使用正则表达式能够提高开发效率和处理文本数据的能力。