【问题标题】:Python Class Inheritance issuePython类继承问题
【发布时间】:2010-10-30 00:05:31
【问题描述】:

我在玩 Python 类继承,遇到了一个问题,如果从子类(下面的代码)调用继承的 __init__,我从 Active Python 得到的结果是:


>>> start
Tom Sneed
Sue Ann
Traceback (most recent call last):
  File "C:\Python26\Lib\site-packages\pythonwin\pywin\framework\scriptutils.py", line 312, <br>in RunScript
    exec codeObject in __main__.__dict__
  File "C:\temp\classtest.py", line 22, in <module>
    print y.get_emp()
  File "C:\temp\classtest.py", line 16, in get_emp
    return self.FirstName + ' ' + 'abc'
AttributeError: Employee instance has no attribute 'FirstName'

这是代码

class Person():
    AnotherName = 'Sue Ann'
    def __init__(self):
        self.FirstName = 'Tom'
        self.LastName = 'Sneed'

    def get_name(self):
        return self.FirstName + ' ' + self.LastName

class Employee(Person):
    def __init__(self):
        self.empnum = 'abc123'

    def get_emp(self):
        print self.AnotherName
        return self.FirstName + ' ' + 'abc'

x = Person()
y = Employee()
print 'start'
print x.get_name()
print y.get_emp()

【问题讨论】:

    标签: python class inheritance


    【解决方案1】:

    Employee 必须显式调用父级的 __init__(不是 init):

     class Employee(Person):  
        def __init__(self):  
             Person.__init__(self)  
             self.empnum = 'abc123'  
    

    【讨论】:

      【解决方案2】:

      你应该明确地调用超类的 init 函数:

      class Employee(Person):
          def __init__(self):
              Person.__init__(self)
              self.empnum = "abc123"
      

      【讨论】:

      • 这行得通——但为什么呢?为什么继承的类不能像将它实例化为自己的对象一样工作?
      • Python 在实例化子类时不会自动调用超类的 init 函数。这个责任留给了程序员。我不知道这背后是否有理由。
      【解决方案3】:

      三件事:

      1. 您需要显式调用构造函数。它不会像在 C++ 中那样自动为您调用
      2. 使用继承自对象的新型类
      3. 对于新式类,使用可用的 super() 方法

      这看起来像:

      class Person(object):
          AnotherName = 'Sue Ann'
          def __init__(self):
              super(Person, self).__init__()
              self.FirstName = 'Tom'
              self.LastName = 'Sneed'
      
          def get_name(self):
              return self.FirstName + ' ' + self.LastName
      
      class Employee(Person):
          def __init__(self):
              super(Employee, self).__init__()
              self.empnum = 'abc123'
      
          def get_emp(self):
              print self.AnotherName
              return self.FirstName + ' ' + 'abc'
      

      推荐使用 super ,因为它也可以在多重继承的情况下正确处理调用构造函数一次(只要继承图中的每个类也使用 super )。如果/当您更改类的继承对象时(例如,您分解出一个基类并更改派生,并且不必担心您的类调用错误的父类),这也是您需要更改代码的少一个地方构造函数)。同样在 MI 方面,您只需要一次超级调用即可正确调用所有基类构造函数。

      【讨论】:

      • 使用super时一定要小心,请阅读:fuhm.net/super-harmful
      • +1 用于推荐新样式类,特别是当 OP 的堆栈跟踪表明他们正在使用 Python 2.6 时。
      • 如果超类没有 init 会有问题吗?如果是这样,这是否意味着超类不能是“黑匣子”?
      • 没有问题的超类没有init。这是相当黑盒式的。
      • 很高兴了解这些陷阱。到目前为止,我一直非常小心,我所有的 python 代码都调用 super() 一直到 object :)
      【解决方案4】:

      为什么不直接使用super(instance) 而不是super(class, instance) 模式,因为类总是instance.__class__

      是否有特定情况不是instance.__class__

      【讨论】:

      • 哇。我认为它删除了我的部分评论。当然应该是“instance.__class__”。
      • 这实际上是一个很好的问题。请观看pyvideo.org/video/879/the-art-of-subclassing(TL;DW:不,这不是instance.__class__。“self”不一定是你。)
      猜你喜欢
      • 2016-07-19
      • 1970-01-01
      • 2016-07-24
      • 1970-01-01
      • 2011-08-25
      • 1970-01-01
      相关资源
      最近更新 更多