python - 只能从 python 中的类后代访问的方法

标签 python class oop inheritance member

假设我有以下两个类

class A:
    def own_method(self):
        pass
    def descendant_method(self):
        pass

class B(A):
    pass

并且我希望 descendant_method 可以从 B 的实例中调用,但不能从 Aown_method 的实例中调用可以从任何地方调用。

我能想到几个方案,都不尽如人意:

  1. 检查一些字段并手动引发 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

但这是在修改方法的运行时行为,我不想这样做

  1. 使用混入:
class A:
    def own_method(self):
        pass

class AA:
    def descendant_method(self):
        pass

class B(AA, A):
    pass

这很好,只要 descendant_method 不使用太多来自 A 的内容,否则我们将不得不继承 AA(A) 这违背了整点

  1. 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 将有许多后代将使用此方法并且不想在每个子类中定义它。

最佳答案

AAA 继承有什么不好?它基本上是一个抽象基类,添加了 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/

相关文章:

python - Sublime Text 插件 : Adding python libraries

python - 对数组的两个值进行更快的循环操作

ios - 在 Swift 中以编程方式更改 Storyboard 的类

java - Android:传递 Activity 类时为 "Expression expected"

javascript - 在 Javascript 中为国际象棋游戏创建对象与整数的 2D 数组

python - 如何在 XCode 4.6 中配置 Python?

python - 如何为该类的每个对象运行类中的函数?

命名空间的 JavaScript 继承

php - 如何在链接类的实例时检索祖先

python - 无法从文本小部件更改背景颜色?