【问题标题】:How can two python classes declare references each other and itself?两个 python 类如何声明彼此和自身的引用?
【发布时间】:2021-10-05 11:36:49
【问题描述】:

这是一个非常基本的问题,实际上是两个问题合二为一。对于这两个问题来说,展示我的 Python 绿意的希望非常简单的答案可能是相同的。

以下代码有两个问题:

  • A 类a:A=A() 创建一个NameError,因为A 类在其声明完成之前不知道A 类存在。
  • A 类b:B=B() 创建一个NameError,因为在声明 B 类之前,A 类不知道 B 类存在。
    #! /usr/bin/python3.10
    
    class A:
       a:A=A()
       b:B=B()
    
    class B:
       a:A=A()
       b:B=B()

我遇到类型错误并想使用 mypy.如果我在类声明之外创建变量作为属性或以其他方式隐藏所需的类型,那么 mypy 将看不到类型声明并且无法解析我的程序以查找类型错误。

你可能会问,我为什么要这个?递归数据结构有不定式应用,但是...

  • A 类引用自身的情况是一个简单的链接列表。链接列表无需跟踪索引,同时允许简单的插入、删除和下一次迭代,代价是应用程序可能不需要的慢速索引。
  • A 类引用 B 类而 B 类引用 A 类的情况是一个简单的容器,其中 B 类(容器)包含一组 A 类实例(项目),这些实例知道它们所在的容器。李>

Python 能否以 mypy 对类型声明满意的方式完成这些非常基本的事情?

我开始认为“python 方式”是让每个函数对每个参数进行类型检查。我考虑得越多,解释型语言提出这样的要求就越合乎逻辑,但我仍然希望使我的代码尽可能有条理和声明性。

【问题讨论】:

  • 表示链表的不需要引用自身。只有类的一个实例需要引用另一个实例。
  • 你不能在同一个类体内创建一个类的实例,这个类还不存在。如果要使用尚不存在的类键入注释属性,可以使用from __future__ import annotations
  • 您定义的是类属性,而不是实例属性(尽管 class 语句中带注释的 name 可用于对实例属性进行类型提示)。

标签: python mypy recursive-datastructures


【解决方案1】:

我认为您的部分问题没有解决方案。您的声明:

class A:
   a:A=A()
   b:B=B()

暗示 A().a 是 A 的另一个实例,它又引用另一个 A,依此类推。这不一定是个问题,但是让它成为对象创建或实例化的一部分将自动需要无限数量的对象!也许你可以这样做:

from typing import Optional


class A:
    a: Optional["A"]
    def __init__(self, other: Optional["A"] = None):
        self.a = other

这将允许您有一个基本情况(self.a 是 None)和 self.a 是 A 的另一个实例的其他情况。

注意上面也使用“A”来定义类型。这可以帮助您解决类型提示问题,尽管我不知道它是如何与 mypy 一起玩的!您可以应用它,使您的解决方案看起来像:

from typing import Optional


class A:
    a: Optional["A"]
    b: Optional["B"]

class B:
    a: Optional["A"]
    b: Optional["B"]

【讨论】:

  • 一件小事:鉴于a(和b)可能是None,所有类型提示都应该是Optional["A"](和Optional["B"]
  • 这很好,谢谢。将其添加到答案中。
【解决方案2】:

[在 cmets 讨论后编辑答案。]

如果您想要一个带有__init__ 方法的递归类定义,那么正确的实现将取决于您的目标,但PirateNinjas's answer using Optional 可能是您想要的。但是,如果你真的需要静态类成员,你可以在声明两个类之后初始化它们:

class A:
    a: 'A'
    b: 'B'

class B:
    a: 'A'
    b: 'B'

A.a = A()
A.b = B()
B.a = A()
B.b = B()

【讨论】:

    猜你喜欢
    • 2012-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-01
    • 1970-01-01
    • 2020-02-25
    • 2020-12-10
    • 1970-01-01
    相关资源
    最近更新 更多