Python
Python
计算机组成
- 数据:存储器(RAM、Cache);
- 计算:运算器ALU(算术运算、逻辑运算)

Python概述
版本
Python 2 与 Python3
查看Python版本
1 | PS C:\Users\Qingyuan_Qu> python -V |
开发环境
- 官方Python IDEL
- Anaconda3
- VS Code
- PyCharm
- … …
编程规范
- 代码缩进:分支、循环、函数、类定义、异常处理、With语句等。注意代码块和函数体的缩进,一般以4个空格为一个缩进单位,或直接一个
Tab制表符; - 导入模块顺序:标准库、扩展库、自定义库;避免导入整个库,最好用到啥导啥;
- 不要写过长语句;
扩展库安装卸载
| 命令 | 说明 | 举例 |
|---|---|---|
| pip list | ||
| pip install package[==version] | ||
| pip uninstall packagename[==version] |
安装Jupyter Notebook
1 | pip install jupyter notebook |
启动Jupyter Notebook
1 | jupyter notebook --no-browser --ip=192.168.179.100 --port 9999 |
帮助信息
内置函数help()可以查看属性、方法、类、模块等的帮助信息。
相关术语
关键字
1 | import keyword |

变量
编程的本质,就是对内存中数据的访问和修改。程序所用的数据都会保存到内存中,程序员需要一种机制来访问或修改内存中的数据。
这种机制就是变量,每个变量都代表了某一小块内存,而且变量是有名字的,程序对变量赋值,实际上就是把数据装入到该变量所代表的内存区的过程;
程序读取变量的值,实际上就是从该变量所代表的内存区取值的过程。形象地理解:变量相当于一个有名称的容器,该容器用于装各种不同类型的数据。
摘录自《疯狂Java讲义·第五版》
变量命名规范
变量名称区分大小写。
变量名称首字母不能是数字
变量名称可以由字母、数字和下划线组成
变量名称不能使用Python内置的关键字
数据类型
数值类型
| 数值类型 | 描述 | 示例 |
|---|---|---|
| int | 整数 | 8、10、100 |
| float | 浮点数 | 1.0、2.1、1e-3 |
| complex | 复数 | 1+2j、1.23j、1.1+1j |
| bool | 布尔型 | True、False |
Python语言中,任何非零的数值、非空的数据类型,非空的字符串和非空列表,都等价于True,(但除1以外都不等于True)
1 | 2 == True |
0或空类型、””(空字符串)、[]空表都等价于False,可以直接用作判断条件,(但除0以外都不等于False)。
1 | if []: |
字符串
| 使用方式 | 示例 | 备注 | |
|---|---|---|---|
| 单引号 | ‘ ‘ | hi = ‘hello world’ | 可使用 [\]续行输入 |
| 双引号 | “ “ | hi = “hello world” | 可使用 [\]续行输入 |
| 多行字符串 | 以 [‘’’] [“””]开头结尾 |
NoneType
无、空。
类型取值: None
1 | a = [] |
1 | def fun(): |
运算符
| 运算符分类 | 示例 | |
|---|---|---|
| 赋值运算符 | =, +=, -=, *=, /=, %=, //= | a=10 |
| 算术运算符 | +, -, *, /, %, //, ** | 5/3=1.666, 5//3=1, 5%3=2 |
| 比较运算符 | <, >, <=, >=, ==, != | 3<=4 |
| 逻辑运算符 | and, or, not | T and F => False , T or F => T |
| 成员运算符 | in, not in | “he” in ‘hello’ => True |
| 身份运算符 | is, is not | a = 1 ,b = 1, a is b => True |
| 位运算符 | &, |, ^, ~, <<, >> |
1 | a = 00111000 = 56 => ~a = -(00111000+1) = -57 |
is 与 ==
情况一
1 | a = 3 |
is 与 ==
情况二
1 | a = ["a"] |
id(): Return the identity of an object. (CPython uses the object’s memory address.)CPython 是用 C 语言实现的 Python 解释器,也是官方的并且是最广泛使用的Python解释器。
内置函数
函数是组织好的、实现单一功能或相关联功能的代码段。我们可以将函数视为一段有名字的代码,这类代码可以在需要的地方以函数名()的形式调用。
内置函数概念
内置函数(built in function)不需要额外导入任何模块即可直接使用,具有非常快的运算速度,推荐优先使用。使用下面的语句可以查看所有的内置函数和内置对象。
1 | dir(__builtins__) |
Help on built-in module builtins:
NAME
builtins - Built-in functions, types, exceptions, and other objects.
DESCRIPTION
This module provides direct access to all ‘built-in’ identifiers of Python; for example, builtins.len is
the full name for the built-in function len().
This module is not normally accessed explicitly(显式) by most applications, but can be useful in modules that provide objects with the same name as a built-in value, but in which the built-in of that name is also needed.
该模块提供对Python所有“内置”标识符的直接访问;例如,builtins.len是内置函数len()的全名。
该模块通常不会被大多数应用程序显式访问,但在提供与内置值同名的对象的模块中可能很有用,但在这些模块中也需要该名称的内置值。
1 | import builtins |
1 | def len(): |
常见的内置函数
| 功能 | 函数名 | 示例 |
|---|---|---|
| 输入 | input() | |
| 输出 | print() |
| 功能 | 函数名 | 示例 |
|---|---|---|
| 绝对值 | abs(x) | abs(-5) = 5 |
| 四舍五入 | round(a[,b]) | round(5.55,1) = 5.5 |
| 幂运算 | pow(a,b) | a的b次幂 |
| 商和余数 | divmod(a,b) | divmod(5,2) = (2,1) |
| 功能 | 函数名 | 示例 |
|---|---|---|
| 最大值 | max() | max([1,3,4,5]) = 5 |
| 最小值 | min() | min([1,3,4,5]) = 1 |
| 求和 | sum() | sum([1,2,3]) = 6 |
| 功能 | 函数名 | 示例 |
|---|---|---|
| 映射 | map(func, *iterables) | map(lambda x:x**2, [1,2,3]) |
| 过滤 | filter(function or None, iterable) | filter(lambda x:x%2==0, [1,2,3,4]) |
| 功能 | 函数名 | 示例 |
|---|---|---|
| 元素个数 | len(items) | len(“study bigdata”) => 13 |
| 类型判断 | type() | a = “hello”; type(a) => <class ‘str’> |
| 帮助信息(模块、类、方法) | help() | |
| 等差数列 | range(stop) | range(5) => 0,1,2,3,4 |
| range(start, stop[, step]) | range(1,10,2) => 1,3,5,7,9 |
map
1 | def add(x, y): |
字符串相关方法
字符串索引查询
单值索引
1 | domain = "studybigdata.cn" |
范围索引
1 | domain[5:8] |
修改
不支持! 因为是不可变类型,所以不可对元素重新赋值。
1 | domain[1] = "S" |
常用方法
s = “ hello World “
s1 = “hello”
s2 = “123456”
| 大小写 | |
| 大写 | s.upper() |
| 小写 | s.lower() |
| 首字母大写 | s.capitalize() |
| 每个单词大写 | s.title() |
| 大小写互换 | s.swapcase() |
| 对齐方式 | |
| 居中对齐 | s.center(20,”-“) |
| 左对齐 | s.ljust(20,”-“) |
| 右对齐 | s.rjust(20,”-“) |
| 去除字符 | |
| 去除头部空格 | s.lstrip() |
| 去除头部空格 | s.rstrip() |
| 去除首尾空格 | s.strip() |
| 去除前缀 | s.removeprefix(“he”) |
| 去除后缀 | s.removesuffix(“ld”) |
| 查找替换 | |
| 某字符的索引 | s.index(“abc”) 查找到,返回索引;查找不到,抛出异常 |
| 某字符的索引 | s.find(“abc”) 查找到,返回索引;查找不到,返回-1 |
| 字符串替换 | s.replace(“hello”, “hi”) |
| 拆分-合并 | |
| 字符串拆分为列表 | s.split(“ “) |
| 可迭代对象链接成字符串 | “-“.join(l) |
| 字符串与字节 | |
| 字符串转字节 | b = “abc张三”.encode(“utf-8”) |
| 字节转字符串 | b.decode(“utf-8”) |
| 判断开头结尾 | |
| 判断是否是小写/大写 | s1.islower() => True |
| 判断是否为纯数据 | s2.isdigit() => => True |
| 判断是否以某字符开头 | s.endswith(“rld “) |
| 判断是否以某字符结尾 | s.startswith(“ hell”) |
分支循环
分支
1 | if condition: |
1 | if condition: |
判断一个数是奇数还是偶数
1 | var = int(input("请输入一个整数")) |
1 | var = int(input("请输入一个整数")) |
循环
for
1 | # range(start,end) # 返回可迭代对象,左闭右开 |
while
1 | sum = 0 |
continue
- 中断某次循环,继续下一次循环
1 | # 打印1-9中的偶数。 |
break
- 终止循环
1 | sum = 0 |
案例:九九乘法口诀表

