继承
**编写类时,并非总是要从空白开始。如果你要编写的类是另一个现成类的特殊版本,可使用继承。一个类继承另一类时,它将自动获得另一个类的所有属性和方法;原有的类称为父类,而新类称为子类。
**
子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。
子类的方法__init_()
创建子类的实例时,Python首先需要完成的任务是给父类的所有属性赋值。
创建子类时,父类必须包含在当前文件中,且位于子类前面。定义了子类ElectricCar。定义子类时,必须在括号内指定父类的名称。方法__init__()接受创建Car实例所需的信息。
super()是一个特殊函数,将父类和子类关联起来。这行代码让Python调用ElectricCar的父类的方法__init__(),让ElectricCar实例包含父类的所有属性。
为测试继承是否能够正确的发挥作用,我们创建ElectricCar类的一个实例,并将其存储在变量my_tesla中。这行代码调用ElectricCar类中定义的方法__init__(),后者让Python调用父类Car中定义的方法__init__()。
给子类定义属性和方法
让一个类继承另一个类后,可添加区分子类和父类所需的新属性和方法。
首先,我们添加了新属性self.battery_size,并设置其初始值70.根据ElectricCar类创建的所有实例都将包含这个属性,但所有Car实例都不包含它。还添加了一名为describe_battery()的方法。对于ElectricCar类的特殊化程度没有任何限制。
重写父类的方法
对于父类的方法,只要它不符合子类模拟的实物行为,都可对其进行重写。为此,可在子类中定义一个这样的方法,即它与要重写的父类方法相同。
将实例用作属性
使用代码模拟实物时,可能会发现自己给类添加的细节越来越多:属性和方法清单以及文件越来越长。这种情况下,可能需要将类的一部分作为一个独立的类提取出来。
class Car():
"""一次模拟汽车的简单尝试"""
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
long_name = str(self.year) + ' ' + self.make + ' ' + self.model
return long_name.title()
def read_odometer(self):
print("This car has " + str(self.odometer_reading) + " miles on it.")
def update_odometer(self, mileage):
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
def increment_odometer(self, miles):
self.odometer_reading += miles
class Battery():
def __init__(self,battery_size=70):
self.battery_size = battery_size
def decribe_battery(self):
print("This car has a " + str(self.battery_size) + "-kWh battery.")
class ElectricCar(Car):
def __init__(self, make, model, year):
super().__init__(make, model, year)
self.battery = Battery()
my_tesla = ElectricCar('tesla','model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.decribe_battery()
首先,我们定义一个名为Battery的新类,它没有继承任何类。方法__init__()除self外,还有另一个形参battery_size。这个形参是可选的:如果没有给它提供值,将设置为70.方法describe_battery()也移到了这个类中。
在ElectricCar类中,添加了一个名为self.battery的属性。并将该实际存储在属性self.battery中。每当方法__init__()被调用时,都将执行该操作。
导入单个类
随着你不断地给类添加功能,文件可能变得很长,即便你妥善地使用了继承。为遵循python的总体理念,应让文件尽可能整洁。下面来创建一个值包含Car类的模块。这让我们面临一个微妙的命名问题:在上篇文章中,已经有一个名为car.py的文件,因为它包含表示汽车的代码。我们将这样解决这个命名问题:将Car类存储在一个名为car.py的模块中,该模块将覆盖前面使用的文件car.py。
上图,我们包含了一个模块级文档字符串,对该模块的内容做了简要的描述。下面来创建另一个文件——my_car.py,在其中导入Car类并创建其实例。
import语句让Python打开模块car,并导入其中的Car类。
在一个模块中存储多个类
虽然同一个模块中的类之间应存在某种相关性,但可根据需要在一个模块中存储任意数量的类。
class Car():
"""一次模拟汽车的简单尝试"""
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
long_name = str(self.year) + ' ' + self.make + ' ' + self.model
return long_name.title()
def read_odometer(self):
print("This car has " + str(self.odometer_reading) + " miles on it.")
def update_odometer(self, mileage):
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
def increment_odometer(self, miles):
self.odometer_reading += miles
class Battery():
def __init__(self,battery_size=70):
self.battery_size = battery_size
def decribe_battery(self):
print("This car has a " + str(self.battery_size) + "-kWh battery.")
def get_range(self):
if self.battery_size == 70:
range = 240
elif self.battery_size == 85:
range = 270
message = "This car can go approximately " + str(range)
message += "miles on a full charge."
print(message)
class ElectricCar(Car):
def __init__(self, make, model, year):
super().__init__(make, model, year)
self.battery = Battery()
新建一个名为my_electric_car.py的文件,导入ElectricCar类;
from car import ElectricCar
my_tesla = ElectricCar('tesla','model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.decribe_battery()
my_tesla.battery.get_range()
输出与前面看到的相同,但大部分逻辑都隐藏在一个模块中;
从一个模块中导入多个类
可根据需要在程序文件中导入任意数量的类。
从一个模块中导入多个类时,用逗号分隔了各个类。以上红点3和红点6代码行分别创建了普通汽车和电动汽车;
导入整个模块
导入整个模块,在使用句点表示访问需要的类。由于创建类实例的代码都包含模块名,因此不会与当前文件使用的任何名称发生冲突;
在一个模块中导入另一个模块
有时候,需要将类分散到多个模块中,以免模块太大,或在同一个模块中存储不相关的类。将类存储在多个模块中时,你可能会发现一个模块中的类依赖于另一个模块中的类。这种情况下,可在前一个模块中导入必要的类。
将Car类存储在一个模块中,并将ElectricCar和Battery类存储在另一个模块中。将第二个模块名名为electric_car.py,并将Battery和ElectricCar类复制到这个模块中
将Car类导入该模块中。如果我们忘记第一行代码,Python将在我们试图创建ElectricCar实例时引发错误。我们还需更新模块car,使其包含Car类;
现在可以分别从每个模块中导入类;
从模块car中导入了Car类,并从模块中electric_car中导入ElectricCar类。
类编码风格
类名应采用驼峰命名法,即将类命中的每个单词的首字母都大写,而不是用下划线。实例名和模块名都采用小写格式,并在单词之间加上下划线。
对于每个类,都应紧跟在类定义后面包含一个文档字符串。这种字符串简要****地描述类的功能,并遵循编写函数的文档字符串时采用的格式约定。每个模块也都应包含一个文档字符串,对其中的类可用于做什么进行描述。
可使用空行来组织代码,但不要滥用。在勒种,可使用一个空行来分割方法;而在模块中,可使用两个空行来分隔类。
需要同时导入标准库的模块和你编写的模块时,先编写导入标准库模块的import语句,再添加一个空行,然后编写导入你自己编写的模块import语句。
往期 精彩回顾
本文分享自微信公众号 - 杰哥的IT之旅(Jake_Internet)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。