在父类文件中调用子类方法的Python实现

34 投票
6 回答
75678 浏览
提问于 2025-04-18 15:30

parent.py:

class A(object):
    def methodA(self):
        print("in methodA")

child.py:

from parent import A
class B(A):
    def methodb(self):
        print("am in methodb")

有没有办法在 parent.py 里调用 methodb() 呢?

6 个回答

0

如果两个类在同一个.py文件里,你可以直接从父类调用子类的方法。虽然会有警告,但其实是可以正常运行的。

类A(object类):

def methodA(self):

    print("in methodA")

    Self.methodb()

类B(继承自A):

def methodb(self):

    print("am in methodb")
1

你可以在任何地方使用这个函数,只要它和一个对象关联在一起。从你的例子来看,它确实是这样。如果你有一个 B 对象,那么你可以在任何地方使用它的 methodb() 函数。

parent.py:

class A(object):
    def methoda(self):
        print("in methoda")

def aFoo(obj):
  obj.methodb()

child.py

from parent import A
class B(A):
    def methodb(self):
        print("am in methodb")

在你导入之后,你可以看到这个是怎么工作的:

>>> from parent import aFoo
>>> from child import B
>>> obj = B()
>>> aFoo(obj)
am in methodb

当然,你不能在 parent.py 里面创建一个新的 B 对象,但如果这个对象以某种方式传递给 parent.py 中的一个函数,你仍然可以使用它的方法。

2

这里有三种方法可以做到这一点!但我强烈推荐使用第三种方法,因为这种方式在设计模式上有一些好处,比如组合和解耦的优势。(GOF)

## approach 1 inheritance 
class A():
    def methodA(self):
        print("in methodA")
    def call_mehtodB(self):
        self.methodb()

class B(A):
    def methodb(self):
        print("am in methodb")

b=B()
b.call_mehtodB()


## approach 2 using abstract method still class highly coupled
from abc import ABC, abstractmethod
class A(ABC):
    def methodA(self):
        print("in methodA")
    @abstractmethod    
    def methodb(self):
       pass

class B(A):

    def methodb(self):
        print("am in methodb")

b=B()
b.methodb()

#approach 3 the recommended way ! Composition 

class A():
    def __init__(self, message):
        self.message=message

    def methodA(self):
        print(self.message)

class B():
    def __init__(self,messageB, messageA):
        self.message=messageB
        self.a=A(messageA)

    def methodb(self):
        print(self.message)

    def methodA(self):
        print(self.a.message)

b=B("am in methodb", "am in methodA")
b.methodb()
b.methodA()
22

你可以这样做:

class A():
    def foo(self):
        self.testb()

class B(A):
    def testb(self):
        print('lol, it works')
b = B()
b.foo()

这样做当然会返回这个结果:

lol, it works

注意,其实并没有从父类调用,而是从子类的实例中调用了函数 foo,这个实例是从父类继承了 foo,也就是说,这种情况是不可能的:

a=A()
a.foo()

会产生:

AttributeError: A instance has no attribute 'testb'

因为

>>> dir(A)
['__doc__', '__module__', 'foo']
>>> dir(B)
['__doc__', '__module__', 'foo', 'testb']

我想说明的是,你可以创建一个子类的实例,它会拥有父类和自己类中的所有方法和参数。

50

这样做只有在 A 是一个抽象基类的情况下才有意义,也就是说 A 只是用来作为其他类的基础,而不是直接被实例化。如果是这样的话,你可以在类 A 中定义 methodB,但不需要实现它:

parent.py:

class A(object):
    def methodA(self):
        print("in methodA")
        self.methodB()

    def methodB(self):
        raise NotImplementedError("Must override methodB")

child.py:

from parent import A

class B(A):
    def methodB(self):
        print("am in methodB")

其实这样做并不是绝对必要的。如果你在 A 中没有声明 methodB,然后实例化 B,你仍然可以在 methodA 的代码中调用 methodB,但这样做是不好的习惯;因为这样不清楚 methodA 是从哪里来的,或者子类需要重写它。

如果你想更正式一些,可以使用 Python 的 abc 模块来声明 A 为一个抽象基类。

from abc import ABC, abstractmethod

class A(ABC):

    def methodA(self):
        print("in methodA")
        self.methodB()

    @abstractmethod
    def methodB(self):
        raise NotImplementedError("Must override methodB")

如果你使用的是 Python 2.x:

from abc import ABCMeta, abstractmethod

class A(object):
 __metaclass__ = ABCMeta

    def methodA(self):
        print("in methodA")
        self.methodB()


    @abstractmethod
    def methodB(self):
        raise NotImplementedError("Must override methodB")

使用这个会实际阻止你实例化 A 或任何从 A 继承的类,除非重写 methodB。例如,如果 B 看起来像这样:

class B(A):
   pass

那么你在尝试实例化它时会出现错误:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class B with abstract methods methodB

如果你尝试实例化 A,也会发生同样的情况。

撰写回答