在 __init__ 中更改时,python 类变量可以成为实例变量吗? [英] Can python class variables become instance variables when altered in __init__?

查看:23
本文介绍了在 __init__ 中更改时,python 类变量可以成为实例变量吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

据我所知,var 是一个 类变量:

As far as I understand var is a class variable here:

class MyClass:
    var = 'hello'

    def __init__(self):
        print(self.var)

这是一个实例变量:

class MyClass:

    def __init__(self, var):
        self.var = var
        print(self.var)

我遇到了问题,我正在寻找一种方法来为实例变量提供类型提示.我当然可以用 def __init__(self, var: str): 提示参数,但这不会影响实例变量本身.

I had the problem, that I was looking for a method to make type hinting possible for instance variables. I can of course typehint the parameter with def __init__(self, var: str): but that would not effect the instance variable itself.

然后我在一些描述中注意到(比如这里)他们使用术语实例变量来表示这样的var:

Then I noticed in some descriptions (like here) that they used the term instance variable for a var like this:

class MyClass:
    var : str = 'hello'

    def __init__(self, var : str = None):
        self.var = var if var
        print(self.var)

这确实是解决方案,但这仍然是一个实例变量吗?因为它是在类主体中定义的,所以在我的理解中它将是一个 类变量.如果您要为 var 使用列表,则对该列表变量的所有更改都将通过实例共享.

That would be the solution indeed, but is that still an instance variable? Because it is defined in the class body, it would be a class variable in my understanding. If you would use a list for var, all alterations to this list-var would be shared over the instances.

但是在这种情况下不会有问题,因为字符串被替换并且不会被其他实例共享.但是,如果您将其称为实例变量,这对我来说似乎是错误的,而且我不知道是否应该像这样使用它只是为了让类型提示起作用.

But in this case there would be no problem, because the string is replaced and would not be shared for other instances. However, it seems wrong to me if you call it an instance variable and I don't know if I should use it like this just to have the type hinting working.

推荐答案

这确实是解决方案,但这仍然是一个实例变量吗?因为它是在类体中定义的,所以在我的理解中它将是一个类变量.[...snip...] 但是,如果您将其称为实例变量,我认为这似乎是错误的,而我不知道是否应该像这样使用它只是为了让类型提示起作用.

That would be the solution indeed, but is that still an instance variable? Because it is defined in the class body, it would be a class variable in my understanding. [...snip...] However, it seems wrong to me if you call it an instance variable and I don't know if I should use it like this just to have the type hinting working.

就其价值而言,我也有同样的不适.似乎我们在概念上混合了两个概念,只是为了获得更清晰的类型注释.

For what it's worth, I also share the same discomfort. It seems like we're conceptually mixing two concepts there just for the sake of having cleaner type annotations.

但是,我已经问过 Guido 一两次了,他似乎确实更喜欢将这些类属性视为实例属性.

However, I've asked Guido one or two times about this, and it seems like he does indeed prefers treating those class attributes as if they were instance attributes.

无论如何,如果我们这样做,要回答您的核心问题:

In any case, to answer your core question, if we do this:

class Test:
    field1: int
    field2: str = 'foo'

那么……

  1. 符合 PEP 484 和 526 标准的类型检查器将把此类视为:
  1. PEP 484 and 526 compliant type checkers will treat this class as if:
  1. 它有一个名为 field1
  2. 的实例属性
  3. 它有一个名为 field2 的实例属性,其默认值为foo"(根据 PEP 526).
  1. It has an instance attribute named field1
  2. It has an instance attribute named field2 that has a default value of 'foo' (as per PEP 526).

  • 在运行时,忽略类型提示,Python 将:

  • At runtime, ignoring type hints, Python will:

    1. 将名为 field1 的类注释添加到测试,但不是属性.(类注释不会自动转换为类属性.)
    2. 将名为 field2 的类 annotation 和名为 field2 的类 attribute 添加到 Test值'富'.
    1. Add a class annotation named field1 to Test, but not a class attribute. (Class annotations are not automatically turned into class attributes.)
    2. Add both a class annotation named field2 to Test as well as a class attribute named field2 containing the value 'foo'.

  • 所以,它可能会有点混乱.

    So, it can get a bit muddled.

    但无论如何,这引出了一个问题:我们如何向类型检查器表明我们希望某个字段真正成为类属性?

    But regardless, this then begs the question: how do we indicate to a type checker that we want some field to genuinely be a class attribute?

    好吧,事实证明 PEP 484 最近被修改为包含 ClassVar 类型注解,正是如此.

    Well, it turns out PEP 484 was amended semi-recently to contain the ClassVar type annotation, which does exactly that.

    所以,如果我们想添加一个新的类属性,我们可以这样做:

    So, if we wanted to add a new class attribute, we could do this:

    from typing import ClassVar
    
    class Test:
        field1: int
        field2: str = 'foo'
        field3: ClassVar[int] = 3
    

    所以现在,field3 应该被视为一个类属性,默认值为3".

    So now, field3 should be treated as a class attribute with a default value of '3'.

    (注意:ClassVar 已添加到 Python 3.5.3 的 typing -- 如果您使用的是与 Python 3.5 捆绑的旧版 typing,您可以获得通过 pip 安装 typing_extensions 第三方模块并从那里导入 ClassVar 来替代该类型的反向移植".)

    (Note: ClassVar was added to typing for Python 3.5.3 -- if you're using the older version of typing bundled with Python 3.5, you can get a "backport" of the type by installing the typing_extensions third part module via pip and importing ClassVar from there instead.)

    我认为您决定接受还是不使用这种方法是个人偏好.

    I think whether you decide to embrace this approach or not use it is a personal preference.

    一方面,Guido 的观点几乎根据定义定义了Pythonic"与否,所以从这个立场来看,采用这个新的习语是没有问题的.此外,语言本身正在缓慢但肯定地转向采用这种新的习语——请参阅最近接受的 PEP 557,例如,它最终遵循相同的习惯用法,将类属性/类注释视为实例属性.

    On one hand, Guido's opinion, pretty much by definition, defines what's "Pythonic" or not, so from that stance, there's no issue adopting this new idiom. Furthermore, the language itself is slowly but surely shifting to adopt this new idiom -- see the very recently accepted PEP 557, for example, which ends up following this same idiom of treating class attributes/class annotations as instance attributes.

    另一方面,人们对这种细微差别会导致问题的担忧难以摆脱.在这种情况下,您可以坚持只在 __init__ 中设置所有字段的标准方法.这种方法还具有使您的代码与 Python 2 和 3.x - 3.5 兼容的好处.

    On the other hand, it's difficult to shake off the nagging worry that this subtle difference will lead to issues down the line. In that case, you could stick with the standard approach of just setting all your fields inside __init__. This approach also has the benefit of keeping your code compatible with Python 2 and 3.x - 3.5.

    一个中间立场可能是从不以任何方式、形状或形式使用类属性,而只坚持使用类注释.这有点限制,因为我们不能再给我们的实例变量默认值,但我们现在可以避免将类属性与实例属性完全混淆.(如前所述,并在评论中指出,类注释不会作为类属性添加.)

    A middle ground might be to just simply never use class attributes, in any way, shape, or form, and just stick to using class annotations. This is slightly restrictive, since we can no longer give our instance variables default values, but we can now avoid conflating class attributes with instance attributes entirely. (As previously stated, and as pointed out in the comments, class annotations are not added as class attributes.)

    这篇关于在 __init__ 中更改时,python 类变量可以成为实例变量吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