我们说我有以下两个班级
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)
,这就违背了整点< / p>
A
中将方法设为私有,并在元类中重新定义: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__()
这很有效,但看起来很脏,就像在self.descendant_method = self._A__descendant_method
中写B
一样。
什么是正确的&#34; pythonic&#34;实现这种行为的方式?
UPD:当然,将方法直接放在B
中会起作用,但我希望A
将有许多将使用此方法的后代,并且不希望在每个子类中定义它。
答案 0 :(得分:2)
据我所知,这可能是实现你想要的最恐怖的方式:
class A:
def own_method(self):
pass
def descendant_method(self):
raise NotImplementedError
class B(A):
def descendant_method(self):
...
另一种选择可能如下:
class A:
def own_method(self):
pass
def _descendant_method(self):
pass
class B(A):
def descendant_method(self):
return self._descendant_method(self)
他们都是Pythonic,因为它是明确,可读,清晰和简洁。
选择其中一种方法取决于您对用例的意图。你问题中一个更具体的例子会有所帮助。
答案 1 :(得分:2)
从xxx
zzz
yyy
继承AA
有什么不妥?它基本上是一个抽象的基类,它增加了A
中不可用的附加功能。如果你真的不希望A
被实例化,那么pythonic答案就不用担心了,只记录用户并不打算这样做。虽然如果您真的坚持,如果用户尝试实例化AA
,您可以定义__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
为Abstract Base Class。要使其工作,您需要将至少一个方法定义为抽象 - AA
如果没有其他方法可以说是抽象的,那么就可以做到。
__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
不能直接使用的方法,但相当意味着可供儿童班使用。这样未来的开发人员就会知道你的意图。
答案 2 :(得分:0)
尝试使用__class__.__name__
检查班级名称。
class A(object):
def descendant_method(self):
if self.__class__.__name__ == A.__name__:
raise NotImplementedError
print 'From descendant'
class B(A):
pass
b = B()
b.descendant_method()
a = A()
a.descendant_method()