5

不确定Python的约定类型暗示的实例变量 - 我一直在__init__构造函数的参数内做他们喜欢在这里看到:类型提示公约实例变量的Python

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

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

但我也看到注释实例变量的__init__参数内的PEP约定等(以下片段),然后还做类型提示:

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 

最后,后来就PEP526文章中,他们说可以做的方便和约定如下:

class Box(Generic[T]): 
    def __init__(self, content): 
     self.content: T = content 

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

那么,这些公约之一比我应该尝试坚持的其他更好/更广泛接受(更好的可读性等)?

+0

直到现在我还没有意识到PEP 526;谢谢。 – chepner

+0

为什么在第二个例子中是'captain'和'damage'实例变量?他们也不是类变量吗?或者事实是,它们在init方法中被改变,使它们成为实例变量?如果我有一个列表,并用'list.append()'改变它,那么所有实例都会共享这个改变,所以它仍然是一个类变量。 – Asara

回答

1

对于大多数情况,我会推荐使用第一个版本,其中将类型分配给__init__方法的参数。

该特定方法的冗余度最小,同时仍允许类型检查程序验证您是否在代码中的其他地方正确调用了该方法__init__

我会建议使用第二个或第三个版本,在那里你明确注释的字段(内部或外部__init__)当你__init__方法已发展足够复杂到这个地步的一个或多个以下应用:

  1. 它不再那么简单,究竟你们的田地,开始与
  2. 现在,已经没有你的参数和你的域之间的一个一对一的映射
  3. 您有掩盖了怎样的田地,在复杂的初始化逻辑分配。

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

我在'打字'gitter频道上询问了这个问题,并得到了Guido的回复(谁是你不知道的机会制作了Python并且目前正在开发mypy并打字相关的东西) :

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

link to quote

所以,好像建议在第三的第二个版本,并在该方式定义类将更加深入地集成到Python语言本身在未来的某一时刻!

编辑:PEP 557, data classesrecently accepted并且似乎在轨道(?)将包含在Python 3.7中。

1

我会坚持你在LoggedVar中做的事情,它遵循与Python中其他任何地方相同的规则,所以不会陷入混乱。

BasicStarShip类通过将它们移出__init__函数来更改变量的范围。随着队长宣布BasicStarShip.captain将返回'皮卡尔'。

PEP526注释很好阅读,但它是一个特定情况下的新规则,即__init__函数。来自Python的禅宗“特殊情况不足以打破规则。”