英文:
Duck Typing Annotations in Python3
问题
我试图为一个具有与另一个dataclass
重叠属性的函数输入参数添加类型注释,实际上将其作为输入参数传递。
考虑以下代码:
from dataclasses import dataclass
from typing import TypeVar
@dataclass
class Foo:
a: str
zar: str
@dataclass
class Car(Foo):
b: str
@dataclass
class CarInterface:
a: str
b: str
mar = TypeVar("mar", bound=CarInterface)
def blah(x: mar):
print(x.a)
car_instance = Car(a="blah blah", zar="11", b="bb")
blah(car_instance)
在这个示例中,我尝试创建自己的类型注释mar
,它受CarInterface
的限制。我希望检查传递给blah()
的任何类至少具有a
和b
属性(不关心类是否具有其他属性,如zar
)。我之所以这样做,是因为类Car
(实际传递的类)将来将是许多将被编写并传递给这个函数的类之一。
我还希望很容易定义一个新的Car
,因此我希望避免抽象类,因为我认为增加复杂性不值得让mypy满意。
因此,我尝试创建mar
,它使用鸭子类型来表示Car
符合CarInterface
的接口。
然而,我遇到了两个mypy错误。
第一个错误出现在def blah
中的mar
注释处
TypeVar "mar" appears only once in generic function signature
另一个错误是我将car_instance
传递给blah()
的地方
Argument of type "Car" cannot be assigned to parameter "x" of type "bar@blah" in function "blah"
Type "Car" cannot be assigned to type "CarInterface"
"Car" is incompatible with "CarInterface"
英文:
I am trying to add a type annotation to a function input argument that is a dataclass
with attributes that overlap with another dataclass
, which actually gets passed in as an input argument.
Consider the following code:
from dataclasses import dataclass
from typing import TypeVar
@dataclass
class Foo:
a: str
zar: str
@dataclass
class Car(Foo):
b: str
@dataclass
class CarInterface:
a: str
b: str
mar = TypeVar("mar", bound=CarInterface)
def blah(x: mar):
print(x.a)
car_instance = Car(a="blah blah", zar="11", b="bb")
blah(car_instance)
In this example, I'm trying to create my own type annotation mar
which is bound by CarInterface
. I want to check that whatever class is passed into blah()
at least has a
and b
attributes (don't care if the class has other attributes such as zar
). I want to do it this way because class Car
(which actually gets passed in) is one of many classes that will be written in the future and passed into this function.
I also want it to be very easy to define a new Car
, so I would like to avoid abstract classes as I don't think the added complexity is worth mypy being happy.
So I'm trying to create mar
which uses duck typing to say that Car
satisfies the interface of CarInterface
.
However, I get two mypy errors.
The first is on the mar
annotation in def blah
TypeVar "mar" appears only once in generic function signaturePylancereportInvalidTypeVarUse
And the other is where I pass car_instance
into blah()
Argument of type "Car" cannot be assigned to parameter "x" of type "bar@blah" in function "blah"
Type "Car" cannot be assigned to type "CarInterface"
"Car" is incompatible with "CarInterface"PylancereportGeneralTypeIssues
答案1
得分: 4
使用Protocol
来定义CarInterface
而不是dataclass
:
from dataclasses import dataclass
from typing import Protocol
@dataclass
class Foo:
a: str
zar: str
@dataclass
class Car(Foo):
b: str
class CarInterface(Protocol):
a: str
b: str
def blah(x: CarInterface):
print(x.a)
car_instance = Car(a="blah blah", zar="11", b="bb")
blah(car_instance)
上述代码将进行类型检查,但是如果你尝试传递给blah
一个Foo
而不是Car
,你将得到一个mypy错误,类似于:
test.py:22: error: Argument 1 to "blah" has incompatible type "Foo"; expected "CarInterface"
test.py:22: note: "Foo" is missing following "CarInterface" protocol member:
test.py:22: note: b
Found 1 error in 1 file (checked 1 source file)
Protocol
可以被用作TypeVar
的约束,但只有在你想要表明两个变量不仅实现了协议,而且还是相同特定类型时才需要使用TypeVar
(例如,表明函数接受任何实现了CarInterface
的对象,并返回完全相同类型的对象,而不是其他任意的CarInterface
实现)。
英文:
Use a Protocol
to define CarInterface
rather than a dataclass
:
from dataclasses import dataclass
from typing import Protocol
@dataclass
class Foo:
a: str
zar: str
@dataclass
class Car(Foo):
b: str
class CarInterface(Protocol):
a: str
b: str
def blah(x: CarInterface):
print(x.a)
car_instance = Car(a="blah blah", zar="11", b="bb")
blah(car_instance)
The above code will typecheck fine, but if you try to pass blah
a Foo
instead of a Car
you'll get a mypy error like this:
test.py:22: error: Argument 1 to "blah" has incompatible type "Foo"; expected "CarInterface"
test.py:22: note: "Foo" is missing following "CarInterface" protocol member:
test.py:22: note: b
Found 1 error in 1 file (checked 1 source file)
A Protocol
can be used as the bound for a TypeVar
, but it's only necessary to use a TypeVar
if you want to indicate that two variables not only implement the protocol but are also the same specific type (e.g. to indicate that a function takes any object implementing CarInterface
and returns the same exact type of object rather than some other arbitrary CarInterface
implementation).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论