2015-09-22 92 views
3

我想了解继承如何在Python中工作。我正在看一个简单的代码,有一件事让我感到困惑。代码如下:Python中的继承基础知识

class Person: 

    def __init__(self, first, last): 
     self.firstname = first 
     self.lastname = last 

    def Name(self): 
     return self.firstname + " " + self.lastname 

class Employee(Person): 

    def __init__(self, first, last, staffnum): 
     Person.__init__(self,first, last) 
     self.staffnumber = staffnum 

    def GetEmployee(self): 
     return self.Name() + ", " + self.staffnumber 

x = Person("Marge", "Simpson") 
y = Employee("Homer", "Simpson","1007") 
print(x.Name()) 
print(y.GetEmployee()) 

我的问题是,在再次使用时Person.__init__()调用基类的构造函数,但是当我们调用名称()基类的方法,而不是使用“人”,我们使用“自”。有人可以澄清这种困惑,我了解Python的继承是如何工作的?

+3

这不是很pythonic的代码,可能不是最好的学习!但是请注意,只有当子类没有实现'method' **时,才可以使用'self.method'来访问超类实现**。这里的子类实现了'__init__',所以需要明确地访问超类的版本(虽然它应该用'super'来实现),但是不实现'Name'。尝试改变它,看看会发生什么! – jonrsharpe

+0

还有一个问题,当我们需要调用一个父类的方法时,我们需要传递孩子(自我)作为参数。为什么? –

+0

因为你没有使用'super(Employee,self).__ init __(first,last)'。搜索绑定与未绑定方法的信息; 'self.Name'被绑定,'Person .__ init__'被解除绑定。 – jonrsharpe

回答

1

以下两种方法是等效的(假设“名称”方法不会被覆盖):

class Employee(Person): 
    def __init__(self, first, last, staffnum): 
     Person.__init__(self, first, last) 
     self.staffnumber = staffnum 

    def getEmployee(self): 
     return Person.Name(self) + self.staffnumber 


class Employee(Person): 
    def __init__(self, first, last, staffnum): 
     Person.__init__(self, first, last) 
     self.staffnumber = staffnum 

    def getEmployee(self): 
     return self.Name() + self.staffnumber 

在第二个例子中,当self.Name()被调用时,类的实例是“绑定“的功能,所以第一个参数不需要传递。

因为init在Employee子类中被覆盖,所以不能调用self。 init(first,last)。然后你会打电话给员工。 init(self,* args)而不是Person。 init(self,* args)。这将创建一个无限递归循环,否则你会得到一个参数错误。

作为一般规则,当您重写某个方法时,必须在子类中使用以下表示法。 ParentClass.methodname(self,* args,** kwargs)。你可以调用self.Name()的原因是因为名字没有被覆盖。

我在这里重复自己。这会使它结晶吗?还是让我更加困惑?

+0

我不确定这会回答这个问题,因为它不能解释'__init__'和'Name'之间调用的区别。 – jonrsharpe

+0

它被绑定到函数意味着它继承了方法Name(),所以它也可以被self.Name()调用?如果那是真的,那我就明白了。其次,为什么我们需要将自己作为一个参数来传递,那就是把孩子传递给父类? –

2

Employee类继承了基类Person类的方法,其中包括__init__方法。所以在类定义的顶部,它有__init__Name方法。

然后Employee类定义将覆盖它继承的方法__init__。为了调用Person__init__方法,它必须按名称调用Person.__init__(实际上,它可以使用super()作为另一种选择)。

但由于Employee不会覆盖继承Name方法,它可以使用self.Name()调用Name方法,它继承了顶部。

+0

非常感谢你!得到它了!! :) –

+0

还有一个问题,当我们需要调用父类的方法时,我们需要传递子(self)作为参数。为什么? –

0

说简单的说法就是self.method()的意思是“调用method可用的最具体的实现”(即,当前对象的继承树最远的那个)。在这种情况下,您不必拨打电话self.__init__,因为这会再次调用Employee.__init__。您需要编写Person.__init__(或使用super())来显式调用继承的方法。

因为Employee没有定义自己的Name方法,Person.Name是可用的最具体的一个,所以这就是被称为self.Name()。如果Employee定义了它自己的Name,那么将由self.Name()来代替。

+0

非常感谢你!我现在明白了! :) :) –

+0

还有一个问题,当我们需要调用父类的方法时,我们需要传递子(self)作为参数。为什么? –

+0

@ShahrozPunjwani:每当你在一个类上调用一个方法时(如在Person.__ init__中),你需要传递该实例作为第一个参数。当你调用实例的方法时(如'self.Name'),你不会(它会自动为你传递)。 – BrenBarn