首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >试着理解PEP 526中的“类和实例变量注释”

试着理解PEP 526中的“类和实例变量注释”
EN

Stack Overflow用户
提问于 2022-12-03 12:30:58
回答 1查看 33关注 0票数 -2

在我看来,在注释类和实例变量的上下文中,我误解了佩普526

基于这里的PEP文档中的示例,对象bar应该是一个具有默认值7的实例变量。

代码语言:javascript
复制
class Foo:
    bar: int = 7
    
    def __init__(self, bar):
        self.bar = bar

但是用Python进行测试对我来说就不一样了。bar是一个类和实例变量。

代码语言:javascript
复制
Python 3.9.10 (tags/v3.9.10:f2f3f53, Jan 17 2022, 15:14:21) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class Foo:
...   bar: int = 7
...   def __init__(self, bar):
...     self.bar = bar
...
>>> Foo.bar
7
>>> f = Foo(3)
>>> f.bar
3
>>> f.__class__.bar
7
>>>

也许PEP不仅仅是清楚的?IMHO - PEP遭到违反,目标没有实现。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-12-03 15:30:58

没有冲突,PEP确实解释了发生了什么。

首先:实例变量只是一个实例上的名称集(通常通过self.[name] = ...),类变量只是一个类上的名称集(通常是通过在class ...语句体中为名称赋值)。--它们不是相互排斥的

您可能缺少的是Python如何在实例上查找名称。当您有一个实例foo并希望获得属性bar时,foo.bar实际上是由为该类定义的代码处理的,因为它需要对更高级的用例(称为描述符)进行一些检查,但是对于正则变量,它将在返回到类变量之前从实例变量返回值。--这是默认值如何工作的--;如果实例上没有设置bar,则使用类的值。

换句话说:类上的实例变量集的默认值只有在不对实例设置值时才起作用:

代码语言:javascript
复制
>>> class Foo:
...     bar: int = 7
...     def __init__(self, bar: int | None):
...         if bar is not None:
...             self.bar = bar
...
>>> f1 = Foo()  # default value for bar
>>> f2 = Foo(3)  # explicit value set
>>> Foo.bar  # default on class
7
>>> f1.bar   # is returned here
7
>>> "bar" in vars(f1)  # as there is no instance variable
False
>>> f2.bar  # gets the instance value
3
>>> vars(f2)["bar"]  # from the instance namespace
3

链接到的部分。讨论了为什么需要为类型检查器注释类变量。他们给出的示例有两个名称,一个是实例属性的默认值,另一个是仅在类上设置的名称。如果没有该类型注释,类型检查器就无法区分这两种情况,因为它们看起来完全相同,否则:

代码语言:javascript
复制
class Starship:
    captain = 'Picard'
    stats = {}

stats dict是在实例之间共享的,因此self.stats = ...将隐藏类变量并中断预期的使用:

stats是一个类变量(跟踪许多不同的游戏统计信息),而captain是一个实例变量,在类中设置了一个默认值。这种差异可能不会被类型检查器看到:两者都在类中初始化,但是captain只是实例变量的一个方便的默认值,而stats实际上是一个类变量--它打算由所有实例共享。

使用ClassVar[...]可以让类型检查器知道创建实例属性应该是一个错误,而分配给self.captain则不是:

由于这两个变量都是在类级别上初始化的,因此通过将类变量标记为带有ClassVar[...]包装的类型的注释来区分它们是非常有用的。通过这种方式,类型检查器可能会将意外分配标记为实例上同名的属性。

请注意,PEP的目的是定义类型注释如何为变量(包括类和实例变量)工作,而不是定义Python变量在运行时如何工作!类型注释被设计为用于静态分析工具的机器可读的文档,并且帮助查找程序员错误。不要试图将此理解为对Python运行时工作方式的描述。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74666784

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档