<p>另一种选择(可能不会像流行的</em>那样<em>)是使用除<code>pydantic</code>之外的反序列化库。例如,Dataclass向导库就是支持此特定用例的库。如果需要<code>Field(alias=...)</code>提供的相同往返行为,可以将<code>all</code>参数传递给<code>json_field</code>函数。请注意,有了这样一个库,您确实失去了执行完整类型验证的能力,这可以说是pydantic最大的优势之一;但是,它会以类似于pydantic的方式执行类型转换。我觉得验证没有那么重要还有一些原因,我在下面列出了这些原因</p>
<p><strong>为什么我会认为数据验证是一个<em>好的</em>
一般功能:</strong></p>
<ul>
<li>如果您自己构建和传递输入,那么您很可能相信您知道自己在做什么,并且正在传递正确的数据类型</李>
<li>如果您从另一个API获得输入,那么假设该API有合适的文档,您可以从它们的文档中获取一个示例响应,并使用该响应来建模您的类结构。如果API清楚地记录了其响应结构,则通常不需要任何验证</李>
<li>数据验证需要时间,因此与只执行类型转换并捕获可能发生的任何错误而不事先验证输入类型相比,数据验证会稍微减慢过程</李>
</ul>
<p>为了证明这一点,这里有一个使用<a href="https://dataclass-wizard.readthedocs.io/" rel="nofollow noreferrer">dataclass-wizard</a>库(依赖于使用<code>dataclasses</code>而不是pydantic模型)的上述用例的简单示例:</p>
<pre class="lang-py prettyprint-override"><code>from dataclasses import dataclass
from dataclass_wizard import JSONWizard, json_field
@dataclass
class TMDB_Category:
name: str = json_field('strCategory')
description: str = json_field('strCategoryDescription')
@dataclass
class TMDB_GetCategoriesResponse(JSONWizard):
categories: list[TMDB_Category]
</code></pre>
<p>运行它的代码如下所示:</p>
<pre class="lang-py prettyprint-override"><code>input_dict = {
"categories": [
{
"strCategory": "Beef",
"strCategoryDescription": "Beef is ..."
},
{
"strCategory": "Chicken",
"strCategoryDescription": "Chicken is ..."
}
]
}
c = TMDB_GetCategoriesResponse.from_dict(input_dict)
print(repr(c))
# TMDB_GetCategoriesResponse(categories=[TMDB_Category(name='Beef', description='Beef is ...'), TMDB_Category(name='Chicken', description='Chicken is ...')])
print(c.to_dict())
# {'categories': [{'name': 'Beef', 'description': 'Beef is ...'}, {'name': 'Chicken', 'description': 'Chicken is ...'}]}
</code></pre>
测量性能</h4>
<p>如果有人好奇的话,我已经设置了一个快速的基准测试来比较pydantic与DataClass的反序列化和序列化时间:</p>
<pre class="lang-py prettyprint-override"><code>from dataclasses import dataclass
from timeit import timeit
from pydantic import BaseModel, Field
from dataclass_wizard import JSONWizard, json_field
# Pydantic Models
class Pydantic_TMDB_Category(BaseModel):
name: str = Field(alias="strCategory")
description: str = Field(alias="strCategoryDescription")
class Pydantic_TMDB_GetCategoriesResponse(BaseModel):
categories: list[Pydantic_TMDB_Category]
# Dataclasses
@dataclass
class TMDB_Category:
name: str = json_field('strCategory', all=True)
description: str = json_field('strCategoryDescription', all=True)
@dataclass
class TMDB_GetCategoriesResponse(JSONWizard):
categories: list[TMDB_Category]
# Input dict which contains sufficient data for testing (100 categories)
input_dict = {
"categories": [
{
"strCategory": f"Beef {i * 2}",
"strCategoryDescription": "Beef is ..." * i
}
for i in range(100)
]
}
n = 10_000
print('=== LOAD (deserialize)')
print('dataclass-wizard: ',
timeit('c = TMDB_GetCategoriesResponse.from_dict(input_dict)',
globals=globals(), number=n))
print('pydantic: ',
timeit('c = Pydantic_TMDB_GetCategoriesResponse.parse_obj(input_dict)',
globals=globals(), number=n))
c = TMDB_GetCategoriesResponse.from_dict(input_dict)
pydantic_c = Pydantic_TMDB_GetCategoriesResponse.parse_obj(input_dict)
print('=== DUMP (serialize)')
print('dataclass-wizard: ',
timeit('c.to_dict()',
globals=globals(), number=n))
print('pydantic: ',
timeit('pydantic_c.dict()',
globals=globals(), number=n))
</code></pre>
<p>以及基准测试结果(在Mac OS Big Sur、Python 3.9.0上测试):</p>
<pre><code>=== LOAD (deserialize)
dataclass-wizard: 1.742989194
pydantic: 5.31538175
=== DUMP (serialize)
dataclass-wizard: 2.300118940
pydantic: 5.582638598
</code></pre>
<p>在他们的文档中,<code>pydantic</code>声称总体上是最快的库,但要证明不是这样很简单。如您所见,对于上述数据集,<code>pydantic</code>在反序列化和序列化过程中大约慢2倍。但值得注意的是<code>pydantic</code>已经相当快了</p>