不确定类型提示实例变量的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
这些约定中的一个是否比我应该坚持的更好/更广泛接受(更好的可读性等等)?
答案 0 :(得分:2)
我建议您使用第一个版本,在大多数情况下,您可以为__init__
方法的参数指定类型。
该特定方法具有最少的冗余,同时仍允许类型检查器验证您是否在代码中的其他位置正确调用__init__
方法。
我建议使用第二个或第三个版本,当您的__init__
方法变得足够复杂到一个或多个时,您可以明确注释您的字段(__init__
内部或外部)以下适用:
然而,我不清楚第二个版本或第三个版本是否是首选版本 - 我个人更喜欢第三个版本,因为它在概念上更清晰,似乎并没有混合实例与类的概念属性,但我不能否认第二个版本看起来更干净。
我在打字' gitter频道,并得到了Guido的以下回应(他是非常不可能知道的,制作了Python并且目前正致力于mypy并打字相关的东西):
无论如何,似乎都有强烈的意见。我确实更喜欢在类体中放置属性注释,而不是在
__init__
和其他方法中使用它们。我还认为,对于PEP 526,这将是未来(也可以使用基于类的NamedTuple声明,可能还有https://github.com/ericvsmith/dataclasses)。
所以,看起来推荐第二个版本超过第三个版本,并且以这种方式定义类将在未来的某个时候更深入地集成到Python语言本身中!
修改: PEP 557, data classes为recently accepted,似乎在线上(?)包含在Python 3.7中。
答案 1 :(得分:1)
我坚持使用你在LoggedVar中所做的事情,它遵循与Python中其他地方相同的规则,从而减少了混乱。
BasicStarShip类通过将变量移出__init__函数来更改变量的范围。随着船长宣布,BasicStarShip.captain将返回' Picard'。
PEP526注释很好阅读,但它是一个特定情况__init__函数的新规则。来自 Python的禅宗:"特殊情况并不足以打破规则。"