【问题标题】:Python typing for base and concrete class (I use base class to list children but what use attributes from concrete class)基类和具体类的 Python 类型(我使用基类列出子类,但使用具体类的属性)
【发布时间】:2022-08-16 22:31:29
【问题描述】:

让我解释一下问题。我对类型提示很有经验(90% 或更多),但这对我来说很难——你能帮忙吗?

  1. 我创建了具有children 属性的基类,其类型为BaseClass
  2. 我创建了继承BaseClass 的具体类,该类具有some_int 额外属性。
  3. 问题是我的来自BaseClass 的类型提示返回set[\'BaseClass\'],所以孩子不能有额外的属性some_int。无论所有孩子都有some_int 属性(都将是具体的类对象)。

    见代码:

    from dataclasses import dataclass
    
    
    @dataclass
    class BaseClass:
        name: str
        children: set[\'BaseClass\']
    
        def add_child(self, child: \'BaseClass\'):
            self.children.add(child)
    
    
    @dataclass
    class ConcreteClass(BaseClass):
        some_int: int
    
        def sum(self):
            # artificial to show problem
            accumulator = 0
            for child in self.children:
                # type hint error!
                # some_int is not exists in BaseClass (what is true)
                accumulator += child.some_int
    

    如何在 Python 中正确表达?

  • 您可以查看if isinstance(child, ConcreteClass),然后添加。
  • 建议与此问题无关。不需要检查类型,但需要编写正确的打字注释。
  • 您是要表达children: set[Self] 还是ConcreteClass 可以将BaseClass 实例作为孩子?在前一种情况下,请参见 PEP673(自我类型)中的 this example,在后一种情况下 - 除了显式保护 if isinstance()assertcast (此处不合适,IMO)外,别无他法。
  • 不知道Self 能做什么,但BaseClass Self 应该是一样的,我认为它不能解决问题。我可能会读 PEP。请记住,鸭子类型是在 Python 中的——我不需要重写这个方法,因为它会起作用。我只需要重写输入:)
  • 鸭子打字意味着如果表现得像鸭子,我确实需要检查鸭子是否是鸭子。

标签: python python-typing


【解决方案1】:

如果您只需要 ConcreteClass 的实例访问该属性,则可以覆盖 children 集的类型提示:

@dataclass
class ConcreteClass(BaseClass):
    some_int: int
    children: set['ConcreteClass']

这意味着ConcreteClass.children 只能包含它自己,这允许类型检查器确定集合的所有元素都必须具有some_int

如果你想要不止一个ConcreteClass,你仍然需要告诉类型检查器它可以确定什么。您可以通过定义BaseClass 也具有属性some_int 或使用Protocol 来做到这一点。协议允许您将鸭子类型引入类型检查器 - 它可以使用协议来检查是否有任何类公开了正确的属性/方法,无论它们继承自什么。

from typing import Protocol

class HasInt(Protocol):
    some_int: int

@dataclass
class BaseClass:
    name: str
    children: set[HasInt]

这告诉类型检查器所有孩子都必须遵循HasInt 协议。类型检查器现在可以允许在children 中使用任何实例,甚至是不相关的类,只要它们都具有 some_int 属性。

【讨论】:

    猜你喜欢
    • 2018-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-02
    相关资源
    最近更新 更多