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

时间:2017-07-06 22:31:31

标签: python python-3.x instance-variables conventions type-hinting

不确定类型提示实例变量的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`

链接到上面的代码段: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

最后,在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

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

2 个答案:

答案 0 :(得分:2)

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

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

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

  1. 不再那么直截了当地开始
  2. 的字段
  3. 您的参数与字段之间不再存在一对一的映射
  4. 您有复杂的初始化逻辑,可以模糊字段的分配方式。
  5. 然而,我不清楚第二个版本或第三个版本是否是首选版本 - 我个人更喜欢第三个版本,因为它在概念上更清晰,似乎并没有混合实例与类的概念属性,但我不能否认第二个版本看起来更干净。

    我在打字' 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 :(得分:1)

我坚持使用你在LoggedVar中所做的事情,它遵循与Python中其他地方相同的规则,从而减少了混乱。

BasicStarShip类通过将变量移出__init__函数来更改变量的范围。随着船长宣布,BasicStarShip.captain将返回' Picard'。

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