Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/359.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.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
什么&x2019;Python的继承点是什么?_Python_Oop_Inheritance - Fatal编程技术网

什么&x2019;Python的继承点是什么?

什么&x2019;Python的继承点是什么?,python,oop,inheritance,Python,Oop,Inheritance,假设您有以下情况 #include <iostream> class Animal { public: virtual void speak() = 0; }; class Dog : public Animal { void speak() { std::cout << "woff!" <<std::endl; } }; class Cat : public Animal { void speak() { std::cout &

假设您有以下情况

#include <iostream>

class Animal {
public:
    virtual void speak() = 0;
};

class Dog : public Animal {
    void speak() { std::cout << "woff!" <<std::endl; }
};

class Cat : public Animal {
    void speak() { std::cout << "meow!" <<std::endl; }
};

void makeSpeak(Animal &a) {
    a.speak();
}

int main() {
    Dog d;
    Cat c;
    makeSpeak(d);
    makeSpeak(c);
}
现在,在这个例子中,您可以看到相同的策略。你使用遗传来利用狗和猫都是动物的等级观念。 但是在Python中,不需要这种层次结构。这同样有效

class Dog:
    def speak(self):
        print "woff!"

class Cat:
    def speak(self):
        print "meow"

def makeSpeak(a):
    a.speak()

d=Dog()
c=Cat()
makeSpeak(d)
makeSpeak(c)
在Python中,您可以向任何想要的对象发送信号“说话”。如果对象能够处理它,它将被执行,否则它将引发异常。假设您向这两个代码中添加了一个类飞机,并将一个飞机对象提交给makeSpeak。在C++的情况下,它不会编译,因为飞机不是一个派生类动物。在Python的情况下,它将在运行时引发异常,这甚至可能是预期的行为

另一方面,假设您添加了一个带有speak()方法的moutoftruth类。在C++的情况下,要么你必须重构你的层次结构,要么你必须定义一个不同的MaSkPosim方法来接受口述对象,或者在java中你可以把行为提取到一个CabScript中,并为每个接口实现接口。有很多解决方案


我想指出的是,我还没有找到在Python中使用继承的单一原因(除了框架和异常树之外,但我想还有其他策略)。无需实现基本派生层次结构即可执行多态性。如果您想使用继承来重用实现,那么您可以通过包含和委派来实现这一点,另外还有一个好处,即您可以在运行时修改它,并且您可以清楚地定义包含的接口,而不会产生意外的副作用

因此,最后的问题是:Python中的继承有什么意义

编辑:感谢您提供了非常有趣的答案。实际上,您可以将其用于代码重用,但在重用实现时,我总是很小心。一般来说,我倾向于做非常浅的继承树,或者根本不做树,如果某个功能是通用的,我将其重构为一个通用模块例程,然后从每个对象调用它。我确实看到了单点更改的优势(例如,我没有添加到狗、猫、驼鹿等,而是添加到动物,这是继承的基本优势),但您可以通过委托链(例如,la JavaScript)实现同样的优势。我并不是说这样更好,只是换一种方式而已


我也发现了这一点。

我认为Python中的继承不是为了让代码编译,而是为了继承的真正原因,即将类扩展到另一个子类,并重写基类中的逻辑。然而,Python中的duck类型使“接口”概念变得无用,因为您可以在调用之前检查该方法是否存在,而无需使用接口来限制类结构。

您将运行时duck类型称为“重写”继承,然而,我相信继承作为一种设计和实现方法有其自身的优点,是面向对象设计的一个组成部分。以我的拙见,您是否能够实现其他目标的问题并不重要,因为实际上您可以在不使用类、函数等的情况下编写Python代码,但问题是您的代码设计得有多好、健壮和可读性

我可以举两个例子来说明在我看来继承是正确的方法,我相信还有更多

首先,如果您明智地编写代码,makeSpeak函数可能希望验证其输入是否确实是动物,而不仅仅是“它会说话”,在这种情况下,最优雅的方法是使用继承。同样,您可以用其他方式来实现,但这就是面向对象设计与继承的美妙之处——您的代码将“真正”检查输入是否是“动物”

第二,显然更直接的是封装——面向对象设计的另一个组成部分。当祖先具有数据成员和/或非抽象方法时,这就变得相关了。举一个愚蠢的例子,在这个例子中,祖先有一个函数(说两遍)调用一个当时的抽象函数:

class Animal(object):
    def speak(self):
        raise NotImplementedError()

    def speak_twice(self):
        self.speak()
        self.speak()

class Dog(Animal):
    def speak(self):
        print "woff!"

class Cat(Animal):
    def speak(self):
        print "meow"
假设
“说两遍”
是一个重要的特性,您不想同时在Dog和Cat中对其进行编码,我相信您可以推断出这个示例。当然,您可以实现一个Python独立函数,该函数将接受一些duck类型的对象,检查它是否有speak函数并调用它两次,但这既不优雅,也忽略了第1点(验证它是动物)。更糟糕的是,为了加强封装示例,如果子类中的成员函数想要使用
“说两遍”
,该怎么办

如果祖先类有一个数据成员,例如
“腿的数量”
,它被祖先类中的非抽象方法使用,如
“腿的数量”
,但在后代类的构造函数中启动(例如,Dog将用4初始化它,Snake将用0初始化它)


同样,我相信还有无数的例子,但基本上每一个(足够大的)基于面向对象设计的软件都需要继承。

Python中的类基本上只是对一组函数和数据进行分组的方法。。它们与C++中的类和…

不同。 我主要看到继承用于重写超类的方法。例如,可能更像Python的继承用法是

from world.animals import Dog

class Cat(Dog):
    def speak(self):
        print "meow"
当然猫不是狗的一种,但我有一个(第三方)
dog
类,它工作得很好,除了我想覆盖的
speak
方法之外——这节省了重新实现整个类的时间,就这样它发出喵喵声。同样,虽然猫不是狗的一种,但是猫确实继承了很多属性

重写方法或属性的更好(实用)示例
from world.animals import Dog

class Cat(Dog):
    def speak(self):
        print "meow"
import urllib

class AppURLopener(urllib.FancyURLopener):
    version = "App/1.7"

urllib._urlopener = AppURLopener()
class AnimalError(Exception):
    pass

class AnimalBrokenLegError(AnimalError):
    pass

class AnimalSickError(AnimalError):
    pass
command = raw_input("What do you want the dog to do?")
if command in dir(d): getattr(d,command)()
class Repeat:
    "Send a message more than once"
    def __init__(repeat, times, do):
        repeat.times = times
        repeat.do = do

    def __call__(repeat):
        for i in xrange(repeat.times):
             repeat.do()

class Speak:
    def __init__(speak, animal):
        """
        Check that the animal can speak.

        If not we can do something about it (e.g. ignore it).
        """
        speak.__call__ = animal.speak

    def twice(speak):
        Repeat(2, speak)()

class Dog:
     def speak(dog):
         print "Woof"

class Cat:
     def speak(cat):
         print "Meow"

>>> felix = Cat()
>>> Speak(felix)()
Meow

>>> fido = Dog()
>>> speak = Speak(fido)
>>> speak()
Woof

>>> speak.twice()
Woof

>>> speak_twice = Repeat(2, Speak(felix))
>>> speak_twice()
Meow
Meow
class AnimalControl(object):
    def __init__(self):
        self._animalsInTruck=[]

    def catachAnimal(self,animal):
        if isinstance(animal,Animal):
            animal.speak()  #It's upset so it speak's/maybe it should be makesNoise
            if not self._animalsInTruck.count <=10:
                self._animalsInTruck.append(animal) #It's then put in the truck.
            else:
                #make note of location, catch you later...
        else:
            return animal #It's not an Animal() type / maybe return False/0/"message"