查看原文
其他

Python基础编程——类(二)

JackTian 杰哥的IT之旅 2019-05-09

继承

编写类时,并非总是要从空白开始。如果你要编写的类是另一个现成类的特殊版本,可使用继承。一个类继承另一类时,它将自动获得另一个类的所有属性和方法;原有的类称为父类,而新类称为子类。

子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。

子类的方法__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语句。

往期精彩回顾Python变量和简单数据类型(一)Python变量和简单数据类型(二)Python编程入门到实践—列表篇(一)Python编程入门到实践—列表篇(二)Python基础编程—操作列表篇(一)Python基础编程—操作列表篇(二)Python基础编程——if语句篇(一)Python基础编程——if语句篇(二)Python基础编程—字典篇(一)Python基础编程—字典篇(二)Python基础编程——函数(一)Python基础编程——函数(二)Python基础编程——类(一)TCP/IP协议及三次握手、四次断开详解Linux下MySQL基本操作Hadoop基础理论知识


文章已于修改

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存