在父类文件中调用子类方法的Python实现
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 个回答
如果两个类在同一个.py文件里,你可以直接从父类调用子类的方法。虽然会有警告,但其实是可以正常运行的。
类A(object类):
def methodA(self):
print("in methodA")
Self.methodb()
类B(继承自A):
def methodb(self):
print("am in methodb")
你可以在任何地方使用这个函数,只要它和一个对象关联在一起。从你的例子来看,它确实是这样。如果你有一个 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
中的一个函数,你仍然可以使用它的方法。
这里有三种方法可以做到这一点!但我强烈推荐使用第三种方法,因为这种方式在设计模式上有一些好处,比如组合和解耦的优势。(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()
你可以这样做:
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']
我想说明的是,你可以创建一个子类的实例,它会拥有父类和自己类中的所有方法和参数。
这样做只有在 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
,也会发生同样的情况。