# 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')
Copied!
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
Copied!
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))
Copied!
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()
Copied!
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 失败" } }
Copied!
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 失败" }
Copied!
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)
Copied!
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()
Copied!
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'