希望在class AggregateMaker
中为def make(self):
添加类型提示,以便测试test_fruit
和test_tea
中的代码将自动完成Fruit
或Tea
方法/属性,而不是返回None
在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
我尽可能多地输入了我认为合理的内容,但仍然有空白。
我觉得用原型对象和对dataclasses.replace
的调用来代替这些通常是有意义的。
(从其他地方的上下文中,我知道这在短期内是不实际的。)
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