【发布时间】:2022-01-14 20:15:38
【问题描述】:
总结
TLDR:我有一个带有严重子类的 ABC。 ABC 有一个返回子类实例的方法。我想将 ABC 和子类放在不同的文件中。
示例
在一个文件中,这是可行的:
from abc import ABC, abstractmethod
class Animal(ABC):
# Methods to be implemented by subclass.
@property
@abstractmethod
def name(self) -> str:
"""Name of the animal."""
...
@abstractmethod
def action(self):
"""Do the typical animal action."""
...
# Methods directly implemented by base class.
def turn_into_cat(self):
return Cat(self.name)
class Cat(Animal):
def __init__(self, name):
self._name = name
name = property(lambda self: self._name)
action = lambda self: print(f"{self.name} says 'miauw'")
class Dog(Animal):
def __init__(self, name):
self._name = name
name = property(lambda self: self._name)
action = lambda self: print(f"{self.name} says 'woof'")
>>> mrchompers = Dog("Mr. Chompers")
>>> mrchompers.action()
Mr. Chompers says 'woof'
>>> mrchompers.turn_into_cat().action()
Mr. Chompers says 'miauw'
问题
我想将Animal 类定义放在base.py 中,将Cat 和Dog 类定义放在subs.py 中。
问题是,这会导致循环导入。 base.py 必须包含 from .subs import Cat,subs.py 必须包含 from .base import Animal。
我之前遇到过循环导入错误,但通常是在输入提示时。在那种情况下,我可以把这些线
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from .base import Animal
但是,这里不是这样。
关于如何将此代码拆分为 2 个文件的任何想法?
【问题讨论】:
-
基类需要知道它的子类对我来说似乎很奇怪。也许
turn_into_cat应该住在Cat中并以Animal作为参数? -
见我的answer 到Improper use of new to generate class instances?。它不需要基类提前知道它的所有子类。
-
一个简单的技巧,在
def turn_into_cat中执行import subs,然后简单地执行return subs.Cat(whatever) -
嗯是的@juanpa 这当然是一种可能性......不过,我认为在模块中间导入是不好的做法。如果有其他解决方案,我更喜欢那个
-
@NerdOnTour:抽象类规定
name应该在子类中实现。在这种情况下,子类通过让属性name返回受保护变量_name的值来实现这一点,该变量在实例化时设置。它使name成为只读属性。或者,子类可以取消name = property(..)行并直接在__init__方法中设置self.name = name。但是,该属性将是可写的——我认为这会让动物感到困惑,像这样改变它的名字。