[英]How to type hint builder pattern in Python?
Would like to add type hinting to def make(self):
from in the class AggregateMaker
so that the code in the tests test_fruit
and test_tea
would autocomplete the Fruit
or Tea
methods/properties rather than returning None
想为def make(self):
from in the class AggregateMaker
添加类型提示,以便测试test_fruit
和test_tea
中的代码自动完成Fruit
或Tea
方法/属性,而不是返回None
Is this possible in Python 3.10?这在 Python 3.10 中是否可行?
from dataclasses import dataclass
@dataclass
class Fruit:
name: str
smell: str
@dataclass
class Tea:
name: str
hot: bool
class AggregateMaker():
_fields: dict
@classmethod
def new(cls, **fields):
return cls(fields=None).with_(**fields)
###
# How to type hint in here to return Fruit or Tea?
###
def make(self):
return self._make(self._fields)
def with_(self, **overrides):
copy = dict(self._fields)
for name, value in overrides.items():
copy[name] = value
return type(self)(copy)
class FruitMaker(AggregateMaker):
def __init__(self, fields):
if fields is None:
fields = {
"name": None,
"smell": None,
}
self._fields = fields
def _make(self, fields) -> Fruit:
return Fruit(**fields)
class TeaMaker(AggregateMaker):
def __init__(self, fields):
if fields is None:
fields = {
"name": None,
"hot": None,
}
self._fields = fields
def _make(self, fields) -> Tea:
return Tea(**fields)
def test_fruit():
durian = FruitMaker.new().with_(name="Durian").with_(smell="Strong").make()
assert durian.name == "Durian"
assert durian.smell == "Strong"
assert type(durian) is Fruit
def test_tea():
camomile = TeaMaker.new(name="Camomile", hot=True).make()
assert type(camomile) is Tea
I typed as much of it as I felt was reasonable, but there are still gaps.我尽可能多地输入了我认为合理的内容,但仍然存在差距。
I feel like it'd usually make sense to replace most of this with, like, prototype objects, and calls to dataclasses.replace
.我觉得用原型对象和对dataclasses.replace
的调用来替换其中的大部分通常是有意义的。
(From context elsewhere, I know that isn't practical in the near term.) (从其他地方的情况来看,我知道这在短期内是不切实际的。)
from dataclasses import dataclass
from typing import Any, Generic, Type, TypeVar
T = TypeVar("T")
TMaker = TypeVar("TMaker", bound="AggregateMaker[Any]")
@dataclass
class Fruit:
name: str
smell: str
@dataclass
class Tea:
name: str
hot: bool
class AggregateMaker(Generic[T]):
_fields: dict[str, Any]
def __init__(self, fields: dict[str, Any] | None) -> None:
...
@classmethod
def new(cls: Type[TMaker], **fields: Any) -> TMaker:
return cls(fields=None).with_(**fields)
def make(self) -> T:
return self._make(self._fields)
def _make(self, fields: dict[str, Any]) -> T:
...
def with_(self: TMaker, **overrides: Any) -> TMaker:
copy = dict(self._fields)
for name, value in overrides.items():
copy[name] = value
return type(self)(copy)
class FruitMaker(AggregateMaker[Fruit]):
def __init__(self, fields: dict[str, Any]):
if fields is None:
fields = {
"name": None,
"smell": None,
}
self._fields = fields
def _make(self, fields: dict[str, Any]) -> Fruit:
return Fruit(**fields)
class TeaMaker(AggregateMaker[Tea]):
def __init__(self, fields: dict[str, Any]):
if fields is None:
fields = {
"name": None,
"hot": None,
}
self._fields = fields
def _make(self, fields: dict[str, Any]) -> Tea:
return Tea(**fields)
def test_fruit() -> None:
durian = FruitMaker.new().with_(name="Durian").with_(smell="Strong").make()
assert durian.name == "Durian"
assert durian.smell == "Strong"
assert type(durian) is Fruit
def test_tea() -> None:
camomile = TeaMaker.new(name="Camomile", hot=True).make()
assert type(camomile) is Tea
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.