H1DDENADM1N / H1DDENADM1N.github.io

0 stars 0 forks source link

简述 enum.Enum、dataclasses.dataclass(frozen=True)、pydantic.BaseModel 使用场景区别,并举例说明 #7

Open H1DDENADM1N opened 4 months ago

H1DDENADM1N commented 4 months ago
import datetime
from dataclasses import dataclass
from datetime import datetime
from enum import Enum

from pydantic import BaseModel

# enum.Enum
# 使用场景:
#     当你需要定义一组具有唯一性的命名常量时,例如状态码、选项值或具有特定意义的符号。
#     用于表示一组互斥的选项或类型。
class StatusCode(Enum):
    SUCCESS: int = 200
    NOT_FOUND: int = 404
    SERVER_ERROR: int = 500

# 使用
print(StatusCode.SUCCESS.name)  # SUCCESS
print(StatusCode.SUCCESS.value)  # 200
# StatusCode.SUCCESS = 2333  # AttributeError: cannot reassign member 'SUCCESS'

status = StatusCode.SUCCESS
print(status.name)  # SUCCESS
print(status.value)  # 200

# status.value = 2333  # AttributeError: <enum 'Enum'> cannot set attribute 'value'
# print(status.value)

# dataclasses.dataclass(frozen=True)
# 使用场景:
#     当你需要创建轻量级的数据容器,特别是当类的主要目的是存储数据而不是提供方法时。
#     用于定义记录或实体,其中数据在创建后不应被修改。
@dataclass(frozen=True)
class Point:
    x: int = 0
    y: int = 0

# 使用
print(Point.x)  # 0
print(Point.y)  # 0
Point.x = (
    2333  # 这里你试图修改类字段,这是可以的,因为类字段是静态的,不会影响实例的状态。
)
print(Point.x)  # 2333

p1 = Point()
print(p1.x)  # 0 因为实例字段没有创建副本,所以它们是静态的
print(p1.y)  # 0

p2 = Point(x=1, y=2)
print(p2.x)  # 1
print(p2.y)  # 2
# p2.x = 3  # dataclasses.FrozenInstanceError: cannot assign to field 'x'
# print(p2.x)

p3 = Point(
    x="not a number", y="not a number"
)  # dataclass 没有动态类型检查,所以这里不会报错
print(p3.x)  # not a number
print(p3.y)  # not a number

# pydantic.BaseModel
# 使用场景:
#     用于数据验证和设置类型注解,特别是在Web应用程序和服务中,需要确保输入数据的有效性和类型安全。
#     当你需要自动将输入数据转换为正确的类型,并提供详细的错误信息时。

class User(BaseModel, frozen=True):
    name: str = "name"
    age: int = 0

# 使用
# print(User.name)  # raise AttributeError(item)
# print(User.age)  # raise AttributeError(item)

user = User(name="Alice", age=30)
print(user.name)
print(user.age)

# 尝试修改age字段,这将引发异常,因为模型是不可变的
# user.age = "thirty"  # raise pydantic_core.ValidationError.from_exception_data(self.__class__.__name__, [error])  pydantic_core._pydantic_core.ValidationError: 1 validation error for User age
# print(user.age)

# user = User(name="Bob", age="not a number")  # pydantic_core._pydantic_core.ValidationError: 1 validation error for User age  Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='not a number', input_type=str]    For further information visit https://errors.pydantic.dev/2.8/v/int_parsing
# print(user.age)
# print(user.name)

# 同时使用enum.Enum、dataclasses.dataclass和pydantic.BaseModel
# 使用enum.Enum定义文章状态
import enum
from dataclasses import dataclass, field

from pydantic import BaseModel

# 使用enum.Enum定义文章状态
class ArticleStatus(enum.Enum):
    DRAFT = "draft"
    PUBLISHED = "published"
    ARCHIVED = "archived"

# 使用pydantic.BaseModel定义文章元数据
class ArticleMetadata(BaseModel):
    title: str = "title"
    content: str = "content"
    author: str = "author"
    status: ArticleStatus = ArticleStatus.DRAFT

# 使用dataclasses.dataclass定义文章
@dataclass(frozen=True)
class Article:
    id: int = 0
    metadata: ArticleMetadata = field(default_factory=lambda: ArticleMetadata())
    create_datetime: datetime = datetime.now()

# 使用
# 创建文章元数据实例
metadata = ArticleMetadata(
    title="Python学习笔记",
    content="笔记内容",
    author="user0",
    status=ArticleStatus.PUBLISHED,
)

# metadata2 = ArticleMetadata(
#     title=2333,  # ❗ not a string
#     content="笔记内容",
#     author="user0",
#     status=ArticleStatus.PUBLISHED,
# )  # 🤢 pydantic_core._pydantic_core.ValidationError: 1 validation error for ArticleMetadata

# 创建文章实例
article = Article(id=1, metadata=metadata)

# 打印文章信息
print(f"Article ID: {article.id}")
print(f"Article Title: {article.metadata.title}")
print(f"Article Content: {article.metadata.content}")
print(f"Article Author: {article.metadata.author}")
print(f"Article Status: {article.metadata.status.value}")
print(f"Article Create Time: {article.create_datetime}")

# article.id = 2333  # 🤢 dataclasses.FrozenInstanceError: cannot assign to field 'id'
article.metadata.title = "JAVA学习笔记"  # 这里可以修改,因为BaseModel未设置frozen=True
article.metadata.content = (
    "笔记内容笔记内容笔记内容"  # 这里可以修改,因为BaseModel未设置frozen=True
)
article.metadata.author = "user1"  # 这里可以修改,因为BaseModel未设置frozen=True
article.metadata.status = (
    ArticleStatus.ARCHIVED
)  # 这里可以修改,因为BaseModel未设置frozen=True
# article.metadata.status.value = "archived"  # 🤢 raise AttributeError(AttributeError: <enum 'Enum'> cannot set attribute 'value'
# article.create_datetime = datetime(
#     2024, 1, 1, 0, 0, 0
# )  # 🤢 dataclasses.FrozenInstanceError: cannot assign to field 'create_datetime'

# 打印文章信息
print(f"Article ID (frozen dataclass, 不能修改): {article.id}")
print(
    f"Article Title (pydantic.BaseModel 未设置frozen=True, 可以修改): {article.metadata.title}"
)
print(
    f"Article Content (pydantic.BaseModel 未设置frozen=True, 可以修改): {article.metadata.content}"
)
print(
    f"Article Author (pydantic.BaseModel 未设置frozen=True, 可以修改): {article.metadata.author}"
)
print(
    f"Article Status (enum.Enum status.value不能修改, 但是status可以改变): {article.metadata.status.value}"
)
print(f"Article Create Time (frozen dataclass, 不能修改): {article.create_datetime}")