Python继承:何时以及为什么__init__

时间:2017-04-26 04:13:13

标签: python inheritance

我是一个Python新手,试图理解继承方法背后的哲学/逻辑。问题最终会考虑为什么以及何时必须在子类中使用__init__方法。例如:

似乎从超类继承的子类不需要自己的构造函数(__init__)方法。下面,狗继承了哺乳动物的属性(名称,年龄)和方法(makenoise)。你甚至可以添加一个方法(do_a_trick)似乎所有东西都是“应该”的。

但是,如果我想在Cats类中尝试在子类中添加新属性,则会收到错误,指出“self”未定义。然而我在狗类的定义中使用了“自我”。差异的本质是什么? 它似乎定义了Cats,因为我希望我需要使用__init__(self,name)super()__init__(name)。为什么不同?

class Mammals(object):

  def __init__(self,name):
    self.name = name
    print("I am a new-born "+ self.name)  
    self.age = 0

  def makenoise(self):
    print(self.name + " says Hello")

class Dogs(Mammals):

  def do_a_trick(self):
    print(self.name + " can roll over")

class Cats(Mammals):

 self.furry = "True"  #results in error `self' is not defined


mymammal = Mammals("zebra") #output "I am a new-born zebra"
mymammal.makenoise()  #output "zebra says hello"
print(mymmmal.age)    #output 0

mydog = Dogs("family pet") #output "I am a new-born family pet"
mydog.makenoise()  #output "family pet says hello"
print(mydog.age)  # output 0
mydog.do_a_trick() #output "family pet can roll over"

7 个答案:

答案 0 :(得分:3)

  

Explicit is better than implicit.

但是,你可以在下面做:

DictWriter.writerow()

class Dogs(Mammals):
    def __init__(self):
        #add new attribute
        self.someattribute = 'value'
        Mammals.__init__(self)

答案 1 :(得分:2)

  

如果我想在子类中添加一个新属性,就像我尝试的那样   在Cats类中,我收到错误说" self"没有定义。然而,我   用过" self"在狗类的定义中。

在您的超类Mammal中,您有一个__init__函数,它会使用您已选择的参数*来调用self。当你在__init__函数的主体中时,这个参数就在范围内 - 它是一个局部变量,就像任何局部变量一样,并且在它包含之后它不可能引用它功能终止。 Dog类do_a_trick上定义的函数也接受一个名为self的参数,它也是该函数的本地参数。 这些变量的特殊之处不在于它们的名称(你可以将它们称为任何你想要的东西),但事实上,作为python中实例方法的第一个参数,它们获得了对它们被称为它们的对象的引用。值。 (再次阅读最后一句话,这是理解这一点的关键,你可能第一次没有得到它。)

现在,在Cat中,您有一行根本不在函数中的代码。此时没有任何内容,包括self,这就是失败的原因。如果要在Cat中定义一个带有self参数的函数,则可以引用该参数。如果该参数碰巧是Cat上实例方法的第一个参数,那么它将具有调用它的Cat实例的值。否则,它将传递给它的任何东西。

*你明智地选择了!

答案 2 :(得分:2)

Python类顶层的声明成为类属性。如果您来自C ++或Java背景,这类似于声明静态成员变量。您无法在该级别分配实例属性。

变量self通常是指类的特定实例,即从中调用该方法的类。当使用语法inst.method()进行方法调用时,函数的第一个参数是调用该方法的对象inst。在您的情况下,通常按照惯例,该参数在方法的函数体中命名为self。您可以认为self只是方法体中的有效标识符。您的作业self.furry = True不会在某个方法中发生,因此我们不会在那里定义。

您基本上有两种方法可以实现您的目标。第一种是将furry正确定义为cat类的属性:

class Cat(Mammals):
    furry = True

    # Rest of Cat implementation ...

或者您可以在cat构造函数中设置实例变量furry的值:

class Cat(Mammals):
    def __init__(self):
        super(Mammals, self).__init__(self)
        self.furry = True

    # Rest of Cat implementation ...

如果您正在使用Python,我强烈建议您阅读Python文档的这两部分:

Python classes

Python data model special methods(更高级)

答案 3 :(得分:1)

你可以通过启动构造函数方法中的所有变量来完成Chankey的答案,例如a = 11111, length = 5

但是你也可以做这样的事情

__init__

然后

class Cats(Mammals):

 furry = "True"

您无法在函数外使用cat = Cats("Tom") cat.furry # Returns "True" 的原因是因为self仅显式用于类的实例。如果你在外面使用它,会导致歧义。如果我的答案不清楚,请在评论中告诉我。

答案 4 :(得分:1)

__init__方法在创建类的实例时运行一次。因此,如果您想在实例创建时设置属性,那就是您执行此操作的位置。 self是一个特殊的关键字,它作为第一个参数传递给每个方法,它引用实例本身。 __init__与此方面的其他方法没有什么不同。

"差异的本质是什么":您定义方法Dog.do_a_trick,并且像往常一样接收self作为方法的参数。但是在Cat中,您无意中(可能是下意识地!)尝试在类范围内工作 - 这就是您设置类属性的方式,其值相同对于所有的猫:

class Cat(object):
    sound = "meow"

它有所不同,因此您可以同时使用这两个选项。有时(不是所有的时间,但偶尔),类属性是一个有用的东西。所有的猫都有相同的声音。但是大多数时候你会使用实例属性 - 不同的猫有不同的名字;如果需要,请使用__init__

答案 5 :(得分:1)

假设您有一个名为Person的类,其名为get_name的方法定义为:

 class Person():
     def __init__(self, first_name, last_name):
         self.first_name = first_name
         self.last_name = last_name

     def get_name(self):
         return self.first_name + ' ' + self.last_name

并且,您将Person的实例创建为p1。现在,当您使用此实例调用函数get_name()时,它将在内部转换

    Person.get_name(p1)

所以,自我就是实例本身。

如果没有self,您可以将上面的代码写为:

 class Person():
     first_name = None
     last_name = None


     def get_name(personobject):
         return personobject.first_name + ' ' + personobject.last_name

我想说的是名称self只是一种惯例。

对于继承,如果您希望在子类中有额外的属性,则需要首先启动超类并根据需要添加参数。 例如,如果要创建名为Person的{​​{1}}子类,并使用新属性Boy,则可以将其定义为:

height

答案 6 :(得分:0)

正如其他答案中所指出的那样,你在另一个答案中看到self 函数实际上是一个参数。通过Python约定,第一个参数 实例方法始终为self

Cats从其基类继承__init__函数, Mammals。您可以覆盖__init__,也可以拨打电话或不拨打电话 类实现。

如果Cats __init__想要调用基本实现,但不想关心参数,则可以使用Python变量参数。这显示在以下代码中。

班级声明:

class Cats(Mammals):

  def __init__(self, *args):
    super().__init__(*args)
    self.furry = "True"

例如,请参阅此Stack Overflow问题,了解有关该星的信息 可变数量参数的表示法: Can a variable number of arguments be passed to a function?

附加测试代码:

cat = Cats("cat")
print(vars(cat))

输出:

I am a new-born cat
{'name': 'cat', 'age': 0, 'furry': 'True'}