【发布时间】:2021-11-18 17:19:00
【问题描述】:
我正在使用一些从父类 (Widget) 派生的类;在孩子们中,有些人具有某些属性(posx 和 posy),有些则没有。
import enum
from dataclasses import dataclass
from typing import List
class Color(enum.IntEnum):
GLOWING_IN_THE_DARK = enum.auto()
BROWN_WITH_RAINBOW_DOTS = enum.auto()
@dataclass
class Widget:
"""Generic class for widget"""
@dataclass
class Rectangle(Widget):
"""A Color Rectangle"""
posx: int
posy: int
width: int = 500
height: int = 200
color: Color = Color.BROWN_WITH_RAINBOW_DOTS
@dataclass
class Group(Widget):
children: List[Widget]
@dataclass
class Button(Widget):
"""A clickable button"""
posx: int
posy: int
width: int = 200
height: int = 100
label: str = "some label"
即使只对具有这些属性的小部件进行了一些过滤,mypy 也无法识别它们应该具有。
有没有办法向mypy 表明我们有一个具有给定属性的对象?
例如下面的函数和调用:
def some_function_that_does_something(widgets: List[Widget]):
"""A useful docstring that says what the function does"""
widgets_with_pos = [w for w in widgets if hasattr(w, "posx") and hasattr(w, "posy")]
if not widgets_with_pos:
raise AttributeError(f"No widget with position found among list {widgets}")
first_widget = widgets_with_pos[0]
pos_x = first_widget.posx
pos_y = first_widget.posy
print(f"Widget {first_widget} with position: {(pos_x, pos_y)}")
some_widgets = [Group([Rectangle(0, 0)]), Button(10, 10, label="A button")]
some_function_that_does_something(some_widgets)
会按预期返回结果:Widget Button(posx=10, posy=10, width=200, height=100, label='A button') with position: (10, 10)
但是mypy 会抱怨:
__check_pos_and_mypy.py:53: error: "Widget" has no attribute "posx"
pos_x = first_widget.posx
^
__check_pos_and_mypy.py:54: error: "Widget" has no attribute "posy"
pos_y = first_widget.posy
^
Found 2 errors in 1 file (checked 1 source file)
怎么办?
也许,一种方法是改变类的设计:
-
Widget的子类和位置(例如WidgetWithPos) -
Rectangle和Button将派生自此类 - 我们在函数中注明:
widget_with_pos: List[WidgetWithPos] = ...
...但是,我无法更改课程的原始设计,mypy 可能仍会抱怨以下内容:
List comprehension has incompatible type List[Widget]; expected List[WidgetWithPos]
当然,我们可以放一堆# type:ignore,但这会使代码混乱,我相信有更聪明的方法;)
谢谢!
【问题讨论】:
标签: python type-hinting mypy python-typing duck-typing