JL *_*ret 6 python type-hinting mypy
我有一个属性,每个实例仅计算一次,并None用作保护值。这是带有属性的非常常见的模式。
注释的最佳方法是什么?
这个问题是关于如何使用mypy来验证我物业的代码。与如何重构代码无关。作为非可选的int,属性的类型就是我想要的方式。例如,假设下游代码将执行print(book.the_answer+1)。
不正确的字符串分配和None完全是为了破坏按物业期望定义的合同,我希望mypy对其进行标记。
class Book:
def __init__(self, title):
self.title = title
_the_answer = None #line 6
# _the_answer : int = None #line 7
def __str__(self):
return "%s => %s" % (self.title, self.the_answer)
@property
def the_answer(self)->int:
"""always should be an int. Not an Optional int"""
if self._the_answer is None:
if "Guide" in self.title:
#this is OK
self._the_answer = 42
elif "Woolf" in self.title:
#this is wrong, mypy should flag it.
self._the_answer = "?, I haven't read it" # line 21
else:
#mypy should also flag this
self._the_answer = None #line 24
return self._the_answer #line 26
print(Book("Hitchhiker's Guide"))
print(Book("Who's afraid of Virginia Woolf?"))
print(Book("War and Peace"))
Run Code Online (Sandbox Code Playgroud)
输出:
Hitchhiker's Guide => 42
Who's afraid of Virginia Woolf? => ?, I haven't read it
War and Peace => None
Run Code Online (Sandbox Code Playgroud)
Mypy的输出:
test_prop2.py:21: error: Incompatible types in assignment (expression has type "str", variable has type "Optional[int]")
test_prop2.py:26: error: Incompatible return value type (got "Optional[int]", expected "int")
Run Code Online (Sandbox Code Playgroud)
第26行实际上并没有错,这完全取决于IF中分配的内容。21和24都不正确,但是mypy仅捕获21。
注意:如果我将属性更改为return,return cast(int, self._the_answer) #line 26则至少将其保留。
如果将类型添加到保护值中,请执行以下操作_the_answer:
class Book:
def __init__(self, title):
self.title = title
#_the_answer = None
_the_answer : int = None #line 7
def __str__(self):
return "%s => %s" % (self.title, self.the_answer)
@property
def the_answer(self)->int:
"""always should be an int. Not an Optional int"""
if self._the_answer is None:
if "Guide" in self.title:
#this is OK
self._the_answer = 42
elif "Woolf" in self.title:
#this is wrong. mypy flags it.
self._the_answer = "?, I haven't read it" # line 21
else:
#mypy should also flag this
self._the_answer = None #line 24
return self._the_answer #line 26
print(Book("Hitchhiker's Guide"))
print(Book("Who's afraid of Virginia Woolf?"))
print(Book("War and Peace"))
Run Code Online (Sandbox Code Playgroud)
运行输出相同,但是mypy具有不同的错误:
test_prop2.py:7: error: Incompatible types in assignment (expression has type "None", variable has type "int")
Run Code Online (Sandbox Code Playgroud)
并且它没有键入检查行21、24和26(实际上它只键入了一次,但是后来我更改了代码,此后没有)。
如果我将第7行更改为_the_answer : int = cast(int, None),则mypy完全保持沉默,并且没有任何警告。
mypy 0.720
Python 3.6.8
Run Code Online (Sandbox Code Playgroud)
经过一夜的睡眠,我得到了解决方案:将打字职责与看守职责分开。
\n\n保护变量self/cls._the_answer是无类型的。
在第 15 行,在告诉我实例尚未计算该属性的保护条件下,我键入提示一个新变量名称answer。
21 和 24 中的两个错误分配现已被标记。
\n\nfrom typing import cast\nclass Book:\n def __init__(self, title):\n self.title = title\n\n _the_answer = None\n\n def __str__(self):\n return "%s => %s" % (self.title, self.the_answer)\n\n @property\n def the_answer(self)->int:\n """always should be an int. Not an Optional int"""\n if self._the_answer is None:\n answer : int #line 15: this is where the typing happens\n if "Guide" in self.title:\n #this is OK \xe2\x9c\x85\n answer = 42\n elif "Woolf" in self.title:\n #this is wrong \xe2\x9d\x8c\n answer = "?, I haven\'t read it" # line 21\n else:\n #mypy should also flag this \xe2\x9d\x8c\n answer = None #line 24\n self._the_answer = answer\n return cast(int, self._the_answer) #line 26\n\nprint(Book("Hitchhiker\'s Guide"))\nprint(Book("Who\'s afraid of Virginia Woolf?"))\nprint(Book("War and Peace"))\nRun Code Online (Sandbox Code Playgroud)\n\n与之前相同的实际运行输出。
\n\n现在,两条问题线都已标记;-)
\n\ntest_prop4.py:21: error: Incompatible types in assignment (expression has type "str", variable has type "int")\ntest_prop4.py:24: error: Incompatible types in assignment (expression has type "None", variable has type "int")\nRun Code Online (Sandbox Code Playgroud)\n\n那么cast第 26 行呢?answer如果if 语句中没有任何赋值怎么办?如果没有cast,我可能会收到警告。我可以像第 15 行那样指定一个默认值吗answer : int = 0?
我可以,但除非确实有一个好的应用程序级默认值,否则我宁愿让事情在执行时立即爆炸(UnboundLocalError在回答时),而不是让 mypy 高兴但不得不追寻一些奇怪的运行时值。
最后一点完全取决于您的应用程序的期望,默认值可能是更好的选择。
\n| 归档时间: |
|
| 查看次数: |
175 次 |
| 最近记录: |