【发布时间】:2021-11-03 18:42:22
【问题描述】:
我有一个大类定义,为了清楚起见,我想在一个单独的文件中分离出算术 dunder 方法。但是,这些方法需要能够返回类的新实例,这会导致循环导入、名称错误或难看的不可维护性。
我想这样做的动机是在最后。
这是一个最小的工作示例。将所有内容放在一个文件中...
#classa.py
class A:
def __init__(self, val):
self.val = val
def __add__(self, other):
return A(self.val + other.val)
...它有效:
from .classa import A
a1 = A(30)
a2 = A(21)
(a1 + a2).val # 51
现在,尝试将__add__ 方法放入一个单独的文件中。
什么不起作用:
尝试 1
#classa.py
from .classa_add import Aarithmatic
class A(Aarithmatic):
def __init__(self, val):
self.val = val
#classa_add.py
from .classa import A
class Aarithmatic:
def __add__(self, other):
return A(self.val + other.val)
由于循环导入,我们得到一个错误是可以理解的:
from .classa import A # <-- ImportError
a1 = A(30)
a2 = A(21)
(a1 + a2).val
尝试 2
以防万一人们将我指向this 答案:)
#classa.py
from .classa_add import Aarithmatic
class A(Aarithmatic):
def __init__(self, val):
self.val = val
#classa_add.py
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from .classa import A
class Aarithmatic:
def __add__(self, other):
return A(self.val + other.val)
我们在尝试添加实例时遇到名称错误,因为 A 未知。这是有道理的,这里使用的“解决方案”仅适用于 A 仅用于注释时:
from .classa import A
a1 = A(30)
a2 = A(21)
(a1 + a2).val # <-- NameError: name 'A' is not defined # (in __add__)
尝试 3
我可以这样做......
#classa.py
class A:
def __init__(self, val):
self.val = val
#classa_add.py
from .classa import A
def _a_add(self, other):
return A(self.val + other.val)
A.__add__ = _a_add
# Or as oneliner:
A.__add__ = lambda self, other: A(self.val + other.val)
但这首先是相当丑陋和不可读,其次我必须导入classa_add只是为了添加添加功能,这很混乱:
from .classa import A
import .classa_add # <- unclear to reader, why this needs to be here
a1 = A(30)
a2 = A(21)
(a1+a2).val # 51
如果这是一个包,我可以添加一个 __init__.py 文件来执行此操作,但它仍然很难看,而且我确信有更好的解决方案。
有谁知道,更好的解决方案是什么?
非常感谢!
顺便说一句,我正在使用 python 3.8。
编辑
推理。为什么我什至想这样做?
我有两个相似的类(A 和B),每个类都有很多方法。沿着pandas DataFrame 和Series 类的思路思考,只是稍微小一点,而且不太相似,以至于可以让它们从一个共同的父类继承。目前,每个类都有一个定义它的文件(classa.py 和classb.py)。
现在,这些文件首先太长,其次,实例上的算术非常相似。
这让我想创建一个单独的文件来定义a1 + a2、b1 + b2、a1 * a2、b1 * b2 以及a + b 和a * b 的含义。
我希望这可以更清楚地说明我为什么要这样做,并且我希望您同意以这种方式拆分类定义更易于维护。
【问题讨论】:
-
我想我以前从未见过这样的事情。看起来是个 XY 问题
-
你可以写一个 mixin 类,或者找出一些更简洁的继承结构。但是
A.__add__ = _a_add感觉非常奇怪,我想我会对此感到非常惊讶。我不明白为什么它不在主类定义中 -
我同意 XY 的问题,这绝不是你想做的任何事情的最佳方式
-
我已将我的推理添加到问题的末尾