![](/img/trans.png)
[英]How to declare python dataclass member field same as the dataclass type
[英]How to specify the type of a callable python dataclass member to accept subclass instances
我希望能够指定一个可调用的数据 class 成员,并采用派生 class 的实例。如果我使用抽象成员函数,这将很容易。
我尝试过如下代码,但不知道为 Callable 类型规范提供什么参数。 我正在寻找一种方法来注释handler
属性,以便派生类可以将自己的实例作为handler
(在本例中为Specific
)的参数,而不仅仅是Base
。
@dc.dataclass
class Base():
name: str
handler: typing.Callable[['Base'], str] # <--- What to use instead of 'Base'
@dc.dataclass
class Specific(Base):
specific: str
# This is the callable that I would like to use.
def specific_handler(v: Specific) -> str:
return f"{v.specific}"
# Assigning specific_handler to handler gives a type error.
sg = Specific(name="two", handler=specific_handler, specific="extra info")
# The handler can be used in following manner.
assert("extra info" == sg.handler(sg))
我正在使用 Python 3.7。
解决方案仍然涉及typing.TypeVar
。
只要handler
的第一个参数不接受与拥有的 class 相同类型的参数,那么Base
就必须是通用的(如果它是相同类型,您可以使用typing.Self
来逃避)。 handler
的第一个参数是否是Base
的子类并不重要,这只是您添加到typing.TypeVar(bound=...)
的细节。
import dataclasses as dc
import typing
T = typing.TypeVar("T", bound="Base[typing.Any]")
@dc.dataclass
class Base(typing.Generic[T]):
name: str
handler: typing.Callable[[T], str]
# `Base["Specific"]` assumes that you want `Specific.handler` to be of type `typing.Callable[[Specific], str]`, which is true in this situation.
# Otherwise just provide another subclass of `Base` (or `typing.Any`).
@dc.dataclass
class Specific(Base["Specific"]):
specific: str
def specific_handler(v: Specific) -> str:
return f"{v.specific}"
sg = Specific(name="two", handler=specific_handler, specific="extra info")
assert "extra info" == sg.handler(sg)
虽然@dROOOze 的回答有效,但没有必要冗长(需要重复 class 名称作为通用属性)。 下面的替代解决方案使用typing.Self
(通过typing_extensions
在 python 3.11 上添加,通过typing_extensions向后移植,在mypy
master 上受支持 - 尽管 0.991 仍然缺少此功能)。 所以,如果你可以使用 master mypy
分支或者稍后阅读这个答案,那么mypy 1.0
及以上版本完全支持Self
。
这是一个游乐场。
import sys
from dataclasses import dataclass
from typing import Callable
# You can omit this guard for specific target version
if sys.version_info < (3, 11):
from typing_extensions import Self
else:
from typing import Self
@dataclass
class Base:
name: str
handler: Callable[[Self], str]
@dataclass
class Specific(Base):
specific: str
def specific_handler(v: Specific) -> str:
return f"{v.specific}"
sg = Specific(name="two", handler=specific_handler, specific="extra info")
assert "extra info" == sg.handler(sg)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.