类型提示实例变量Python的约定

hhp*_*ram 9 python conventions instance-variables type-hinting python-3.x

不确定类型提示实例变量的Python约定 - 我一直在__init__构造函数参数中执行它们,如下所示:

class LoggedVar(Generic[T]):
    def __init__(self, value: T, name: str, logger: Logger) -> None:
        self.name = name
        self.logger = logger
        self.value = value`
Run Code Online (Sandbox Code Playgroud)

链接到上面的代码段:https://docs.python.org/3/library/typing.html#user-defined-generic-types

但我也看到PEP约定注释实例变量(下面的代码段),然后在__init__参数中进行类型提示:

class BasicStarship:
    captain: str = 'Picard'               # instance variable with default
    damage: int                           # instance variable without default
    stats: ClassVar[Dict[str, int]] = {}  # class variable`

    def __init__(self, damage: int, captain: str = None):
        self.damage = damage
        if captain:
            self.captain = captain  # Else keep the default
Run Code Online (Sandbox Code Playgroud)

最后,在PEP526文章的后面,他们说为了方便和惯例,可以做以下事情:

class Box(Generic[T]):
    def __init__(self, content):
        self.content: T = content
Run Code Online (Sandbox Code Playgroud)

url以上两个代码片段:https: //www.python.org/dev/peps/pep-0526/#class-and-instance-variable-annotations

那么这些约定中的一个是否比我应该坚持的更好/更广泛接受(更好的可读性等......)?

Gar*_*ary 15

@阿萨拉

似乎从 Python 3.8.10 / Mypy 0.910(2021 年 9 月)开始,当谈到区分类定义中实例变量的类型注释和类定义中类(静态)变量的声明时,分配默认值会产生很大的差异。如果您不指定默认值(例如x: int),Python 会将表达式视为类型注释;如果指定默认值(例如x: int = 42),Python 会将表达式视为类(静态)变量声明。

可以使用ClassVar语法为类定义中的类(静态)变量创建类型注释。如果您不指定默认值(例如),则不会创建y: ClassVar[int]事实类(静态)变量;如果您指定默认值(例如),则会创建一个事实类(静态)变量。y: ClassVar[int] = 69

  • 如果默认值的分配会产生差异,那么为什么在上面的示例(取自 PEP 526)中,分配了默认值“Picard”的“captain”变量被描述为“具有默认值的实例变量”而不是被认为是一个类变量? (4认同)

Mic*_*x2a 11

我建议使用第一个版本,在__init__大多数情况下,您可以为方法的参数分配类型。

该特定方法具有最少的冗余,同时仍允许类型检查器验证您__init__是否在代码的其他地方正确调用了该方法。

我建议使用第二个或第三个版本,__init__当您的__init__方法变得足够复杂到可以应用以下一项或多项时,您可以在其中明确注释您的字段(内部或外部):

  1. 你的字段从什么开始已经不再那么简单了
  2. 您的参数和字段之间不再存在一对一的映射
  3. 你有复杂的初始化逻辑,它掩盖了你的字段是如何分配的。

然而,我不清楚是首选第二个版本还是第三个版本——我个人更喜欢第三个版本,因为它在概念上更清晰,并且似乎没有混合实例与类属性的概念,但我不能否认第二个版本看起来更干净。

我在“打字”gitter 频道上询问了这个问题,并得到了 Guido 的以下回复(在你不知道的情况下,他制作了 Python,目前正在研究 mypy 并输入相关内容):

无论哪种方式,似乎都有强烈的意见。我确实更喜欢将属性注释放在类主体中,而不是将它们散布在整个__init__和其他方法中。我还认为 PEP 526 这将是未来(还有基于类的 NamedTuple 声明和可能的https://github.com/ericvsmith/dataclasses)。

引用链接

因此,似乎推荐使用第二个版本而不是第三个版本,并且以这种方式定义类将在将来的某个时候更深入地集成到 Python 语言本身中!

编辑: PEP 557,数据类最近接受(?),似乎是在赛道上被包括在Python 3.7。