方法一
第一步
观察发现:
如果把上三角补全的话,是一个 9*9 实对称阵;
列(i)的取值是(1~9)
行(j)的取值也是(1~9)
1 | 11 21 31 41 51 61 71 81 91 |
结果
1 | 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 |
第二步
取其中一半,只有当 j<=i 时输出,并调整格式
1 | for i in range(1,10): |
1 | 1*1=1 |
方法二
1 | for i in range(1,10): |
Collection模块
This module implements specialized container datatypes providing alternatives to Python’s general purpose built-in containers, dict, list, set, and tuple.
该模块实现了专门的容器数据类型,为Python的通用内置容器dict、list、set和tuple提供了替代方案。
序列类型
Python中常用的序列类型有字符串、列表和元组。

Python中的序列支持双向索引:正向递增索引和反向递减索引
正向递增索引从左向右依次递增,第一个元素的索引为0,第二个元素的索引为1,以此类推;
反向递减索引从右向左依次递减,从右数第一个元素的索引为-1,第二个元素的索引为-2,以此类推。
列表
创建
直接创建
列表可以包含任意类型的数据,包括数字、字符串、元组等。
1 | int_l = [1,2,3] |
其他类型转换而来
1 | trans_l = list("study") |
索引查询
支持 单值索引和范围索引切片。
1 | str_l[1] |
索引修改
1 | int_l[0] = 3 |
1 | int_l[1:3] = [4,5] |
增加
追加元素
1 | str_l.append("e") |
插入元素
1 | str_l.insert(0,"a") |
扩展列表
1 | str_l.extend(["g","f"]) |
升序
1 | str_l = ["a","c","b"] |
降序
1 | str_l = ["a","c","b"] |
逆转
1 | str_l = ["a","c","b"] |
删除
删除最后的元素
1 | str_l = ["a","b","c","d"] |
按值删除元素
1 | str_l.remove("a") |
清空列表
1 | str_l = ["a","b","c"] |
回收列表
1 | str_l = ["a","b","c"] |
列表推导式
需求一
根据已知列表,产生一个新列表,新列表中的每个元素为旧列表元素的平方。
1 | # 输入: |
方法一
1 | l_new = [] |
方法二
1 | l_new = [i**2 for i in l_old] |
需求二
从已知整数列表中筛选出奇数,形成一个新列表。
1 | # 输入: |
方法一
1 | l_odd = [] |
方法二
1 | l_odd = [i for i in l_old if i%2==1] |
需求三
计算两个数据集合的笛卡尔积。
1 | # 输入 |
方法一
1 | l_a = [1,2,3] |
方法二
1 | [(i,j) for i in l_a for j in l_b] |
元组
不支持修改。
创建
1 | t = (1) # 注意:1,int类型 |
查询
支持索引和范围索引
1 | t = (1,2,3) |
集合
Python集合具备互异性和无序性。
Ø 互异性:集合中的元素互不相同。
Ø 无序性:集合中的元素没有顺序。
Python要求放入集合中的元素必须是不可变类型。
Ø 不可变类型:整型、浮点型、字符串、元组。
Ø 可变类型:列表、集合、字典。

