我正在修改一个应用程序,尝试使用 Pydantic 作为我的应用程序模型,使用 SQLAlchemy 作为我的数据库模型。
我有现有的类,我在
__init__
方法中定义了属性,就像我被教导的那样:
class Measure:
def __init__(
self,
t_received: int,
mac_address: str,
data: pd.DataFrame,
battery_V: float = 0
):
self.t_received = t_received
self.mac_address = mac_address
self.data = data
self.battery_V = battery_V
在 Pydantic 和 SQLAlchemy 中,按照文档,我必须在
__init__
方法之外定义这些属性,例如在 Pydantic 中:
import pydantic
class Measure(pydantic.BaseModel):
t_received: int
mac_address: str
data: pd.DataFrame
battery_V: float
为什么会这样?这不是不好的做法吗?对该类的其他方法(类方法、静态方法、属性...)有任何影响吗?
请注意,这也是 非常不方便 因为当我实例化该类的对象时,我不'无法获得有关构造函数需要哪些参数的建议!
在 SQLAlchemy、Pydantic 和其他类似的库中,属性在
__init__
方法之外定义,主要原因是为了实现
声明式数据定义
以及利用这些库提供的
元编程和数据验证
功能。
为什么不在
__init__
中定义属性?
-
声明式定义更清晰:
将属性定义移到类级别,可以清晰地展现类的结构和预期的数据类型。 这提高了代码的可读性和可维护性,因为一眼就能看出类的属性和类型,而无需深入研究
__init__
方法。 -
元编程和数据验证:
SQLAlchemy 和 Pydantic 利用这些类级别定义来实现强大的功能,例如:
- 数据验证: Pydantic 可以根据类型注解自动验证输入数据,确保数据类型和格式的正确性。
- ORM 映射: SQLAlchemy 使用类属性来映射数据库表结构,自动处理数据库交互。
- 序列化/反序列化: Pydantic 可以轻松地将模型实例序列化为 JSON 或其他格式,并在需要时反序列化回来。
- 性能优势: 在某些情况下,声明式定义可以带来性能优势。例如,Pydantic 在创建实例时可以使用预定义的模型结构,而无需动态创建属性,从而提高效率。
这不是不好的做法吗?
在传统的 Python 类中,将属性定义在
__init__
方法中是标准做法。 然而,对于 SQLAlchemy 和 Pydantic 这样的库,在类级别定义属性是推荐的做法,并且不会被视为不好的做法。 这是因为这些库的设计理念和目标与传统的 Python 类有所不同。
对其他方法的影响:
将属性定义在类级别并不会对其他方法(类方法、静态方法、属性等)产生负面影响。 你仍然可以在这些方法中访问和使用这些属性。
不便之处:
的确,在类级别定义属性可能会导致在实例化对象时缺少 IDE 提示。 然而,现代 IDE 和代码编辑器通常可以识别 Pydantic 和 SQLAlchemy 模型,并提供代码补全和类型提示。 此外,这些库的文档通常非常详细,可以帮助你了解如何正确地实例化对象。
总结:
虽然在
__init__
之外定义属性可能看起来与传统的 Python 代码风格不同,但这是 SQLAlchemy 和 Pydantic 等库实现其强大功能所必需的。 这种做法提供了声明式定义、元编程、数据验证和其他优点,从而提高了代码的可读性、可维护性和功能性。