【问题标题】:calling child class method from parent class file in python从python中的父类文件调用子类方法
【发布时间】:2014-09-23 14:06:29
【问题描述】:

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()

【问题讨论】:

  • 如果你需要,那是相当严重的代码异味。
  • 可能是我做错了,但正在寻找其他更聪明的方法。
  • @JagadeeshNM 很难说你可能做错了什么以及如何变得更聪明,因为通过这样做你实际上想要实现什么并不明显。听起来有点像您的问题来自更广泛的程序设计中的不愉快方法......

标签: python class inheritance parent


【解决方案1】:

只有当A 是一个抽象基类时才有意义,这意味着A 仅用作其他类的基类,而不是直接实例化。如果是这种情况,您将在 A 类上定义 methodB,但不要实现它:

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

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


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 ABCMeta, abstractmethod

class A(object):
 __metaclass__ = ABCMeta

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

    @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,也会发生同样的情况。

【讨论】:

  • 为什么要显式设置__metaclass__,而不只是在定义中使用ABC作为基类?
【解决方案2】:

你可以这样做:

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']

我想展示的是,您可以创建子类的实例,并且它将具有来自父类和它自己的类的所有方法和参数。

【讨论】:

    【解决方案3】:

    有三种方法可以做到这一点!但我强烈建议使用方法#3,因为组合/解耦在设计模式方面具有一定的好处。 (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()
    

    【讨论】:

    • 在您的第三个建议中,您如何处理 a=A()a.methodb()(如果我没记错的话,这就是最初的问题)
    【解决方案4】:

    您可以在任何地方使用该函数只要它附加到一个对象,它似乎来自您的示例。如果你有一个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 中的函数,您仍然可以使用它的方法。

    【讨论】:

      【解决方案5】:

      如果两个类都在同一个 .py 文件中,那么您可以直接从父类调用子类方法。 它给了我警告,但运行良好。

      A 类(对象):

      def methodA(self):
      
          print("in methodA")
      
          Self.methodb()
      

      B(A)类:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-07-07
        • 2020-01-14
        • 1970-01-01
        • 2017-11-09
        • 2012-02-22
        • 2016-02-14
        • 1970-01-01
        • 2014-06-11
        相关资源
        最近更新 更多