python - python 属性设置器参数的类型注释应该是什么?
问题描述
python 是否对属性设置器参数的PEP-484类型注释有立场?我看到两个选项,这两个选项似乎都有效(根据我和 mypy)。
考虑:
from dataclasses import dataclass
from typing import Any
@dataclass
class Foo:
_bar: int = 1
@property
def bar(self) -> int:
return self._bar
@bar.setter
def bar(self, value) -> None:
self._bar = value
问题是:
应该用
@bar.setter
还是用value
键入参数?typing.Any
int
一方面,在 setter 中,具有预期的类型提示对于执行验证会很好,但另一方面,传入的值可以是任何类型。
不过要注意一件事;mypy确实会警告对属性设置器的错误分配:
f = Foo()
f.bar = 2 # Ok
f.bar = "baz" # Incompatible types in assignment (expression has type "str", variable has type "int")
我相信这来自于作为 a 的揭示类型,Foo.bar
而int
不是来自 的value
论点的类型@bar.setter
。
我在python/cpython和python/typeshed项目中搜索了示例,但没有找到任何确定的内容。
我对现代 python 非常有经验,并且很乐意阅读 cpython 源代码(无论是 C 还是 python 本身)。引用 PEP 或包含来自 cpython 或 mypy 维护者的输入的答案将是理想的。
解决方案
这个问题非常适合基于强烈的意见,但是,我认为对于使用预期类型(即def bar(self, value: int) -> None:
)注释的突变器可能有更强有力的论据。首先,实现注释是为了帮助静态分析,而不是提供任何真正的运行时好处(据我所知,它们目前没有。来自PEP 484 基本原理:
在这些目标中,静态分析是最重要的。这包括对离线类型检查器(如 mypy)的支持,以及提供可供 IDE 用于代码完成和重构的标准符号。
如果类型注释主要用于静态分析、linting 等,那么您希望能够检查是否传入了错误的类型而不是在运行时发现您没有正确处理参数是有意义的例如使用类型检查isinstance
。
这也意味着我们可以事半功倍,因为更具体的int
注释将消除我们添加这些类型保护的需要:
def bigger_fun(n: Any) -> None:
if isinstance(n, float):
# do something...
else
# dosomething else...
def smaller_fun(n: int) -> None:
# do something
您将确切地知道您将收到什么类型以及如何处理它,而不是需要实现不同的多个条件分支来首先将参数转换为预期值,然后再对其进行操作。这将允许您使用最少的内部逻辑/处理使您的 mutators 尽可能苗条。
例如,如果您要传递错误的类型,您的 IDE 或静态分析工具至少会在传递 a 时警告float
您smaller_fun
。另一方面,Any
对于某些类型,使用可能会产生意想不到的行为,这会引入难以追踪的运行时错误。
现在更具体地说是您的问题,同一个 PEP 在@property
注释的含义中涉及注释的使用
预计类型检查器会尝试推断出尽可能多的信息。最低要求是处理内置装饰器@property、@staticmethod 和@classmethod。
这意味着您可以期望@property
注释应该像您期望的那样正常运行。无需任何特殊处理。
虽然 python 本质上是一种动态类型语言,但像 mutator 这样的方法与特定值(以及类型)密切相关,应该只做一件事而不是多件事中的一件。因此,虽然它可能会为像 之类的比较方法__gt__
(它可能会为不同类型执行不同的操作)获取一个Any
值,但一个 mutator 应该采用尽可能窄的范围。
最后,尽管类型提示不是并且可能永远不应该是强制性的,但所有最流行的 Python IDE(例如 Pycharm)都会自动支持类型提示。即使其他程序员可能没有注释类型,它们也会经常发出警告,但可以安全地推断出类型。这意味着即使在使用带有类型提示的库时,带有int
注解的变异器对于最终用户来说仍然比注解提供更多的信息和有用的信息Any
。
推荐阅读
- php - 我想查看product_name。错误是 - 此集合实例上不存在属性 [product_name]。(abc.blade.php)
- vue.js - 如何向 vuepress 博客添加语法高亮?
- java - Bukkit:getInstance 为空
- python - 多个客户的IP地址交易列表数据以表格形式给出。开发一个程序在python中计算
- flutter - Flutter 使用 workmanager 在准确时间显示本地通知
- r - 使用 dplyr 和管理列值
- linux - Shell脚本用一个值替换所有出现的字符串
- java - 在我的实体中计算休眠中的过程或查询
- networking - 我怎样才能找到每两个小时的往返延误的平均值?
- python - 确保在夜间进行模拟时不会中断模拟(Windows 10)