在数据类中创建类变量的正确方法

Kur*_*ine 10 python python-3.x python-dataclasses

我刚刚开始使用 Python 的数据类,我想确认我正在以正确的方式声明类变量。

使用常规的 Python 类

class Employee:

    raise_amount = .05

    def __init__(self, fname, lname, pay):
        self.fname = fname
        self.lname = lname
        self.pay = pay
Run Code Online (Sandbox Code Playgroud)

使用 python 数据类

@dataclass
class Employee:
    fname: str
    lname: str
    pay: int
    raise_amount = .05
Run Code Online (Sandbox Code Playgroud)

我所指的类变量是raise_amount. 这是使用数据类正确声明的类变量吗?或者有更好的方法吗?

我已经测试了数据类实现,它提供了预期的功能,但我主要想知道我的实现是否遵循最佳实践。

Mis*_*agi 18

要创建类变量,请将该字段注释为 atyping.ClassVar或根本不注释。

from typing import ClassVar

@dataclass
class Foo:
    ivar: float = 0.5
    cvar: ClassVar[float] = 0.5
    nvar = 0.5

foo = Foo()
Foo.ivar, Foo.cvar, Foo.nvar = 1, 1, 1
print(Foo().ivar, Foo().cvar, Foo().nvar)   # 0.5 1 1
print(foo.ivar, foo.cvar, foo.nvar)         # 0.5 1 1
Run Code Online (Sandbox Code Playgroud)

有一个细微的区别,未注释的字段被 完全忽略@dataclass,而该ClassVar字段被存储但不转换为属性。


dataclasses — 数据类

成员变量 [...] 是使用 PEP 526 类型注释定义的。

类变量

dataclass()实际检查字段类型的两个地方之一是确定字段是否是 PEP 526 中定义的类变量。它通过检查字段的类型是否为typing.ClassVar. 如果字段是 a ClassVar,则将其作为字段排除在外,并被数据类机制忽略。ClassVar模块级 fields() 函数不会返回 此类伪字段。

  • 值得注意的是,`dataclasses.fields(Foo)`不会显示`cvar`,但它会在`Foo.__dataclass_fields__`中 (3认同)
  • 如果一个变量没有被注释,它会被``dataclass``完全忽略。这实际上也使其成为一个类变量。 (2认同)

Niz*_*med 8

您应该使用typing.ClassVarmypy 注释类变量,以便在通过类实例为类变量赋值时捕获错误。

完全省略注释对 mypy 没有帮助。

from dataclasses import dataclass
from typing import ClassVar


@dataclass
class Class:
    name: ClassVar[str]
    desc = "default description"


instance = Class()
instance.desc = "instance description"
instance.name = "instance name"

Class.name = "class name"
Class.desc = "class description"
Run Code Online (Sandbox Code Playgroud)

Mypy 输出;

error: Cannot assign to class variable "name" via instance
Run Code Online (Sandbox Code Playgroud)