Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/299.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python继承。为什么这么乱?_Python_Syntax - Fatal编程技术网

Python继承。为什么这么乱?

Python继承。为什么这么乱?,python,syntax,Python,Syntax,可能重复: 例如: class Pet(object): def __init__(self, name, species): self.name = name self.species = species def getName(self): return self.name def getSpecies(self): return self.species def __str__(self):

可能重复:

例如:

class Pet(object):

    def __init__(self, name, species):
       self.name = name
       self.species = species

    def getName(self):
     return self.name

    def getSpecies(self):
     return self.species

    def __str__(self):
     return "%s is a %s" % (self.name, self.species)

class Dog(Pet):

   def __init__(self, name, chases_cats):
      Pet.__init__(self, name, "Dog")
      self.chases_cats = chases_cats

   def chasesCats(self):
     return self.chases_cats

正如你们所看到的,狗是从宠物身上继承下来的。我完全理解代码。但是,为什么我们必须在狗类中称为宠物的init呢?为什么仅仅把它称为狗类的第一行还不够(狗类(宠物))呢?它似乎只会创建更混乱的代码。对我来说,这有点扼杀了Python中的继承点。

使用该语言会强制在之前或之后初始化超类,这意味着您将失去功能。子类可能依赖于要首先运行的超类的初始化,反之亦然

此外,它无法知道要传递什么参数——子类决定传递给初始值设定项的值,这比自动传递所有参数更灵活

初始化超类的另一种方法是使用,尽管这实际上会通过在对象的
\uuuu mro\uuu
中查找它来动态初始化
self
的超类(方法解析顺序)

在python 2中:

super(self, Dog).__init__(self, name, "Dog")
在python 3中,您可以进一步减少语法,避免重复:

super().__init__(self, name, "Dog")
编辑

由于您实际上没有使用传递给dog的
name
参数,因此可以通过接受
dog
初始值设定项中的任意关键字和位置参数,并将它们向上传递到初始化链,进一步简化某些语法:

class Dog(Pet):

   def __init__(self, chases_cats, *args, **kwargs):
      Pet.__init__(self, *args, species="Dog", **kwargs)
      self.chases_cats = chases_cats

class Pet(object):

    def __init__(self, name, species, *args, **kwargs):
       self.name = name
       self.species = species

在您的场景中,初始值设定项可能非常简单,不需要这样做,但当您有更多参数和/或更深层的类层次结构时,了解这一点非常有用。

您可以将物种设置为这样的类属性

class Pet(object):
    species = None

    def __init__(self, name):
        self.name = name

    def getName(self):
        return self.name

    def getSpecies(self):
        return self.species

    def __str__(self):
        return "%s is a %s" % (self.name, self.species)

class Dog(Pet):
    species = "Dog"

    def __init__(self, name, chases_cats):
        Pet.__init__(self, name)
        self.chases_cats = chases_cats

    def chasesCats(self):
        return self.chases_cats

如果您没有调用
Pet.\uuuu init\uuuu()
,则将永远不会初始化
Pet.species
属性。你可能会认为应该自动调用
Pet.\uuuuu init\uuuuu()
,但是当必须使用参数调用
\uuuuu init\uuuuu()
函数时,没有智能的方法可以做到这一点。我更新了我的答案,提供了更多关于使用位置参数(例如.*args)和关键字参数(例如.*kwargs)的信息@Li aungYip同意,在C++中,当构造函数有参数时,它们也必须在子中显式调用。如果以后需要更改访问它们的方式,请使用python,它不会更改使用该类的任何内容的语法。请参阅为什么这是一个很棒的语言功能,以及为什么不编写getter/setter。是的,实际上我更喜欢这种设计,为什么必须在基类中初始化物种,这对于OO透视来说很奇怪。@zinking,你不必这样做。有些人喜欢,有些人不喜欢。这种设计确实意味着你不能为一个特定的实例改变物种。如果物种应该等于类名,您可以将其定义为on
Pet
def species(self):返回类型(self)。\uuu name\uuu
。这提供了所有的功能,除了
Pet
对象具有
None
@Darthfett的物种,你是什么意思?我可以很容易地设置一个名为
species
的实例属性来覆盖class属性。@gnibbler我的错误,我认为它最终会改变class属性。我还了解到类属性可以从实例访问(我认为它严格地从类名访问),所以我想我应该先测试一下。谢谢你的更正。