博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
03python面向对象编程2
阅读量:5967 次
发布时间:2019-06-19

本文共 7334 字,大约阅读时间需要 24 分钟。

 

3.继承

如果你要编写的类是另一个现成类的特殊版本,可使用继承。一个类继承另一个类时,它将自动获得另一个类的所有属性和方法;原有的类称为父类,而新类称为子类。子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。

3.1子类的方法 init()

创建子类的实例时,Python首先需要完成的任务是给父类的所有属性赋值。为此,子类的方法 init() 需要父类施以援手。
例如,下面来模拟电动汽车。电动汽车是一种特殊的汽车,因此我们可以在前面创建的 Car类的基础上创建新类 ElectricCar ,这样我们就只需为电动汽车特有的属性和行为编写代码。下面来创建一个简单的 ElectricCar 类版本,它具备 Car 类的所有功能:

In [1]:
"""A class that can be used to represent a car."""class Car():    """A simple attempt to represent a car."""    def __init__(self, manufacturer, model, year):        """Initialize attributes to describe a car."""        self.manufacturer = manufacturer        self.model = model        self.year = year        self.odometer_reading = 0            def get_descriptive_name(self):        """Return a neatly formatted descriptive name."""        long_name = str(self.year) + ' ' + self.manufacturer + ' ' + self.model        return long_name.title()        def read_odometer(self):        """Print a statement showing the car's mileage."""        print("This car has " + str(self.odometer_reading) + " miles on it.")            def update_odometer(self, mileage):        """        Set the odometer reading to the given value.        Reject the change if it attempts to roll the odometer back.        """        if mileage >= self.odometer_reading:            self.odometer_reading = mileage        else:            print("You can't roll back an odometer!")        def increment_odometer(self, miles):        """Add the given amount to the odometer reading."""        self.odometer_reading += miles
In [2]:
class ElectricCar(Car):    """Models aspects of a car, specific to electric vehicles."""    def __init__(self, manufacturer, model, year):        """        Initialize attributes of the parent class.        Then initialize attributes specific to an electric car.        """        super().__init__(manufacturer, model, year)

首先是 Car 类的代码。创建子类时,父类必须包含在当前文件中,且位于子类前面。我们定义了子类 ElectricCar 。定义子类时,必须在括号内指定父类的名称。方法 init()接受创建 Car 实例所需的信息。

super() 是一个特殊函数,帮助Python将父类和子类关联起来。这行代码让Python调用 ElectricCar 的父类的方法 init() ,让 ElectricCar 实例包含父类的所有属性。父类也称为超 类(superclass),名称super因此而得名。

为测试继承是否能够正确地发挥作用,我们尝试创建一辆电动汽车,但提供的信息与创建普通汽车时相同。在处,我们创建 ElectricCar 类的一个实例,并将其存储在变量 my_tesla 中。这行代码调用 ElectricCar 类中定义的方法 init() ,后者让Python调用父类 Car 中定义的方法 init() 。我们提供了实参 'tesla' 、 'model s' 和 2016 。 除方法 init() 外,电动汽车没有其他特有的属性和方法。当前,我们只想确认电动汽车具备普通汽车的行为:

In [3]:
my_tesla = ElectricCar('tesla', 'model s', 2016)print(my_tesla.get_descriptive_name())
2016 Tesla Model S
 

3.2 Python2.7中的继承。

在Python 2.7中,继承语法稍有不同, ElectricCar 类的定义类似于下面这样:
函数 super() 需要两个实参:子类名和对象 self 。为帮助Python将父类和子类关联起来,这些实参必不可少。另外,在Python 2.7中使用继承时,务必在定义父类时在括号内指定 object 。

In [4]:
# class Car(object):#     def __init__(self, make, model, year):#     -- snip --# class ElectricCar(Car):#     def __init__(self, make, model, year):#         super(ElectricCar, self).__init__(make, model, year)#         -- snip --
 

3.3 给子类定义属性和方法

让一个类继承另一个类后,可添加区分子类和父类所需的新属性和方法。 下面来添加一个电动汽车特有的属性(电瓶),以及一个描述该属性的方法。我们将存储电 瓶容量,并编写一个打印电瓶描述的方法:

In [5]:
class ElectricCar(Car):    """Models aspects of a car, specific to electric vehicles."""    def __init__(self, manufacturer, model, year):        """        Initialize attributes of the parent class.        Then initialize attributes specific to an electric car.        """        super().__init__(manufacturer, model, year)        self.battery_size = 70            def describe_battery(self):        """打印一条描述电瓶容量的消息"""        print("This car has a " + str(self.battery_size) + "-kWh battery.")
In [6]:
my_tesla = ElectricCar('tesla', 'model s', 2016)print(my_tesla.get_descriptive_name())my_tesla.describe_battery()
2016 Tesla Model SThis car has a 70-kWh battery.
 

3.4 重写父类的方法

对于父类的方法,只要它不符合子类模拟的实物的行为,都可对其进行重写。为此,可在子 类中定义一个这样的方法,即它与要重写的父类方法同名。这样,Python将不会考虑这个父类方 法,而只关注你在子类中定义的相应方法。 假设 Car 类有一个名为 fill_gas_tank() 的方法,它对全电动汽车来说毫无意义,因此你可能 想重写它。下面演示了一种重写方式:

In [7]:
# class ElectricCar(Car):#     -- snip --#     def fill_gas_tank(self):#         """电动汽车没有油箱"""#         print("This car doesn't need a gas tank!")

现在,如果有人对电动汽车调用方法 fill_gas_tank() ,Python将忽略 Car 类中的方法 fill_gas_tank() ,转而运行上述代码。使用继承时,可让子类保留从父类那里继承而来的精华, 并剔除不需要的糟粕。

 

3.5 将实例用作属性

使用代码模拟实物时,你可能会发现自己给类添加的细节越来越多:属性和方法清单以及文 件都越来越长。在这种情况下,可能需要将类的一部分作为一个独立的类提取出来。你可以将大 型类拆分成多个协同工作的小类。

例如,不断给 ElectricCar 类添加细节时,我们可能会发现其中包含很多专门针对汽车电瓶 的属性和方法。在这种情况下,我们可将这些属性和方法提取出来,放到另一个名为 Battery 的 类中,并将一个 Battery 实例用作 ElectricCar 类的一个属性:

In [10]:
# class Car():#     -- snip --class Battery():    """A simple attempt to model a battery for an electric car."""    def __init__(self, battery_size=60):        """Initialize the batteery's attributes."""        self.battery_size = battery_size    def describe_battery(self):        """Print a statement describing the battery size."""        print("This car has a " + str(self.battery_size) + "-kWh battery.")
In [11]:
class ElectricCar(Car):    """Models aspects of a car, specific to electric vehicles."""    def __init__(self, manufacturer, model, year):        """        Initialize attributes of the parent class.        Then initialize attributes specific to an electric car.        """        super().__init__(manufacturer, model, year)        self.battery = Battery()

我们定义了一个名为 Battery 的新类,它没有继承任何类。方法 init() 除 self 外,还有另一个形参 battery_size 。这个形参是可选的:如果没有给它提供值,电瓶容量将 被设置为60。方法 describe_battery() 也移到了这个类中。

在 ElectricCar 类中,我们添加了一个名为 self.battery 的属性。这行代码让Python 创建一个新的 Battery 实例(由于没有指定尺寸,因此为默认值 60 ),并将该实例存储在属性 self.battery 中。每当方法 init() 被调用时,都将执行该操作;因此现在每个 ElectricCar 实 例都包含一个自动创建的 Battery 实例。

In [13]:
my_tesla = ElectricCar('tesla', 'model s', 2016)print(my_tesla.get_descriptive_name())my_tesla.battery.describe_battery()
2016 Tesla Model SThis car has a 60-kWh battery.
In [14]:
class Battery():    """A simple attempt to model a battery for an electric car."""    def __init__(self, battery_size=60):        """Initialize the batteery's attributes."""        self.battery_size = battery_size    def describe_battery(self):        """Print a statement describing the battery size."""        print("This car has a " + str(self.battery_size) + "-kWh battery.")              def get_range(self):        """Print a statement about the range this battery provides."""        if self.battery_size == 60:            range = 140        elif self.battery_size == 85:            range = 185        else:            range = 200        message = "This car can go approximately " + str(range)        message += " miles on a full charge."        print(message)
In [15]:
my_tesla = ElectricCar('tesla', 'model s', 2016)print(my_tesla.get_descriptive_name())my_tesla.battery.describe_battery()my_tesla.battery.get_range()
2016 Tesla Model SThis car has a 60-kWh battery.This car can go approximately 140 miles on a full charge.

新增的方法 get_range()。

 

3.6 模拟实物

模拟较复杂的物件(如电动汽车)时,需要解决一些有趣的问题。续航里程是电瓶的属性还 是汽车的属性呢?如果我们只需描述一辆汽车,那么将方法 get_range() 放在 Battery 类中也许是合 适的;但如果要描述一家汽车制造商的整个产品线,也许应该将方法 get_range() 移到 ElectricCar 类中。在这种情况下, get_range() 依然根据电瓶容量来确定续航里程,但报告的是一款汽车的续 航里程。我们也可以这样做:将方法 get_range() 还留在 Battery 类中,但向它传递一个参数,如 car_model ;在这种情况下,方法 get_range() 将根据电瓶容量和汽车型号报告续航里程。

这让你进入了程序员的另一个境界:解决上述问题时,你从较高的逻辑层面(而不是语法层 面)考虑;你考虑的不是Python,而是如何使用代码来表示实物。到达这种境界后,你经常会发 现,现实世界的建模方法并没有对错之分。有些方法的效率更高,但要找出效率最高的表示法,需要经过一定的实践。只要代码像你希望的那样运行,就说明你做得很好!即便你发现自己不得 不多次尝试使用不同的方法来重写类,也不必气馁;要编写出高效、准确的代码,都得经过这样的过程。

 
 

转载于:https://www.cnblogs.com/xinmomoyan/p/10806982.html

你可能感兴趣的文章
Devexpress 15.1.8 Breaking Changes
查看>>
ElasticSearch Client详解
查看>>
mybatis update返回值的意义
查看>>
expdp 详解及实例
查看>>
通过IP判断登录地址
查看>>
深入浅出JavaScript (五) 详解Document.write()方法
查看>>
Beta冲刺——day6
查看>>
在一个程序中调用另一个程序并且传输数据到选择屏幕执行这个程序
查看>>
代码生成工具Database2Sharp中增加视图的代码生成以及主从表界面生成功能
查看>>
关于在VS2005中编写DLL遇到 C4251 警告的解决办法
查看>>
提高信息安全意识对网络勒索病毒说不
查看>>
使用Jquery 加载页面时调用JS
查看>>
css+div+jquery弹出层
查看>>
求职相关(链接,不定期更新)
查看>>
pdo 连接数据库 报错 could not find driver 解决方法
查看>>
maya pyside 多个窗口实例 报错 解决
查看>>
我的友情链接
查看>>
通知中心
查看>>
我的友情链接
查看>>
MVC中的三个模块
查看>>