假设我有以下两个类
class A:
def own_method(self):
pass
def descendant_method(self):
pass
class B(A):
pass
并且我希望 descendant_method
可以从 B
的实例中调用,但不能从 A
和 own_method
的实例中调用可以从任何地方调用。
我能想到几个方案,都不尽如人意:
- 检查一些字段并手动引发
NotImplementedError
:
class A:
def __init__(self):
self.some_field = None
def own_method(self):
pass
def descendant_method(self):
if self.some_field is None:
raise NotImplementedError
class B(A):
def __init__(self):
super(B, self).__init__()
self.some_field = 'B'
pass
但这是在修改方法的运行时行为,我不想这样做
- 使用混入:
class A:
def own_method(self):
pass
class AA:
def descendant_method(self):
pass
class B(AA, A):
pass
这很好,只要 descendant_method
不使用太多来自 A
的内容,否则我们将不得不继承 AA(A)
这违背了整点
- 在
A
中使方法私有(private)并在元类中重新定义它:
class A:
def own_method(self):
pass
def __descendant_method(self):
pass
class AMeta(type):
def __new__(mcs, name, parents, dct):
par = parents[0]
desc_method_private_name = '_{}__descendant_method'.format(par.__name__)
if desc_method_private_name in par.__dict__:
dct['descendant_method'] = par.__dict__[desc_method_private_name]
return super(AMeta, mcs).__new__(mcs, name, parents, dct)
class B(A, metaclass=AMeta):
def __init__(self):
super(B, self).__init__()
这行得通,但显然看起来很脏,就像在 B
本身中编写 self.descendant_method = self._A__descendant_method
一样。
实现此行为的正确“pythonic”方式是什么?
UPD:当然,将方法直接放在 B
中是可行的,但我预计 A
将有许多后代将使用此方法并且不想在每个子类中定义它。
最佳答案
AA
从 A
继承有什么不好?它基本上是一个抽象基类,添加了 A
中不可用的附加功能。如果你真的不想 AA
被实例化,那么 pythonic 的答案是不用担心它,只是记录用户不打算这样做。不过,如果您真的坚持,您可以定义 __new__
以在用户尝试实例化 AA
时抛出错误。
class A:
def f(self):
pass
class AA(A):
def g(self):
pass
def __new__(cls, *args, **kwargs):
if cls is AA:
raise TypeError("AA is not meant to be instansiated")
return super().__new__(cls)
class B(AA):
pass
另一种选择可能是使 AA
成为 Abstract Base Class .为此,您需要将至少一个方法定义为抽象的——如果没有其他您想要说是抽象的方法,__init__
可以这样做。
from abc import ABCMeta, abstractmethod
class A:
def __init__(self, val):
self.val = val
def f(self):
pass
class AA(A, metaclass=ABCMeta):
@abstractmethod
def __init__(self, val):
super().__init__(val)
def g(self):
pass
class B(AA):
def __init__(self, val):
super().__init__(val)
最后,在 A
上提供后代方法有什么不好,但就是不使用它。您正在为 A
编写代码,所以不要使用该方法...您甚至可以记录该方法,它不打算由 A
直接使用>,但更适合子类(class)使用。这样 future 的开发人员就会知道您的意图。
关于python - 只能从 python 中的类后代访问的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33687486/