-
Notifications
You must be signed in to change notification settings - Fork 207
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
215 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -87,6 +87,7 @@ module.exports = () => { | |
'others/018.md', | ||
'others/019.md', | ||
'others/020.md', | ||
'others/021.md', | ||
] | ||
} | ||
] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
# python-面向对象 - class | ||
> 本文精选:https://www.yuque.com/mrcode.cn/note-combat/nv62kvczbzugm545 | ||
## 如何定义 class | ||
在 Python 3.7 以前,需要这样写 | ||
```python | ||
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') | ||
``` | ||
在 Python 3.7+ ,可以使用 `@dataclass` 帮我们实习上面的效果,可以这样写,更方便 | ||
|
||
```python | ||
from dataclasses import dataclass | ||
|
||
@dataclass | ||
class TaskDemo: | ||
a: str | ||
b: str | ||
c: str = None | ||
``` | ||
## 如何让一个 json 字符串变成类实例呢? | ||
### object_hook 无嵌套对象反序列化 | ||
下面有一个例子 | ||
```python | ||
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)) | ||
``` | ||
下面是测试 | ||
```python | ||
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() | ||
|
||
``` | ||
文档注释的效果如下: | ||
![image.png](https://cdn.nlark.com/yuque/0/2024/png/651749/1715146290743-bf8e34c2-f31b-465a-91ca-76d599f0bdaa.png#averageHue=%23f7f7f7&clientId=u23ce6831-ae8e-4&from=paste&height=120&id=u7b4a0ab8&originHeight=221&originWidth=577&originalType=binary&ratio=2&rotation=0&showTitle=false&size=35696&status=done&style=none&taskId=uc8361871-28a0-42d5-8f0e-e28af64fefb&title=&width=312.5) | ||
:::warning | ||
需要注意的是:这种方式只适合没有嵌套对象的方式 | ||
::: | ||
因为 object_hook 是遇到对象就回调,如果是嵌套对象就不行了,比如下面这种 | ||
```python | ||
result = { | ||
"taskId": 1, | ||
"taskRecordId": 1, | ||
"success": False, | ||
"remark": "请求 API 失败", | ||
"spiderAccountInfo": { | ||
"id": 1, | ||
"use": True, | ||
"success": False, | ||
"remark": "请求 API 失败" | ||
} | ||
} | ||
``` | ||
他的解析方式如下: | ||
|
||
1. 先拿 spiderAccountInfo 的值,也就是这个对象,去调用一次 object_hook | ||
2. 再用 根 对象去调用一次 object_hook | ||
|
||
因为在调用的时候,参数就是对象,比如 | ||
```python | ||
{ | ||
"id": 1, | ||
"use": True, | ||
"success": False, | ||
"remark": "请求 API 失败" | ||
} | ||
``` | ||
所以你就没法知道这个对象对应的字段是什么,在本例中是 spiderAccountInfo 的值,所以你就没有办法实现 | ||
### 处理有嵌套的对象 | ||
```python | ||
@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) | ||
``` | ||
下面是测试 | ||
```python | ||
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() | ||
``` | ||
也就是说,一个 dict 对象,可以通过 `TaskResult(**json_dict)` 这种方式,直接赋值 | ||
:::warning | ||
需要注意的是:如果给定一个该类不存在的字段,就会报错:TypeError: __init__() got an unexpected keyword argument 'taskId2' | ||
::: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters