返回介绍

4.5 继承

发布于 2024-01-21 22:13:25 字数 3301 浏览 0 评论 0 收藏 0

面向对象的编程带来的好处之一是代码的重用,实现这种重用方法之一是通过继承 机制。继承是两个类或多个类之间的父子关系,子类继承了基类的所有公有数据属性和方法,并且可以通过编写子类的代码扩充子类的功能。开个玩笑地说,如果人类可以做到儿女继承了父母的所有才学并加以拓展,那么人类的发展至少是现在的数万倍。继承实现了数据属性和方法的重用,减少了代码的冗余度。

那么我们何时需要使用继承呢?如果我们需要的类中具有公共的成员,且具有一定的递进关系,那么就可以使用继承,且让结构最简单的类作为基类。一般来说,子类是父类的特殊化,如下面的关系:

哺乳类动物——>狗——>特定狗种

特定狗种类继承狗类,狗类继承哺乳动物类,狗类编写了描述所有狗种公有的行为的方法而特定狗种类则增加了该狗种特有的行为。不过继承也有一定弊端,可能基类对于子类也有一定特殊的地方,如某种特定狗种不具有绝大部分狗种的行为,当程序员没有理清类间的关系时,可能使得子类具有了不该有的方法。另外,如果继承链太长的话,任何一点小的变化都会引起一连串变化,我们使用的继承要注意控制继承链的规模。

继承语法:class子类名(基类名1,基类名2,…)基类写在括号里,如果有多个基类,则需要全部都写在括号里,这种情况称为多继承 。在Python中继承有以下一些特点:

1)在继承中基类初始化方法__init__不会被自动调用。如果希望子类调用基类的__init__方法,需要在子类的__init__方法中显示调用了它。这与C++和C#区别很大。

2)在调用基类的方法时,需要加上基类的类名前缀,且带上self参数变量。注意在类中调用该类中定义的方法时不需要self参数。

3)Python总是首先查找对应类的方法,如果在子类中没有对应的方法,Python才会在继承链的基类中按顺序查找。

4)在Python继承中,子类不能访问基类的私有成员。

我们最后一次修改类Charmander的代码,如代码清单4-6所示:

代码清单4-6 自定义类5

class pokemon:
    def __init__(self,name,gender,level,type,status):
        self.__type = type
        self.__gender = gender
        self.__name = name
        self.__level = level
        self.__status = status
        self.__info = [self.__name,self.__type,self.__gender,self.__level, self.__status]
        self.__index = -1
    def getName(self):
        return self.__name
    def getGender(self):
        return self.__gender
    def getType(self):
        return self.__type
    def getStatus(self):
        return self.__status
    def level_up(self):
        self.__status = [s+1 for s in self.__status]
        self.__status[0]+=1  # HP每级增加
2点,其余
1点
    def __iter__(self):
        print '名字
 属性
 性别
 等级
 能力
'
        return self
    def next(self):
        if self.__index ==len(self.__info)-1:
            raise StopIteration
        self.__index += 1
        return self.__info[self.__index]
class Charmander(pokemon):
    def __init__(self,name,gender,level):
        self.__type = ('fire',None)
        self.__gender = gender
        self.__name = name
        self.__level = level
        # 最大
HP,攻击,防御,特攻,特防,速度
        self.__status = [10+2*level,5+1*level,5+1*level,5+1*level,5+1*level,5+1*
level]
        pokemon.__init__(self,self.__name,self.__gender,self.__level,self.__type, self.__status)

*代码详见:示例程序/code/4-5.py

>>> pokemon1 = Charmander('Bang','male',5)
>>> print pokemon1.getGender()
male
>>> for info in pokemon1:
        print info
Bang ('fire', None) male 5 [20, 10, 10, 10, 10, 10]

我们定义了Charmander类的基类pokemon,将精灵共有的行为都放到基类中,子类仅仅需要向基类传输数据属性即可。这样做可以很轻松地定义其他基于pokemon类的子类。因为精灵宝可梦的精灵有数百只,使用继承的方法大大减少了代码量,且当需要对全部精灵进行整体修改时仅需修改pokemon类即可。可以看到我们Charmander类的__init__函数中显示调用了pokemon类的__init__函数,并向基类传输数据,这里注意要加self参数。Charmander类没有继承基类的私有数据属性,因此在子类中只有一个self.__type,不会出现因继承所造成的重名情况。为了能更清晰地讲述这个问题,这里再举一个例子,如代码清单4-7所示:

代码清单4-7 私有成员无法继承

class animal:
    def __init__(self,age):
        self.__age = age
    def print2(self):
        print self.__age
class dog(animal):
    def __init__(self,age):
        animal.__init__(self,age)
    def print2(self):
        print self.__age
a_animal = animal(10)
a_animal.print2()
#result: 10
a_dog = dog(10)
a_dog.print2()
# 程序报错,
AttributeError: dog instance has no attribute '_dog__age'

*代码详见:示例程序/code/4-5.py

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文