构造
1 | s_0 = set() |
交|并|差|对称差
1 | s_1 | s_2 # {1, 2, 3, 4} |
合并union
1 | s_1.union(s_2) # {1, 2, 3, 4} |
子集判断issubset
1 | s_3.issubset(s_1) # True |
超集判断issuperset
1 | s_1.issuperset(s_3) # True |
集合推导式
1 | a = {1,2,3,4,5} |
字典
映射类型以键值对的形式存储元素,键值对中的键与值之间存在映射关系。
字典(dict)是Python唯一的内置映射类型,字典的键必须遵守以下两个原则:
Ø 每个键只能对应一个值,不允许同一个键在字典中重复出现。
Ø 字典中的键是不可变类型。
构造
1 | zs = dict() |
查询
1 | zs["name"] # '张三' |
增加、修改
有则修改,无则增加
1 | zs["age"] = 19 |
删除
1 | zs.pop("tel") |
键
1 | zs.keys() |
遍历字典的key
1 | for k in zs: |
值
1 | zs.values() |
键值对
1 | zs.items() |
按序删除
1 | zs.popitem() # 栈 |
清空
1 | zs.clear() |
字典推导式
1 | # 借助字典推导式,交换字典的key和value, 产生新的字典 |
案例:词频统计
1 | poem = '''江南 |
统计古诗中每个字符出现的次数。
案例:词频统计
1 | word_count = {} |
其他
+ 运算符可用于字符串、列表、元组的拼接;
× 运算符可用于字符串、列表、元组的复制;
集合、字典不支持
排列组合
组合
1 | import itertools |
排列
1 | list(itertools.permutations([1,2])) # [(1, 2), (2, 1)] |
可迭代对象Iterable
可迭代对象的显著特征:包含__iter__方法。
1 | # abc: Abstract Base Classes (ABCs) |
迭代器Iterator
可迭代对象的显著特征:包含__next__方法。

1 | from collections.abc import Iterator |
可迭代对象和迭代器的区别
实现了 __iter__() 方法的类, 属于可迭代类;iter():传入可迭代对象返回迭代器。
实现了 __next__() 方法的类,属于迭代器类;next():从迭代器返回下一个元素。
可以使用迭代器进行迭代访问的列表、元组和字符串等都是可迭代对象。
1 | l1 = [1,2,3] |
生成器Generator
例一
1 | def gen(): |
1 | next(g) |
例二
1 | def yieldtest(x): |
1 | g.__next__() |
函数
函数定义

What is the difference between arguments and parameters?
Parameters are defined by the names that appear in a function definition, whereas arguments are the values actually passed to a function when calling it. Parameters define what kind of arguments a function can accept. For example, given the function definition:
1 | def func(foo, bar=None, **kwargs): |
foo, bar and kwargs are parameters of func. However, when calling func, for example:
1 | func(42, bar=314, extra=somevar) |
the values 42, 314, and somevar are arguments.
常规函数
1 | # 空函数 |
为参数指定默认值
1 | def func(a, b=100): |
默认参数值的计算
参数arg的值,在函数定义时触发计算。
1 | i = 5 |
注意
通常默认参数的值只计算一次,但是当默认参数是可变对象时,会有所不同。下面的函数会在后续调用中累积传递给它的实参。
1 | def f(a, L=[]): |
位置参数
位置参数是函数定义中最基本的参数类型。它们按照声明的顺序从函数调用者那里接受传递的值。在函数调用时,这些值按照函数定义时参数的顺序进行匹配。位置参数是函数定义的一部分,因此调用者必须按照声明时的顺序提供相应的值。
下面是一个简单的函数示例,其中包含两个位置参数:
1 | def add_numbers(x, y): |
在这个函数中,x 和 y 是位置参数。调用这个函数时,必须提供两个值,分别对应于 x 和 y:
1 | sum_result = add_numbers(3, 5) |
在这个例子中,3 和 5 是位置参数,它们分别传递给了 x 和 y。函数执行后返回它们的和,结果为 8。
值得注意的是,位置参数是按照它们在函数定义中的位置进行匹配的。因此,在调用函数时,提供的值的顺序非常重要。
关键字参数
关键字参数是一种在函数调用时通过指定参数名来传递值的方法。与位置参数不同,关键字参数的传递方式不依赖于参数的顺序,而是通过参数名明确指定值。这种方式可以提高函数调用的可读性,尤其是当函数有多个参数,而某些参数是可选的时候。
以下是关键字参数的基本使用方式:
1 | def greet(name, greeting): # greeting:问候 |
在这个函数中,name 和 greeting 都是位置参数。调用函数时,我们可以使用关键字参数的方式传递值:
1 | result = greet(greeting="Hello",name="张三") |
在这个例子中,我们通过 name="Alice" 和 greeting="Hello" 明确指定了每个参数的值。这种方式不仅提高了可读性,而且消除了参数位置的歧义。
关键字参数还可以与位置参数混合使用。例如:
1 | def print_person_info(name, age, city="Unknown"): |
在这个例子中,name 是位置参数,而 age、city 是关键字参数。如果不提供 city 的值,将使用默认值 "Unknown"。
总体而言,关键字参数提供了更灵活的调用方式,特别是在函数有很多参数时,可以明确指定每个参数的值,使得代码更加易读。
可变参数
* 在形参中出现时,用于打包参数为元组;
1 | def star_expression(*args): |
** 在形参中出现时,用于打包实参中的关键字参数为字典;
1 | def dict_expression(**kvargs): |
* 在实参中出现时,用于解包可迭代对象(字符串、列表、元组、字典的键)为位置参数;
1 | def star_expression(arg1,arg2): |
** 在实参中出现时,用于解包字典为关键字参数;
1 | def dict_expression(name,age): |
特殊参数
仅位置参数
1 | # 定义 |
仅关键字参数
1 | # 定义 |
位置关键字参数
1 | # 定义 |
递归
递归:函数自身调用自身。
例1:函数简单的调用自己
没有结束条件,会造成死循环。
1 | def func(): |
例2:不使用for循环打印1-100
1 | def f(x): |
例3:阶乘
1 | def factorial(n): |
例4:斐波那契数
1 | def fibonacci(n): |
作用域
Python变量的作用域一共有4种,分别是:
- L (Local) 局部作用域
- E (Enclosing) 闭包函数外的函数中
- G (Global) 全局作用域
- B (Built-in) 内建作用域
以 L->E->G->B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找。

在函数内引用全局变量
1 | x = 10 |
在函数内修改全局变量(失败)
1 | x = 10 |
在函数内引用全局变量并赋值(失败)
1 | x = 1 |
UnboundLocalError: cannot access local variable ‘x’ where it is not associated with a value
UnboundLocalError:无法访问未与值关联的局部变量“x”
在函数内修改全局变量(成功)
在函数内对外部变量赋值时,会在函数内重新创建一个同名局部变量。
1 | x = 10 |
闭包
在函数内部定义函数并返回的方式。
当函数在执行中,其内的某变量被其内定义的函数引用后,不会立刻释放该变量,允许新定义的函数持有该变量的引用。这就是在lambda演算中引入“闭包”的原因,这种机制产生的持有上层函数环境、新定义的函数,就叫“闭包”。
闭包Enclosing-nolocal
1 | def outer(x): |
1 | a = 10 |
当inner函数中的局部变量a使用nolocal修饰时,指向的是outer函数中的a=20;
当inner函数中的局部变量a使用global修饰时,指向的是全局变量a=10
高阶函数
lambda匿名函数
lambda匿名函数中只能使用简单的语法,不能使用if else while return等语句。
1 | lambda :None |
1 |
|
lambda匿名函数应用
测试数据
1 | x = range(10,0,-1) |
1 | [(10, 'a'), |
打乱
1 | import random |
1 | [(9, 'b'), |
对指定字段排序
1 | def sort_by_one(x): |
排序结果
1 | [(10, 'a'), |
lambda匿名表达式方式
1 | data.sort(key=lambda x:x[0]) |
排序结果
1 | [(1, 'j'), |
再次打乱数据
1 | import random |
根据第一字段的长度排序(逆序)
1 | data.sort(key=lambda x:len(str(x[0])), reverse=True) |
排序结果
1 | [(10, 'a'), |
对字典排序(value)
1 | d = {"a":3,"c":2,"b":1,"e":4} |
排序结果
1 | [('b', 1), ('c', 2), ('a', 3), ('e', 4)] |
为hello函数增加日志打印功能
函数作为参数
1 | import time |
函数作为返回值
1 | def hello(): |
装饰器模式
1 | import time |
1 | print(hello.__name__) #logWrapper |
装饰器调整
1 | import time |
面向对象
面向对象有三个基本特征:封装(Encapsulation)、继承(Inheritance)、多态(Ploymorphism);
封装指的是将对象的实现细节隐藏起来,然后通过一些公用方法来暴露该对象的功能;
继承是面向对象实现软件复用的重要手段,当子类继承父类后,子类作为一种特殊的父类,将直接获得父类的属性和方法;
多态指的是子类对象可以直接赋值给父类变量,但运行时依然表现出子类的行为特征,这意味着同一个类型的对象在执行同一方法时,可能表现出多种行为特征。
《疯狂Java讲义·第五版》
类的定义
1 | class Person: |
构造方法,也称为初始化方法,创建对象时,自动调用该方法。self参数,表示调用该方法的对象。
对象的创建
1 | zs = Person("张三", 18) |
对象的
数据成员和行为都可以称为对象的属性;如:张三的姓名、体重特征和张三的讲话行为都是张三的属性。通常情况下,将对象的数据成员称为属性;将对象的行为称为方法。属性:https://docs.python.org/3.12/glossary.html#term-attribute
类变量
1 | class Person: |
类变量,多个对象共享该变量https://docs.python.org/3.12/glossary.html#term-class-variable
属性的类型
1 | class Person: |
注意:类变量名和对象属性名可相同。
查看对象的属性
1 | zs.__dict__ |
类实例化:https://docs.python.org/3.12/tutorial/classes.html#class-objects
属性字典:https://docs.python.org/3.12/library/stdtypes.html?highlight=__dict__#object.__dict__
公有属性
1 | zs = Person("张三",60) |
私有属性
1 | # zs.__weight # AttributeError |
私有属性类外不可见,可通过如下方式为私有属性增加查询、修改、删除方法。
私有属性访问方式1
1 | class Person: |
1 | zs.set_weight(70) # 通过set方法修改为70 |
私有属性访问方式2
1 | class Person: |
1 | zs = Person("张三",60) |
私有属性访问方式3
1 | class Person: |
1 | zs = Person("张三",60) |
方法
成员方法
1 | class Person: |
类方法
类方法传递一个cls参数,表示当前类;
1 | class Person: |
注意
通常情况下:
对象调用成员方法;类调用类方法。
另外:
对象也可调用类方法;
类也可调用成员方法(类调用成员方法时,需要显式传递对象名到self参数)
静态方法
1 | class Person: |
如果一个方法没有使用到类本身任何变量,可以直接使用静态方法。静态方法放到类外边也不影响,主要是放在类里面给它一个作用域,方便管理 。
添加与查询属性
添加属性
1 | setattr(zs,"age",18) |
查询属性值
1 | getattr(zs,"age") |
面向对象编程练习题
编写一个矩形类,用于表示矩形。该类应包含以下特性和功能:
- 属性:
- 私有属性:宽度和高度。
- 公有属性:面积(用于存储矩形的面积,但在外部不可直接访问)。
- 类属性:总矩形数,用于跟踪创建的矩形实例的数量。
- 方法:
- 私有方法:
- 验证设置的宽度和高度是否有效(大于0)。
- 公有方法:
- 计算矩形的面积,并存储在公有属性
面积中。 - 返回矩形的面积。如果公有属性
面积未被计算,则先调用计算矩形的面积方法。 - 设置矩形的宽度。调用私有方法验证宽度是否有效,如果有效,则更新宽度,并重置面积(因为面积可能受到影响)。
- 设置矩形的高度。调用私有方法验证高度是否有效,如果有效,则更新高度,并重置面积(因为面积可能受到影响)。
- 查询矩形的宽度和高度。
- 计算矩形的面积,并存储在公有属性
- 类方法:
- 返回已创建的矩形实例的总数。
- 静态方法:
- 在静态方法中创建两个矩形对象,并在对象初始化时,指定宽度和高度;
- 通过公有方法修改第一个矩形对象的宽度和高度;
- 查询矩形的宽度和高度;
- 打印矩形的面积
- 打印矩形实例的总数。
- 私有方法:
二、要求
- 实现上述
矩形类,并确保它符合面向对象编程的规范。 - 在类的实现中,应体现公有属性、私有属性、类属性的概念。
- 编写公有方法、私有方法、类方法和静态方法,并确保它们能正确执行其预期的功能。
- 在类的使用过程中,演示如何创建
矩形对象、如何访问和修改其属性、如何调用其方法。 - 编写代码示例,展示如何使用
矩形类,并验证其功能的正确性。
1 | class Rectangle: |
继承
继承是面向对象软件技术当中的一个概念,与多态、封装共为面向对象的三个基本特征。继承可以使得子类具有父类的属性和方法或者重新定义、追加属性和方法等。
百度百科
通过继承创建的新类称为“子类”或“派生类”;
被继承的类称为“父类”或“基类”
子类继承父类的公用方法
在Person类基础上,派生出Student类。
1 | class Person: |
子类调用父类的构造函数
1 | class Person: |
1 | zs = Student("张三",70,18) |
会出现错误
1 | AttributeError: 'Student' object has no attribute '_Student__weight' |
子类对象可以继承父类的公有属性和方法,如上述从父类继承过来的name属性;
不能继承父类的私有属性和私有方法,如上述父类的__weight属性。但可以间接访问父类的私有属性。
在父类中为私有属性weight设置公有get方法。
1 | class Person: |
1 | zs = Student("张三",70,18) |
1 | This a Person. |
重写 Override
重写一个继承自父类的同名方法。
1 | def basic_info(self): |
多态
1 | class Person: |
1 | def whoAmI(x): |
如何查找对象的方法或属性
How can I find the methods or attributes of an object?¶
For an instance x of a user-defined class, dir(x) returns an alphabetized (按字母顺序排列)list of the names containing the instance attributes and methods and attributes defined by its class.
对于用户定义类的实例x,[dir(x)]返回一个按字母顺序排列的名称列表,其中包含实例属性和方法以及由其类定义的属性。
继承练习1
编写一个名为Animal的父类,该类包含以下属性和方法:
- 属性:
name(动物的名称) - 方法:
speak() - 方法:
eat()(打印动物正在进食的消息)
然后,创建两个子类Dog和Cat,它们分别继承自Animal类。
Dog类应该具有额外的属性breed(狗的品种),并实现speak()方法以打印狗叫的声音。Cat类应该只实现speak()方法以打印猫叫的声音。
最后,创建Animal、Dog和Cat的实例,并测试它们的方法,确保Dog和Cat能够正确地调用继承自Animal的eat()方法,以及它们各自的speak()方法。
继承练习2
- 为矩形类派生子类 正方形;
- 为正方形类增加属性edge;
- 修改从父类继承的
calculate_area方法,根据边长的平方计算面积; - 创建正方形对象;
- 计算面积;
- 显示面积
命名空间、包、模块
namespace
The place where a variable is stored. Namespaces are implemented as dictionaries. There are the local, global and built-in namespaces as well as nested namespaces in objects (in methods). Namespaces support modularity by preventing naming conflicts. For instance, the functions builtins.open and os.open() are distinguished by their namespaces. Namespaces also aid readability and maintainability by making it clear which module implements a function. For instance, writing random.seed() or itertools.islice() makes it clear that those functions are implemented by the random and itertools modules, respectively.
存储变量的位置。名称空间被实现为字典。对象(方法)中有本地、全局和内置的名称空间以及嵌套的名称空间。名称空间通过防止名称冲突来支持模块化。
例如,函数[builtins.open()]和[os.open()]通过名称空间进行区分。
名称空间还通过明确哪个模块实现了一个函数来帮助可读性和可维护性。例如,编写[random.seed()]或[itertools.islice()]可以清楚地表明,这些函数分别由[random]和[itertools]模块实现。
module
An object that serves as an organizational unit of Python code. Modules have a namespace containing arbitrary(任意的) Python objects. Modules are loaded into Python by the process of importing.
模块作为Python代码的组织单元的对象。模块的名称空间包含任意(任意的) Python对象。模块通过[导入]的过程加载到Python中。
regular package
A traditional package, such as a directory containing an __init__.py file.
传统的[包],例如包含__init__.py文件的目录。
namespace package
A PEP 420 package which serves only as a container for subpackages. Namespace packages may have no physical representation, and specifically are not like a regular package because they have no __init__.py file.
一个[PEP 420][package],仅用作子包的容器。命名空间包可能没有物理表示,特别是与[常规包]不同,因为它们没有__init__.py文件。
PEP是Python Enhancement Proposals的缩写。一个PEP是一份为Python社区提供各种增强功能的技术规格,也是提交新特性,以便让社区指出问题,精确化技术文档的提案。
1 | ################################### module ################################### |
Module(PY文件)
__name__属性
类、模块、包 都有__name__属性
- 当Python文件被当做程序执行时:
__name__==__main__ - 当Python文件被当做模块导入时:
__name__==文件名
定义模块
Addtion.py
1 | a = 1 |
使用模块
导入模块
1 | import Addition |
从模块导入某个对象
1 | from Addition import add |
从模块导入所有对象
1 | from Addition import * |
特殊情况
使用from Addition import *导入时,无法导入下划线开头的成员;
1 | from Addition import * |
值得注意的是,如果使用import Addition这样导入模块,仍然可以用Addition._c或Addition.__d这样的形式访问到这样的对象。
__all__变量
除非该成员在模块中的__all__变量中。
1 | __all__ = ["a", "_c", "__d", "add"] |
Jupyter中会保留已定义的变量,测试时记得重启kernel。
Regular Package
Regular Package:带 __init__.py文件的文件夹。导入包时,会自动执行__init__.py中的代码。
创建包
1 | PS C:\Users\Qingyuan_Qu\Desktop\python> tree /f /a |
Addition.py
内容不变。
__init__.py
1 | print(__name__) |
使用包
1 | import package.Arithmetic #导入包,只能使用包中的对象(属性、函数等) |
模块练习
题目描述:
假设你是一位软件开发者,你需要创建一个名为math_utilities的Python模块,该模块包含一些基本的数学函数。然后,在另一个Python脚本中,你需要导入这个模块,并使用其中的函数来进行一些计算。
具体要求:
创建一个名为
math_utilities.py的Python模块,并在其中定义以下函数:add(x, y):返回两个数字的和。subtract(x, y):返回两个数字的差。multiply(x, y):返回两个数字的乘积。divide(x, y):返回两个数字的商。如果除数为0,则抛出一个ValueError异常。
创建一个名为
main.py的Python脚本,在该脚本中:- 导入
math_utilities模块。 - 使用
math_utilities模块中的函数来计算并打印以下结果:- 5和3的和
- 5和3的差
- 5和3的乘积
- 尝试计算5除以0(应该捕获并打印异常信息)
- 导入
运行
main.py脚本,并验证结果是否正确。
提示:
- 确保
math_utilities.py和main.py两个文件位于同一个目录下。 - 在
main.py中,你可以使用import math_utilities来导入模块。 - 使用
try-except块来捕获和处理divide函数可能抛出的异常。
练习目标:
- 熟悉Python模块的概念和用法。
- 学会在模块中定义函数,并在其他脚本中导入和使用这些函数。
- 掌握异常处理的基本方法。
包练习
题目描述:
在本练习中,你将学习如何创建一个简单的Python包,并在另一个Python脚本中导入和使用该包中的模块。假设你要创建一个名为my_math_package的包,它包含两个模块:basic_operations和advanced_operations。
具体要求:
创建包目录结构:
- 创建一个名为
my_math_package的目录。 - 在
my_math_package目录下,创建两个子目录basic_operations和advanced_operations(它们将作为包内的模块)。 - 在每个子目录中,创建一个名为
__init__.py的空文件(这是将目录变为Python包所必需的)。
- 创建一个名为
编写模块代码:
- 在
basic_operations模块的__init__.py文件中,定义函数add和subtract。 - 在
advanced_operations模块的__init__.py文件中,定义函数multiply和divide(确保处理除以零的情况)。
- 在
创建使用包的脚本:
- 创建一个名为
use_math_package.py的Python脚本。 - 在这个脚本中,导入
my_math_package包,并使用其中的函数进行一些计算。
- 创建一个名为
运行脚本并验证结果:
- 运行
use_math_package.py脚本,并验证结果是否正确。
- 运行
示例代码:
basic_operations/__init__.py
1 | def add(x, y): |
advanced_operations/__init__.py
1 | def multiply(x, y): |
use_math_package.py
1 | from my_math_package.basic_operations import add, subtract |
练习目标:
- 理解Python包和模块的概念。
- 学会如何创建和组织包结构。
- 学会如何在其他脚本中导入和使用包中的模块。
- 巩固异常处理的知识。
文件处理入门
文件读写
在Python中可以通过open函数打开文件进行读写;
语法格式:
open(file, mode="r")
with关键字
代码中有异常情况
不使用with
1 | f = open("studybigdata.txt","w") |
出现异常时,文件没有正常关闭,文件内容为空。
我们写的字符串在内存中,没有正常刷写到磁盘上。
使用with
1 | with open("studybigdata.txt","w") as f: |
虽然产生了异常,但是可以把字符串写入文件中。
异常处理
1 | 1/0 |
异常处理
1 | f = open("studybigdata.txt","w") |
打印具体异常信息
1 | try: |
多异常处理
1 | try: |
无异常处理
当程序有异常时,执行except语句块;
当程序无异常时,执行else语句块。
1 | try: |
收尾
1 | try: |
异常不处理
抛出异常
1 | raise ZeroDivisionError("主动抛出异常") |
异常处理练习
编写一个程序,该程序从用户输入中读取一系列数字,并计算这些数字的平均值。如果用户输入的不是数字(即输入无法转换为浮点数),则应该捕获异常并提示用户重新输入。当用户输入”q”时,程序应结束并输出已输入数字的平均值(如果至少输入了一个数字)。
多次让用户输入数据;
数据类型转换;
OS模块
| os.name | 查看操作系统内核名 | |
| 环境变量 | ||
| os.environ[] | 设置环境变量 | os.environ[“name”]=”zhangsan” |
| os.getenv() | 查询环境变量 | os.getenv(“PATH”) |
| 目录与文件 | ||
| os.getcwd() | 查询当前工作目录 | |
| os.chdir() | 切换目录 | |
| os.listdir() | 查看指定目录下的所有文件和目录 | os.listdir(“C:\“) |
| os.mkdir() | 创建目录 | |
| os.rmdir() | 删除目录 | |
| os.removedirs() | 删除多个目录 | |
| os.rename() | 重命名文件 |
多线程
进程(线程)的状态
在操作系统中,进程(或线程)可以处于几种不同的状态。这些状态用于描述进程的当前活动或等待状态。以下是常见的进程状态及其介绍:

1. 新建(New)
- 描述:进程正在被创建。
- 详细信息:当一个新进程被创建时,它处于新建状态。操作系统分配必要的资源(如内存)并进行初始化。
2. 就绪(Ready)
- 描述:进程已经准备好执行,但尚未分配到CPU。
- 详细信息:在这个状态下,进程已加载到内存中并等待被调度到CPU上执行。多个就绪进程通常存储在一个就绪队列中,由调度程序根据一定的调度算法选择下一个要执行的进程。
3. 运行(Running)
- 描述:进程正在CPU上执行。
- 详细信息:当进程被调度到CPU上,它从就绪状态变为运行状态。在这个状态下,进程的指令正在被处理器执行。
4. 阻塞/等待(Blocked/Waiting)
- 描述:进程正在等待某个事件(如I/O操作完成或资源可用)。
- 详细信息:如果进程需要等待某个条件满足(例如,等待I/O操作完成、等待某个锁或信号),它会进入阻塞状态。进程在阻塞状态下不会占用CPU资源,直到所等待的事件发生后才会转为就绪状态。
5. 终止(Terminated)
- 描述:进程已经完成执行或因某种原因被终止。
- 详细信息:当进程执行完所有指令或被操作系统终止时,它进入终止状态。操作系统会清理进程所占用的资源,并将其从进程表中移除。
6. 挂起(Suspended)
- 描述:进程被暂时停止执行,并被移出内存。
- 详细信息:操作系统可能会将某些进程从内存中移到磁盘上,以释放内存资源给其他进程使用。挂起状态可以分为两种:
- 就绪挂起(Ready Suspended):进程在磁盘上,但已经准备好执行,一旦被重新加载到内存中即可执行。
- 阻塞挂起(Blocked Suspended):进程在磁盘上,并且在等待某个事件。
Python线程
threading.Thread
threading.Thread 类的构造方法用于创建线程对象。
1 | thread = threading.Thread(target=target_function, args=(arg1, arg2), kwargs={'key1': value1, 'key2': value2}, daemon=False, name='ThreadName') |
这个构造方法可以接受多个参数,主要包括:
target:指定线程将要执行的目标函数或方法。这个参数是一个可调用的对象(函数、方法等),在线程启动后将被调用执行。如果没有指定此参数,线程将不会执行任何操作。
args:一个元组,用于传递给目标函数或方法的参数。如果目标函数需要接收参数,可以通过这个参数传递。如果目标函数不需要参数,可以省略此参数。
kwargs:一个字典,用于传递给目标函数或方法的关键字参数。与
args参数类似,用于传递额外的参数给目标函数或方法。daemon:一个布尔值,表示线程是否为守护线程。如果将守护线程标志设置为
True,则该线程在主线程退出时会被自动终止。默认值为False。name:线程的名称。可以给线程指定一个名称,方便识别和调试。如果不指定名称,系统会自动分配一个名称。
线程示例
1 | import threading |
在这个示例中,我们创建了一个名为 NumberPrinter 的线程,它执行的目标函数是 print_numbers。这个函数接受两个参数 start 和 end,并打印出指定范围内的数字。然后,我们启动线程,并在主线程中等待线程执行完毕。
thread.start():thread.start()是threading.Thread对象的方法,用于启动线程。一旦线程启动,它将执行其目标函数或方法。- 在调用
start()方法之后,线程将进入可运行状态,并在系统资源允许的情况下被调度执行。
thread.join():thread.join()是threading.Thread对象的方法,用于在主线程中等待线程执行完成。- 在调用
join()方法之后,主线程将会阻塞,直到thread线程执行完成。这样做的目的是为了确保在主线程继续执行之前,thread线程已经完成了它的任务。
练习
- 修改上述代码,打印 1,3,5,7,9
Python多线程
简单的Python多线程案例,模拟一个简单的任务,比如计算一组数字的平方和立方。
1 | import threading |
导入模块:导入
threading和time模块。threading用于多线程操作,time用于在计算过程中引入延迟,以便更好地展示多线程的效果。定义任务函数:
calculate_squares(numbers):计算输入列表中每个数字的平方,并打印结果。calculate_cubes(numbers):计算输入列表中每个数字的立方,并打印结果。
主函数:
- 创建一个包含数字的列表
numbers。 - 创建两个线程
thread1和thread2,分别执行计算平方和计算立方的任务。 - 使用
start()方法启动线程。 - 使用
join()方法等待线程完成。
- 创建一个包含数字的列表
执行主函数:检查是否是主模块并调用
main()函数。
运行结果
程序运行时,会同时执行计算平方和立方的任务,输出结果会交错显示,表明两个线程在并发工作。
练习
修改上述代码,添加一个线程,实现输出numbers中所有偶数。
线程锁
threading.Lock():
threading.Lock()是 Python 中的一个锁对象,用于在多线程编程中控制对共享资源的访问。锁在多线程环境中用于防止多个线程同时访问共享资源,从而避免出现数据竞争和不一致的情况。- 你需要在需要保护的代码段前后分别使用
lock.acquire()和lock.release()方法来获取和释放锁,以确保同一时间只有一个线程可以访问共享资源。
下面是一个结合了这些概念的示例代码:
1 | import threading |
在这个示例中,我们创建了两个线程 thread 和 thread2,它们都执行 modify_shared_resource 目标函数。这个函数用于修改一个共享资源 shared_resource。为了确保多个线程不会同时修改 shared_resource,我们使用了一个锁对象 lock 来保护共享资源的访问。每个线程在修改共享资源之前都会先获取锁,然后在修改完成后释放锁。通过这种方式,我们确保了共享资源的安全访问。
练习
将上述程序修改为售票程序;
如,将shared_resource变量视为票数,设置起始值为 10;
再添加一个售票线程。
正确答案
1 | def modify_shared_resource(): |
错误答案
1 | def modify_shared_resource(): |
线程锁案例-售票系统
下面是一个更贴近实际应用的多线程案例,演示如何使用Python的threading模块实现一个简单的售票系统。这个系统有多个线程,模拟多个售票窗口同时卖票。
前面我们通过lock.acquire()与lock.release()实现了锁的获取与释放,但其实我们Python还给我们提供了一个更简单的语法,通过with lock来获取与释放锁。
1 | import threading |
导入模块:
threading:用于多线程操作。time:用于引入延迟。
定义
TicketSeller类:__init__方法:初始化票数和锁。sell_ticket方法:卖票逻辑,使用锁确保线程安全。
定义售票窗口线程函数:
ticket_window函数:调用TicketSeller类的sell_ticket方法。
主函数:
- 初始化售票系统,设置总票数。
- 创建多个线程,模拟多个售票窗口。
- 启动线程并等待所有线程完成。
执行主函数:检查是否是主模块并调用
main()函数。
运行结果
程序运行时,会有多个线程同时执行卖票任务,输出结果类似于:
1 | Window 1 sold 1 ticket, 9 tickets left. |
这个案例展示了如何使用多线程来模拟一个简单的售票系统,其中使用了锁机制来保证多个线程在访问和修改共享资源(即票数)时的线程安全。
The End
文件读写module _io
mode
1 | ========= =============================================================== |
| 文件操作 | 方法 | 示例 |
|---|---|---|
| 打开 | open() |
file = open('filename.txt', 'r') |
| 关闭 | close() |
file.close() |
| 读文件 | ||
| 读n个字符 | read(n) |
content = file.read(10) |
| 读一行 | readline() |
line = file.readline() |
| 读所有行 | readlines() |
lines = file.readlines() |
| 写文件 | ||
| 写入字符串 | write() |
file.write('hello\n') |
下面是这些方法的使用案例:
open
1. ‘r’
- 打开文件进行读取(默认)
1 | with open('example.txt', 'r') as file: |
如果example.txt存在,它会读取并打印文件的内容。如果不存在,则会引发FileNotFoundError。
2. ‘w’
- 打开文件进行写入,先清空文件内容
1 | with open('example.txt', 'w') as file: |
如果example.txt存在,它的内容会被清空,并写入'Hello, World!'。如果文件不存在,它会被创建。
3. ‘x’
- 创建一个新文件并打开进行写入
1 | try: |
如果example.txt存在,则会引发FileExistsError。否则,文件会被创建并写入'This is a new file.'。
4. ‘a’
- 打开文件进行写入,如果文件存在则追加到末尾
1 | with open('example.txt', 'a') as file: |
无论example.txt是否存在,都会在其末尾追加'\nAnother line of text.'。
5. ‘b’ 和 ‘t’
二进制和文本模式(通常与其他模式一起使用)
文本模式(’t’)是默认的,用于处理文本文件。
二进制模式(’b’)用于处理二进制文件,如图像或音频文件。
1 | # 文本模式(默认) |
6. ‘+’
- 打开磁盘文件进行更新(读取和写入)
1 | with open('example.txt', 'r+') as file: |
注意:在使用’r+’模式时,如果试图在读取整个文件后写入,你需要先将文件指针移回文件的开始(使用file.seek(0)),否则的写入操作会覆盖文件的剩余部分。
- 中文
1 | try: |
1 | with open('example.txt', 'r+') as file: |
read
当我们在Python中使用open()函数打开一个文件后,通常会使用文件对象提供的一些方法来读取文件的内容。以下是read(), readline(), 和 readlines() 这三个常用方法的介绍:
1. read()
read()方法用于从文件中读取指定数量的字节或整个文件,并将其作为字符串返回。如果未指定参数,则默认读取整个文件。
示例:
1 | with open('example.txt', 'r') as file: |
2. readline()
readline()方法用于从文件中读取一行内容,并将其作为字符串返回。每次调用readline()时,它都会读取文件中的下一行。
示例:
1 | with open('example.txt', 'r') as file: |
3. readlines()
readlines()方法用于读取文件中的所有行,并将它们作为列表返回,其中列表的每个元素都是文件中的一行。
示例:
1 | with open('example.txt', 'r') as file: |
注意:在使用read(), readline(), 和 readlines() 方法时,如果文件很大,一次性读取整个文件可能会导致内存不足。在这种情况下,最好使用循环逐行读取或使用更高效的读取策略,如文件对象的迭代(如上例中直接遍历文件对象)。
文件读写练习
- 通过Python新建一个文件
gushi.txt,选择一首古诗写入文件中。 - 编写一个函数,读取指定的文件
gushi.txt,将内容复制到copy.txt中,并在控制台输出“复制完毕”。
1. 新建文件并写入古诗
1 | # 定义函数写入古诗 |
2. 读取文件并复制到另一个文件
1 | # 定义函数读取并复制文件内容 |
Time模块
| 时间分类 | 函数名 | |
|---|---|---|
| 格林威治时间 | time.gmtime() | 九元组 |
| 本地时间 | time.localtime() | 九元组 |
| 格式化字符串 | time.asctime() | ‘Sun Apr 23 10:31:48 2023’ |
| 字符串转时间对象 | time.strptime(time_1, ‘%Y-%m-%d %H:%M:%S’) | time1 = “2000-01-01 14:30:30” |
| 时间对象转字符串 | time.strftime(“%Y-%m-%d %H:%M:%S”, time.localtime()) |
localtime北京时间 = gmtime格林威治时间 + 8小时
CSV模块
Python的csv模块提供了用于读写CSV(Comma Separated Values,逗号分隔值)文件的功能。CSV是一种常见的数据交换格式,它以纯文本形式存储表格数据(如电子表格或数据库中的数据)。CSV文件中的每一行代表一条记录,每个字段之间由逗号(或其他指定的分隔符)分隔。
csv模块使得处理CSV文件变得简单而直观,它提供了几个关键的功能:
csv.reader(): 用于读取CSV文件中的数据。它返回一个迭代器,其中每一行都表示为一个列表,列表中的每个元素都是这一行中的一个字段。
csv.writer(): 用于将数据写入CSV文件。你可以使用这个writer对象将行数据(表示为列表或元组)写入CSV文件。
csv.DictReader() 和 csv.DictWriter(): 这两个函数类似于
reader和writer,但它们是处理字典而不是列表。字段名通常位于CSV文件的第一行(标题行),每一行数据都被解析为一个字典,其中键是字段名,值是对应的数据。
下面是一个简单的示例,展示了如何使用csv模块读取和写入CSV文件:
读取CSV文件
1 | import csv |
写入CSV文件
1 | import csv |
使用DictReader和DictWriter
1 | # 写入CSV文件(使用字典形式) |
csv模块还提供了许多其他功能和选项,例如自定义分隔符、引号符号、行终止符等,以满足不同CSV文件格式的需求。这些功能使得csv模块成为处理CSV数据的强大工具。
JSON
Python 的 json 模块用于在 Python 和 JSON(JavaScript Object Notation)之间进行数据交换。JSON 是一种轻量级的数据交换格式,易于人类阅读和编写,也易于机器解析和生成。json 模块提供了简单的接口来编码(序列化)和解码(反序列化)JSON 数据。下面通过几个案例介绍如何使用 json 模块。
常用函数
在 Python 中,json 模块提供了一些主要函数用于 JSON 数据的编码和解码,具体包括 dump、dumps、load 和 loads。这些函数的主要区别在于它们处理 JSON 数据的方式和应用场景。下面详细介绍它们的功能和区别。
总结与区别
dumpvsdumps:dump:将 Python 对象序列化为 JSON 格式,并写入文件。用于处理文件 I/O。dumps:将 Python 对象序列化为 JSON 字符串。用于在代码中传递或处理 JSON 数据。
loadvsloads:load:从文件中读取 JSON 数据,并反序列化为 Python 对象。用于处理文件 I/O。loads:将 JSON 字符串反序列化为 Python 对象。用于在代码中解析 JSON 数据。
使用场景
dump和load:适用于将 JSON 数据保存到文件或从文件中读取 JSON 数据的场景。dumps和loads:适用于在内存中操作 JSON 数据,例如在网络传输、日志记录或测试时使用。
通过以上介绍和示例,可以更清楚地了解 json.dump、json.dumps、json.load 和 json.loads 的用法和区别。
JSON序列化与反序列化
JSON 编码(序列化)
将 Python 对象转换为 JSON 字符串的过程称为编码或序列化。
示例:将字典转换为 JSON 字符串
1 | import json |
输出结果:
1 | {"name": "Alice", "age": 25, "is_student": false, "courses": ["Math", "Science"], "address": {"city": "Wonderland", "zipcode": "123456"}} |
JSON 解码(反序列化)
将 JSON 字符串转换为 Python 对象的过程称为解码或反序列化。
示例:将 JSON 字符串转换为字典
1 | import json |
输出结果:
1 | {'name': 'Alice', 'age': 25, 'is_student': False, 'courses': ['Math', 'Science'], 'address': {'city': 'Wonderland', 'zipcode': '123456'}} |
读写 JSON 文件
json 模块还提供了方便的方法来读写 JSON 文件。
示例:将字典写入 JSON 文件
1 | import json |
示例:从 JSON 文件读取数据
1 | import json |
控制 JSON 编码的格式
可以通过 json.dumps() 和 json.dump() 的一些参数来控制 JSON 编码的格式,如缩进和排序键。
示例:格式化 JSON 字符串
1 | import json |
输出结果:
1 | { |
示例:按键排序 JSON 字符串
1 | import json |
输出结果:
1 | { |
通过上述几个案例,可以看到如何使用 Python 的 json 模块来进行 JSON 数据的编码和解码,以及如何读写 JSON 文件和控制 JSON 编码格式。
自定义类对象的序列化
在 Python 中,json 模块也可以用来处理自定义对象的编码和解码。为了将自定义对象转换为 JSON 字符串,我们需要编写自定义的编码和解码函数。下面通过一个具体的案例来展示如何处理自定义对象。
自定义对象编码(序列化)
首先,我们定义一个简单的类 Person,然后编写一个自定义的编码器将其转换为 JSON 字符串。
示例:自定义对象编码
1 | import json |
输出结果:
1 | { |
自定义对象解码(反序列化)
对于解码,需要将 JSON 字符串转换回自定义对象。我们可以编写一个自定义的解码器来实现这一点。
示例:自定义对象解码
1 | import json |
输出结果:
1 | Encoded JSON: |
1 | Decoded Object: |
使用 JSONEncoder 和 JSONDecoder
我们还可以通过继承 json.JSONEncoder 和 json.JSONDecoder 来实现自定义对象的编码和解码。
示例:使用 JSONEncoder 和 JSONDecoder
1 | import json |
输出结果与之前相同:
1 | Encoded JSON: |
1 | Decoded Object: |
通过这些案例,可以看到如何使用 json 模块来处理自定义对象的编码和解码。可以通过编写自定义的编码和解码函数或继承 JSONEncoder 和 JSONDecoder 来实现这一点。
Pickle模块
Python对象序列化工具。
序列化
1 | import pickle |
反序列化
1 | import pickle |
调整
序列化
1 | import pickle |
反序列化
1 | import pickle |
注意:
第一种是将三个对象分别序列化,反序列化的时候load了三次;
第二种是将三个对象组合成一个元组对象再序列化,所以反序列化时只需要load一次。