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

2024-06-26 00:00:56 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我有以下两个类

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

class B(A):
    pass

我希望descendant_method可以从B的实例调用,而不是{}的实例,并且{}可以从任何地方调用。在

我可以想出几种解决办法,但都不令人满意:

  1. 检查一些字段并手动提升NotImplementedError
^{pr2}$

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

  1. 使用混音器:
^{3}$

只要descendant_method不使用A的太多,否则我们将不得不继承{},而这违反了整个要点

  1. 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__()

这是可行的,但显然看起来很脏,就像在B中写self.descendant_method = self._A__descendant_method。在

实现这种行为的正确“Python”方式是什么?在

UPD:将方法直接放在B中当然可以,但是我希望A将有许多后代使用此方法,并且不希望在每个子类中定义它。在


Tags: 方法nameselfdefpassprivatedescmethod
3条回答

尝试使用__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()

据我所知,这可能是实现你想要的最具Python式的方式:

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

class B(A):
    def descendant_method(self):
        ...

另一种选择可能是:

^{pr2}$

它们都是Python式的,因为它清晰、易读、清晰、简洁。在

  • 它是明确的,因为它没有做任何不必要的魔术。在
  • 它是可读的因为 你可以准确地知道你在做什么,你的意图是什么 乍一看。在
  • 很清楚,因为前导的单下划线是 Python社区中广泛使用的私有约定 (非魔法)任何使用它的开发人员都应该知道如何使用它 小心。在

在这些方法中选择一种将取决于您对用例的意图。在你的问题中举一个更具体的例子会很有帮助。在

AAA继承有什么不好的?它基本上是一个抽象基类,它添加了A中没有的附加功能。如果您真的不希望AA被实例化,那么python的答案是不用担心它,只需记录用户不打算这样做。但是如果你真的坚持,你可以定义__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成为{a1}。要实现这一点,您需要至少定义一个方法作为抽象方法,__init__可以这样做,如果没有其他方法您想说是抽象的。在

^{pr2}$

最后,在A上使用子代方法有什么不好的,但是不使用它。您正在为A编写代码,所以不要使用该方法。。。您甚至可以记录该方法,说明它并不打算由A直接使用,而是可以用于子类。这样未来的开发人员就会知道你的意图。在

相关问题 更多 >