# python-面向对象 - class
本文精选:https://www.yuque.com/mrcode.cn/note-combat/nv62kvczbzugm545
# 如何定义 class
在 Python 3.7 以前,需要这样写
class TaskDemo:
def __init__(self, a: str, b: str, c: str = None):
self.a = a
self.b = b
self.c = c
if __name__ == '__main__':
task = TaskDemo('1', '2', 3)
task = TaskDemo('1', '2')
# 或者这样写
task = TaskDemo(a='1', b='2')
# 这个就会报错,因为是必须传入的值
task = TaskDemo('1')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
在 Python 3.7+ ,可以使用 @dataclass
帮我们实习上面的效果,可以这样写,更方便
from dataclasses import dataclass
@dataclass
class TaskDemo:
a: str
b: str
c: str = None
1
2
3
4
5
6
7
2
3
4
5
6
7
# 如何让一个 json 字符串变成类实例呢?
# object_hook 无嵌套对象反序列化
下面有一个例子
import json
from dataclasses import dataclass
# """文档注释""",这种是文档注释,在类下面,字段下面
@dataclass
class TaskConfigData:
"""任务配置信息"""
redisKeyOfResult: str = None
"""响应结果存储在 Redis 中的 key"""
rawKeywords: str = None
"""原始关键词字符串"""
searchKeywords: list[str] = None
"""将原始关键词字符串,处理后的关键词列表"""
taskId: int = None
"""主任务ID"""
taskRecordId: int = None
"""当前任务ID"""
cookie_str: str = None
"""分配的账户对应的 cookie 字符串"""
spiderAccountId: int = None
"""分配的账户 ID"""
browser_headless: bool = True
"""是否开启无头模式"""
def to_json_str(self):
"""将对象转换为 json 字符串"""
return json.dumps(self, default=lambda o: o.__dict__, ensure_ascii=False)
# @staticmethod 注解是标记这个方法是一个静态方法
@staticmethod
def from_json_str(json_str):
"""
将 json 字符串转换为对象
这里使用 object_hook 参数来处理 TaskConfigData 对象,结果就是该类的实例
object_hook 就是遇到对象,就调用这个方法
"""
return json.loads(json_str, object_hook=lambda d: TaskConfigData(**d))
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
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
下面是测试
def test_task_config_data():
config_data = {
"rawKeywords": "假发|潮流",
"redisKeyOfResult": "crawlab:task:result:1",
"searchKeywords": ["假发|潮流"],
"taskId": 1,
"taskRecordId": 1,
"cookie_str": 'did=web_81424f8dcdac46d8b31f2e75679ed311; didv=1712734359000; userId=2862954251; kuaishou.server.web_ph=fcfbbb6413ce14ca0670760dc2dec8d5fab5',
"spiderAccountId": 1,
"browser_headless": False, # 是否无头模式
}
# 从 json 字符串转换为对象
data: TaskConfigData = TaskConfigData.from_json_str(json.dumps(config_data))
print(data)
print(data.to_json_str())
if __name__ == '__main__':
test_task_config_data()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
文档注释的效果如下:
WARNING
需要注意的是:这种方式只适合没有嵌套对象的方式
因为 object_hook 是遇到对象就回调,如果是嵌套对象就不行了,比如下面这种
result = {
"taskId": 1,
"taskRecordId": 1,
"success": False,
"remark": "请求 API 失败",
"spiderAccountInfo": {
"id": 1,
"use": True,
"success": False,
"remark": "请求 API 失败"
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
他的解析方式如下:
- 先拿 spiderAccountInfo 的值,也就是这个对象,去调用一次 object_hook
- 再用 根 对象去调用一次 object_hook
因为在调用的时候,参数就是对象,比如
{
"id": 1,
"use": True,
"success": False,
"remark": "请求 API 失败"
}
1
2
3
4
5
6
2
3
4
5
6
所以你就没法知道这个对象对应的字段是什么,在本例中是 spiderAccountInfo 的值,所以你就没有办法实现
# 处理有嵌套的对象
@dataclass
class SpiderAccountInfo:
"""爬虫账号信息"""
id: str = None
"""分配的爬虫账号ID"""
use: bool = False
"""当次任务是否使用该账号"""
success: bool = False
"""使用账户请求 API 是否成功"""
remark: str = ''
"""备注信息,比如异常信息"""
@dataclass
class TaskResult:
taskId: str = None
"""主任务ID"""
taskRecordId: str = None
"""当前任务ID"""
success: bool = False
"""当前任务执行中是否有错误出现,比如异常信息"""
remark: str = None
"""备注信息"""
spiderAccountInfo: SpiderAccountInfo = None
"""爬虫账户相关信息"""
def to_json_str(self):
"""将对象转换为 json 字符串"""
return json.dumps(self, default=lambda o: o.__dict__, ensure_ascii=False)
@staticmethod
def from_json_str(json_str):
"""将 json 字符串转换为对象"""
json_dict = json.loads(json_str)
return TaskResult(**json_dict)
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
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
下面是测试
def test_task_result():
result = {
"taskId": 1,
"taskRecordId": 1,
"success": False,
"remark": "请求 API 失败",
"spiderAccountInfo": {
"id": 1,
"use": True,
"success": False,
"remark": "请求 API 失败"
}
}
# 从 json 字符串转换为对象
data: TaskResult = TaskResult.from_json_str(json.dumps(result))
print(data)
if __name__ == '__main__':
test_task_result()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
也就是说,一个 dict 对象,可以通过 TaskResult(**json_dict)
这种方式,直接赋值
WARNING
需要注意的是:如果给定一个该类不存在的字段,就会报错:TypeError: init() got an unexpected keyword argument 'taskId2'