类和对象
类是用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。基于类创建 对象时,每个对象都自动具备这种通用行为,然后可根据需要赋予每个对象独特的个性。根据类来创建对象被称为 实例化,这让我们能够使用类的实例。
1. 类与对象的创建和使用
使用类几乎可以模拟任何东西。在Python 3 中,创建和使用类的具体格式如下:
class ClassName():
""" 文档字符串 1"""
def __init__(self,[属性1],[属性2],,..[属性N])
self.属性1 = 属性1
self.属性2 = 属性2
.
.
.
self.属性N= 属性N
self.属性x= 默认值1
self.属性y= 默认值1
def function_name(self,[属性x],[属性y]]):
""" 文档字符串2 """
self.属性x=属性x
self.属性y= 属性y
return 返回值
变量 = ClassName([属性1],[属性2],,..[属性N])
变量.function_name
说明:
(1)创建类使用关键字class。
(2)类名的首字母必须大写,且类名有多个单词组成时,每个单词的首字母都需大写,中间不需要使用任何符号,紧接着写即可。
(3)类中的函数称为方法。每个类都具有内置的方法__init__(),该方法的名称中,开头和末尾各有两个下划线,这是一种约定,旨在避免Python默认方法与普通方法发生名称冲突。其中除self之外,还能具有其他属性,还能给属性指定默认值。
(4)在类中。可定于除__init__()之外的其他函数,其可用于属于自己的属性。
(5)可以将属性的新值覆盖默认值。
(6)类的使用直接使用类名,紧接括号,然后再在括号中提供相应的值。
(7)为了方便,一般将调用类返回的结果赋值给一遍变量,然后再用变量.function_name,即可调用类中的方法。
例如,创建汽车的类,并调用它。
代码:
1 class Car(): 2 """一次模拟汽车的简单尝试""" 3 def __init__(self, make, model, year): 4 """初始化描述汽车的属性""" 5 self.make = make 6 self.model = model 7 self.year = year 8 def get_descriptive_name(self): 9 """返回整洁的描述性信息""" 10 long_name = str(self.year) + ' ' + self.make + ' ' + self.model 11 return long_name.title() 12 13 my_car = Car('audi', 'Q8', 2018) 14 print(my_car.get_descriptive_name())
说明:
第1行,用关键字class创建一个汽车的类Car。
第2行,使用文档字符串概述该类的所能完成的任务。
第3~7行,使用关键字 def 定义了__init__() 方法,并对其属性进行初始化。
第8~11行,用关键字def创建get_descriptive_name()方法,返回整洁的描述信息。
第13行,调用创建的Car类,实例化一个对象,给对象将会鞠咏该类的属性和方法。
第14行,调用类中的get_descriptive_name()方法。
运行结果:
2018 Audi Q8
注:
在Python2.7 中创建类的唯一区别是,需要在类名的括号中写上object,即:
class ClassName (object):
2. 指定属性的默认值
类中的每个属性都必须有初始值,哪怕这个值是0或空字符串。在有些情况下,如设置默认值时,在方法 __init__() 内指定这种初始值是可行的;如果你对某个属性这样做了,就无需包含为它提供初始值的形参。
例如,我们给类Car添加一个名为 odometer_reading 的属性,其初始值总是为0。我们再添加了一个名为read_odometer() 的方法,用于读取汽车的里程表。
代码:
1 class Car(): 2 """一次模拟汽车的简单尝试""" 3 def __init__(self, make, model, year): 4 """初始化描述汽车的属性""" 5 self.make = make 6 self.model = model 7 self.year = year 8 self.odometer_reading = 0 9 10 def get_descriptive_name(self): 11 """返回整洁的描述性信息""" 12 long_name = str(self.year) + ' ' + self.make + ' ' + self.model 13 return long_name.title() 14 15 def read_odometer(self): 16 """打印一条指出汽车里程的消息""" 17 print("This car has " + str(self.odometer_reading) + " miles on it.") 18 19 my_car = Car('audi', 'Q8', 2018) 20 print(my_car.get_descriptive_name()) 21 print(my_car.read_odometer())
说明:
第8行,增加了一个属性 odometer_reading ,并将其初始化为0。
第15~17行,用def关键字定义了一个read_odometer() 方法,用于读取汽车的里程表。
第21行,调用新增加的read_odometer() 方法。
运行结果:
1 2018 Audi Q8 2 This car has 0 miles on it. 3 None
从以上运行结果可知,当我们没有给方法指定返回值时,则其默认返回None。
3. 修改属性的值
3.1 直接修改属性的值
要修改属性的值,最简单的方式是通过实例直接访问它。
例如,在类Car中,直接将里程表读数设置20。
代码:
1 class Car(): 2 """一次模拟汽车的简单尝试""" 3 def __init__(self, make, model, year): 4 """初始化描述汽车的属性""" 5 self.make = make 6 self.model = model 7 self.year = year 8 self.odometer_reading = 0 9 10 def get_descriptive_name(self): 11 """返回整洁的描述性信息""" 12 long_name = str(self.year) + ' ' + self.make + ' ' + self.model 13 return long_name.title() 14 15 def read_odometer(self): 16 """打印一条指出汽车里程的消息""" 17 print("This car has " + str(self.odometer_reading) + " miles on it.") 18 19 my_car = Car('audi', 'Q8', 2018) 20 print(my_car.get_descriptive_name()) 21 my_car.read_odometer() 22 23 my_car.odometer_reading = 20 24 my_car.read_odometer()
说明:
第23行,直接将汽车的属性odometer_reading的值改为20。
第24行,再次调用read_odometer()方法,显示汽车里程表的数据。
运行结果:
1 2018 Audi Q8 2 This car has 0 miles on it. 3 This car has 20 miles on it.
从以上运行结果可知,里程表读数被修改为20。
3.2 通过方法修改属性的值
在类中增加修改方法属性的值,这样每次只修将值传给该方法即可。
例如,在类Car中,增加一个修改属性odometer_reading值的方法update_odometer()。
代码:
1 class Car(): 2 """一次模拟汽车的简单尝试""" 3 def __init__(self, make, model, year): 4 """初始化描述汽车的属性""" 5 self.make = make 6 self.model = model 7 self.year = year 8 self.odometer_reading = 0 9 10 def get_descriptive_name(self): 11 """返回整洁的描述性信息""" 12 long_name = str(self.year) + ' ' + self.make + ' ' + self.model 13 return long_name.title() 14 15 def read_odometer(self): 16 """打印一条指出汽车里程的消息""" 17 print("This car has " + str(self.odometer_reading) + " miles on it.") 18 19 def update_odometer(self, mileage): 20 """将里程表读数设置为指定的值""" 21 22 self.odometer_reading = mileage 23 24 my_car = Car('audi', 'Q8', 2018) 25 print(my_car.get_descriptive_name()) 26 my_car.read_odometer() 27 28 my_car.update_odometer(20) 29 my_car.read_odometer()
说明:
第19~22行,用关键字def定义了一个update_odometer()方法,用于接受汽车里程来修改里程表的数据。
第28行,调用类中的update_odometer()方法,并传给其一个20的值。该方法会用该值取修改属性的初始化的值0。
运行结果:
1 2018 Audi Q8 2 This car has 0 miles on it. 3 This car has 20 miles on it.
3.3 通过方法对属性的值进行递增
有时我们需要将属性值递增特定的量,而不是将其设置为全新的值。
例如,在类Car中,增加一个方法increment_odometer() ,接受一个值,修改属性odometer_reading的为递增的形式。
代码:
1 class Car(): 2 """一次模拟汽车的简单尝试""" 3 def __init__(self, make, model, year): 4 """初始化描述汽车的属性""" 5 self.make = make 6 self.model = model 7 self.year = year 8 self.odometer_reading = 0 9 10 def get_descriptive_name(self): 11 """返回整洁的描述性信息""" 12 long_name = str(self.year) + ' ' + self.make + ' ' + self.model 13 return long_name.title() 14 15 def read_odometer(self): 16 """打印一条指出汽车里程的消息""" 17 print("This car has " + str(self.odometer_reading) + " miles on it.") 18 19 def update_odometer(self, mileage): 20 """将里程表读数设置为指定的值""" 21 self.odometer_reading = mileage 22 23 def increment_odometer(self, miles): 24 """将里程表读数增加指定的量""" 25 self.odometer_reading += miles 26 27 my_car = Car('audi', 'Q8', 2018) 28 print(my_car.get_descriptive_name()) 29 my_car.read_odometer() 30 31 my_car.update_odometer(20) 32 my_car.read_odometer() 33 34 my_car.increment_odometer(10) 35 my_car.read_odometer()
说明:
第23~25行,使用关键字def定义了一个increment_odometer()方法,将汽车的里程数据递增。
运行结果:
1 2018 Audi Q8 2 This car has 0 miles on it. 3 This car has 20 miles on it. 4 This car has 30 miles on it.
从以上的运行结果可知,汽车的里程表数据默认为0,然后被修改为20,最后在原有的基础上递增了10,所以最终为30。
2. 继承
编写类时,并非总是要从空白开始。如果你要编写的类是另一个现成类的特殊版本,可使用继承。一个类继承另一个类时,它将自动获得另一个类的所有属性和方法;原有的类称为父类,而新类称为子类。子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。
2.1 子类的 __init__()方法
创建子类的实例时,Python首先需要完成的任务是给父类的所有属性赋值。为此,子类的 __init__() 方法需要父类施以援手。
例如,电动汽车是一种特殊的汽车,创建新类 ElectricCar 来继承 Car类 。
代码:
1 class Car(): 2 """一次模拟汽车的简单尝试""" 3 def __init__(self, make, model, year): 4 """初始化描述汽车的属性""" 5 self.make = make 6 self.model = model 7 self.year = year 8 self.odometer_reading = 0 9 10 def get_descriptive_name(self): 11 """返回整洁的描述性信息""" 12 long_name = str(self.year) + ' ' + self.make + ' ' + self.model 13 return long_name.title() 14 15 def read_odometer(self): 16 """打印一条指出汽车里程的消息""" 17 print("This car has " + str(self.odometer_reading) + " miles on it.") 18 19 def update_odometer(self, mileage): 20 """将里程表读数设置为指定的值""" 21 self.odometer_reading = mileage 22 23 def increment_odometer(self, miles): 24 """将里程表读数增加指定的量""" 25 self.odometer_reading += miles 26 27 class ElectricCar(Car): 28 """电动汽车的独特之处""" 29 def __init__(self, make, model, year): 30 """初始化父类的属性""" 31 super().__init__(make, model, year) 32 33 my_tesla = ElectricCar('tesla', 'model s', 2018) 34 print(my_tesla.get_descriptive_name())
说明:
第27行,使用关键字class 定义了一个电动汽车的类ElectricCar,并且继承了汽车的类Car。
第29行,使用关键字def 定义__init__()方法,该方法接受创建 Car 实例所需的信息。
第31行, 使用super() 方法将父类和子类关联起来。
注意:以上所有定义类和调用类方法时,都是在Python3中进行的,如果实在Python 2.7中,继承语法稍有不同, 需要在super() 方法的括号中写上父类名称及self。那么31行需改为以下形式:
super(ElectricCar, self).__init__(make, model, year)
运行结果:
2018 Tesla Model S
2.2 给子类定义属性和方法
子类经过继承,毕竟可拥有父类的属性和方法,还能定义自己特有的属性和方法。
例如,电动汽车不仅具有汽车的属性和方法,还有一个电瓶的属性。现在给其增加一个属性battery_size,并创建一个方法来显示它的容量。
代码:
1 class Car(): 2 """一次模拟汽车的简单尝试""" 3 def __init__(self, make, model, year): 4 """初始化描述汽车的属性""" 5 self.make = make 6 self.model = model 7 self.year = year 8 self.odometer_reading = 0 9 10 def get_descriptive_name(self): 11 """返回整洁的描述性信息""" 12 long_name = str(self.year) + ' ' + self.make + ' ' + self.model 13 return long_name.title() 14 15 def read_odometer(self): 16 """打印一条指出汽车里程的消息""" 17 print("This car has " + str(self.odometer_reading) + " miles on it.") 18 19 def update_odometer(self, mileage): 20 """将里程表读数设置为指定的值""" 21 self.odometer_reading = mileage 22 23 def increment_odometer(self, miles): 24 """将里程表读数增加指定的量""" 25 self.odometer_reading += miles 26 27 class ElectricCar(Car): 28 """电动汽车的独特之处""" 29 def __init__(self, make, model, year): 30 """初始化父类的属性,再初始化电动汽车特有的属性""" 31 super().__init__(make, model, year) 32 self.battery_size = 80 33 34 def describe_battery(self): 35 """打印一条描述电瓶容量的消息""" 36 print("This car has a " + str(self.battery_size) + "-kWh battery.") 37 38 my_tesla = ElectricCar('tesla', 'model s', 2018) 39 print(my_tesla.get_descriptive_name()) 40 my_tesla.describe_battery()
说明:
第32行,初始化电动汽车特有的属性,将其初始化为80。
第34~36行,使用关键字def定义一个describe_battery()方法来显示电动汽车的电瓶容量大小。
第40行,调用电动汽车特有的属性的显示方法。
运行结果:
1 2018 Tesla Model S 2 This car has a 80-kWh battery.
2.3 重写父类的方法
对于父类的方法,只要它不符合子类模拟的实物的行为,都可对其进行重写。为此,可在子类中定义一个与要重写的父类方法同名的方法。这样,Python将不会考虑这个父类方法,而只关注你在子类中定义的相应方法。
例如,假设 Car 类有一个名为 fill_gas_tank() 的方法,它对全电动汽车来说毫无意义,因此,请重写它。
代码:
1 class Car(): 2 """一次模拟汽车的简单尝试""" 3 def __init__(self, make, model, year): 4 """初始化描述汽车的属性""" 5 self.make = make 6 self.model = model 7 self.year = year 8 self.odometer_reading = 0 9 10 def get_descriptive_name(self): 11 """返回整洁的描述性信息""" 12 long_name = str(self.year) + ' ' + self.make + ' ' + self.model 13 return long_name.title() 14 15 def read_odometer(self): 16 """打印一条指出汽车里程的消息""" 17 print("This car has " + str(self.odometer_reading) + " miles on it.") 18 19 def update_odometer(self, mileage): 20 """将里程表读数设置为指定的值""" 21 self.odometer_reading = mileage 22 23 def increment_odometer(self, miles): 24 """将里程表读数增加指定的量""" 25 self.odometer_reading += miles 26 27 def fill_gas_tank(self): 28 """汽车油箱""" 29 print("This car need a gas tank!") 30 31 class ElectricCar(Car): 32 """电动汽车的独特之处""" 33 def __init__(self, make, model, year): 34 """初始化父类的属性,再初始化电动汽车特有的属性""" 35 super().__init__(make, model, year) 36 self.battery_size = 80 37 38 def describe_battery(self): 39 """打印一条描述电瓶容量的消息""" 40 print("This car has a " + str(self.battery_size) + "-kWh battery.") 41 42 def fill_gas_tank(self): 43 """电动汽车没有油箱""" 44 print("This car doesn't need a gas tank!") 45 46 my_tesla = ElectricCar('tesla', 'model s', 2018) 47 print(my_tesla.get_descriptive_name()) 48 my_tesla.describe_battery() 49 my_tesla.fill_gas_tank()
说明:
第27~29行,在类Car中定义了一个fill_gas_tank()方法。
第42~44行,定义了一个与父类Car中方法名称一致的方法fill_gas_tank(),即对父类方法的重写。
运行结果:
1 2018 Tesla Model S 2 This car has a 80-kWh battery. 3 This car doesn't need a gas tank!
从以上的运行结果可知,继承父类时,如果子类中的方法名跟父类中的一致,则程序只会执行子类中的方法。
2.4 将实例用作属性
用代码模拟实物时,我们可能会发现自己给类添加的细节越来越多:属性和方法清单以及文件都越来越长。在这种情况下,可能需要将类的一部分作为一个独立的类提取出来。我们可将大型类拆分成多个协同工作的小类。
例如,不断给 ElectricCar 类添加细节时,我们可能会发现其中包含很多专门针对汽车电瓶的属性和方法。在这种情况下,我们可将这些属性和方法提取出来,放到另一个名为 Battery 的类中,并将一个 Battery 实例用作 ElectricCar 类的一个属性:
代码:
1 class Car(): 2 """一次模拟汽车的简单尝试""" 3 def __init__(self, make, model, year): 4 """初始化描述汽车的属性""" 5 self.make = make 6 self.model = model 7 self.year = year 8 self.odometer_reading = 0 9 10 def get_descriptive_name(self): 11 """返回整洁的描述性信息""" 12 long_name = str(self.year) + ' ' + self.make + ' ' + self.model 13 return long_name.title() 14 15 def read_odometer(self): 16 """打印一条指出汽车里程的消息""" 17 print("This car has " + str(self.odometer_reading) + " miles on it.") 18 19 def update_odometer(self, mileage): 20 """将里程表读数设置为指定的值""" 21 self.odometer_reading = mileage 22 23 def increment_odometer(self, miles): 24 """将里程表读数增加指定的量""" 25 self.odometer_reading += miles 26 27 def fill_gas_tank(self): 28 """汽车油箱""" 29 print("This car need a gas tank!") 30 31 class Battery(): 32 """一次模拟电动汽车电瓶的简单尝试""" 33 def __init__(self, battery_size=70): 34 """初始化电瓶的属性""" 35 self.battery_size = battery_size 36 37 def describe_battery(self): 38 """打印一条描述电瓶容量的消息""" 39 print("This car has a " + str(self.battery_size) + "-kWh battery.") 40 41 class ElectricCar(Car): 42 """电动汽车的独特之处""" 43 def __init__(self, make, model, year): 44 """初始化父类的属性,再初始化电动汽车特有的属性""" 45 super().__init__(make, model, year) 46 self.battery = Battery() 47 48 def fill_gas_tank(self): 49 """电动汽车没有油箱""" 50 print("This car doesn't need a gas tank!") 51 52 my_tesla = ElectricCar('tesla', 'model s', 2018) 53 print(my_tesla.get_descriptive_name()) 54 my_tesla.battery.describe_battery()
说明:
第31行,定义了一个名为 Battery 的新类,它没有继承任何类。
第33行,方法 __init__() 除self 外,还有另一个形参 battery_size 。这个形参是可选的:如果没有给它提供值,电瓶容量将被设置为70。
第46行,在 ElectricCar 类中,我们添加了一个名为 self.battery 的属性。
运行结果:
1 2018 Tesla Model S 2 This car has a 70-kWh battery.
3. 导入类
随着我们不断地给类添加功能,文件可能变得很长,即便你妥善地使用了继承亦如此。为遵循Python的总体理念,应让文件尽可能整洁。因此,Python允许我们将类存储在模块中,然后在主程序中导入所需的模块。
3.1 导入单个类
如果一个模块中包含了多个类,但我们只想导入其中的一个类,那么导入语法如下:
from 模块名 import 类名
例如,将有关汽车的类都放到一个模块car中,然后再创建一个程序my_car.py,并导入模块car中的Car类。
模块car的代码:
1 """一个可用于表示汽车的类""" 2 class Car(): 3 """一次模拟汽车的简单尝试""" 4 def __init__(self, make, model, year): 5 """初始化描述汽车的属性""" 6 self.make = make 7 self.model = model 8 self.year = year 9 self.odometer_reading = 0 10 def get_descriptive_name(self): 11 """返回整洁的描述性名称""" 12 long_name = str(self.year) + ' ' + self.make + ' ' + self.model 13 return long_name.title() 14 15 def read_odometer(self): 16 """打印一条消息,指出汽车的里程""" 17 print("This car has " + str(self.odometer_reading) + " miles on it.") 18 19 def update_odometer(self, mileage): 20 """ 21 将里程表读数设置为指定的值 22 拒绝将里程表往回拨 23 """ 24 if mileage >= self.odometer_reading: 25 self.odometer_reading = mileage 26 else: 27 print("You can't roll back an odometer!") 28 29 def increment_odometer(self, miles): 30 """将里程表读数增加指定的量""" 31 self.odometer_reading += miles
说明:
第1行,用文档字符串描述了该模块的功能概况。
第2行,使用关键字class定义了一个Car类。
第3行,用文档字符串描述了该类的功能概况。
第4~31行,定义了该类所包含的方法。
程序my_car的代码:
1 from car import Car 2 3 my_car = Car('audi', 'Q8', 2018) 4 print(my_car.get_descriptive_name()) 5 my_car.odometer_reading = 20 6 my_car.read_odometer()
说明:
第1行,从模块car中导入类Car。
第3行,调用模块中的Car类,并将其返回值赋值给变量my_car 。
第4行,修改类Car中的属性odometer_reading 的值为20。
第5行,调用类中的方法read_odometer()显示属性odometer_reading 的值。
程序my_car的运行结果:
1 2018 Audi Q8 2 This car has 20 miles on it.
3.2 在一个模块中存储多个类
虽然同一个模块中的类之间应存在某种相关性,但可根据需要在一个模块中存储任意数量的类。具体语法格式如下:
from 模块 import 类1,类2,...,类N
例如,将电动车的类ElectricCar 也加到汽车的模块car中,并创建一个名为my_electric_car.py的程序,然后导入 ElectricCar 类,并创建一辆电动汽车了。
模块car的代码:
1 class Car(): 2 """一次模拟汽车的简单尝试""" 3 def __init__(self, make, model, year): 4 """初始化描述汽车的属性""" 5 self.make = make 6 self.model = model 7 self.year = year 8 self.odometer_reading = 0 9 def get_descriptive_name(self): 10 """返回整洁的描述性名称""" 11 long_name = str(self.year) + ' ' + self.make + ' ' + self.model 12 return long_name.title() 13 14 def read_odometer(self): 15 """打印一条消息,指出汽车的里程""" 16 print("This car has " + str(self.odometer_reading) + " miles on it.") 17 18 def update_odometer(self, mileage): 19 """ 20 将里程表读数设置为指定的值 21 拒绝将里程表往回拨 22 """ 23 if mileage >= self.odometer_reading: 24 self.odometer_reading = mileage 25 else: 26 print("You can't roll back an odometer!") 27 28 def increment_odometer(self, miles): 29 """将里程表读数增加指定的量""" 30 self.odometer_reading += miles 31 32 class Battery(): 33 """一次模拟电动汽车电瓶的简单尝试""" 34 def __init__(self, battery_size=70): 35 """初始化电瓶的属性""" 36 self.battery_size = battery_size 37 38 def describe_battery(self): 39 """打印一条描述电瓶容量的消息""" 40 print("This car has a " + str(self.battery_size) + "-kWh battery.") 41 42 def get_range(self): 43 """打印一条描述电瓶续航里程的消息""" 44 if self.battery_size == 70: 45 range = 240 46 elif self.battery_size == 85: 47 range = 270 48 message = "This car can go approximately " + str(range) 49 message += " miles on a full charge." 50 print(message) 51 52 class ElectricCar(Car): 53 """模拟电动汽车的独特之处""" 54 def __init__(self, make, model, year): 55 """ 56 初始化父类的属性,再初始化电动汽车特有的属性 57 """ 58 super().__init__(make, model, year) 59 self.battery = Battery()
程序my_electric_car的代码:
1 from car import ElectricCar 2 3 my_tesla = ElectricCar('tesla', 'model s', 2016) 4 print(my_tesla.get_descriptive_name()) 5 my_tesla.battery.describe_battery() 6 my_tesla.battery.get_range()
程序my_electric_car的运行结果:
1 2016 Tesla Model S 2 This car has a 70-kWh battery. 3 This car can go approximately 240 miles on a full charge.
3.3 从一个模块中导入多个类
实际编程中,我们可根据需要在程序文件中导入任意数量的类。
例如,如果我们要在同一个程序my_cars.py中创建普通汽车和电动汽车,就需要将 Car 和 ElectricCar 类都导入。
代码:
1 from car import Car, ElectricCar 2 3 my_beetle = Car('volkswagen', 'beetle', 2018) 4 print(my_beetle.get_descriptive_name()) 5 my_tesla = ElectricCar('tesla', 'roadster', 2018) 6 print(my_tesla.get_descriptive_name())
运行结果:
1 2018 Volkswagen Beetle 2 2018 Tesla Roadster
3.4 导入整个模块
根据实际应用中,有时我们需要导入整个模块,然后使用句点表示法访问需要的类。这种导入方法很简单,代码也易于阅读。由于创建类实例的代码都包含模块名,因此不会与当前文件使用的任何名称发生冲突。导入整个模块的具体语法格式如下:
import 模块名
例如,我们导入汽车的模块car,然后调用其中的类方法。
代码:
1 import car 2 my_beetle = car.Car('volkswagen', 'beetle', 2018) 3 print(my_beetle.get_descriptive_name()) 4 my_tesla = car.ElectricCar('tesla', 'roadster', 2018) 5 print(my_tesla.get_descriptive_name())
运行结果:
1 2018 Volkswagen Beetle 2 2018 Tesla Roadster
3.5 导入模块中的所有类
在程序中,有时我们需要从一个模块中导入所有的类,此时可使用*代替类名。具体语法格式如下所示:
from 模块 import *
不推荐使用这种导入方式,因为如果只要看一下文件开头的 import 语句,就能清楚地知道程序使用了哪些类,将大有裨益;但这种导入方式没有明确地指出你使用了模块中的哪些类。这种导入方式还可能引发名称方面的困惑。如果你不小心导入了一个与程序文件中其他东西同名的类,将引发难以诊断的错误。这里之所以介绍这种导入方式,是因为虽然不推荐使用这种方式,但你可能会在别人编写的代码中见到它。需要从一个模块中导入很多类时,最好导入整个模块,并使用 module_name.class_name 语法来访问类。
3.6 在一个模块中导入另一个模块
编程过程中,有时我们需要将类分散到多个模块中,以免模块太大,或在同一个模块中存储不相关的类。将类存储在多个模块中时,你可能会发现一个模块中的类依赖于另一个模块中的类。在这种情况下,可在前一个模块中导入必要的类。其语法格式如下所示:
from 模块1 import 模块2
例如,将 Car 类存储在一个模块中,并将 ElectricCar 和 Battery 类存储在另一个模块中。我们将第二个模块命名为 electric_car.py (这将覆盖前面创建的文件 electric_car.py ),并将Battery 和 ElectricCar 类复制到这个模块中。
模块car的代码:
1 """一个可用于表示汽车的类""" 2 class Car(): 3 """一次模拟汽车的简单尝试""" 4 def __init__(self, make, model, year): 5 """初始化描述汽车的属性""" 6 self.make = make 7 self.model = model 8 self.year = year 9 self.odometer_reading = 0 10 def get_descriptive_name(self): 11 """返回整洁的描述性名称""" 12 long_name = str(self.year) + ' ' + self.make + ' ' + self.model 13 return long_name.title() 14 15 def read_odometer(self): 16 """打印一条消息,指出汽车的里程""" 17 print("This car has " + str(self.odometer_reading) + " miles on it.") 18 19 def update_odometer(self, mileage): 20 """ 21 将里程表读数设置为指定的值 22 拒绝将里程表往回拨 23 """ 24 if mileage >= self.odometer_reading: 25 self.odometer_reading = mileage 26 else: 27 print("You can't roll back an odometer!") 28 29 def increment_odometer(self, miles): 30 """将里程表读数增加指定的量""" 31 self.odometer_reading += miles
模块electric_car的代码:
1 """一组可用于表示电动汽车的类""" 2 from car import Car 3 4 class Battery(): 5 """一次模拟电动汽车电瓶的简单尝试""" 6 def __init__(self, battery_size=70): 7 """初始化电瓶的属性""" 8 self.battery_size = battery_size 9 10 def describe_battery(self): 11 """打印一条描述电瓶容量的消息""" 12 print("This car has a " + str(self.battery_size) + "-kWh battery.") 13 14 def get_range(self): 15 """打印一条描述电瓶续航里程的消息""" 16 if self.battery_size == 70: 17 range = 240 18 elif self.battery_size == 85: 19 range = 270 20 message = "This car can go approximately " + str(range) 21 message += " miles on a full charge." 22 print(message) 23 24 class ElectricCar(Car): 25 """模拟电动汽车的独特之处""" 26 def __init__(self, make, model, year): 27 """ 28 初始化父类的属性,再初始化电动汽车特有的属性 29 """ 30 super().__init__(make, model, year) 31 self.battery = Battery()
运行程序代码:
1 from car import Car 2 from electric_car import ElectricCar 3 my_beetle = Car('volkswagen', 'beetle', 2018) 4 print(my_beetle.get_descriptive_name()) 5 my_tesla = ElectricCar('tesla', 'roadster', 2018) 6 print(my_tesla.get_descriptive_name())
程序运行结果:
1 2018 Volkswagen Beetle 2 2018 Tesla Roadster
4. Python 标准库
Python标准库是一组模块,安装的 Python 都包含它。可使用标准库中的任何函数和类,为此只需在程序开头包含一条简单的 import 语句。
模块 collections 中的一个类OrderedDict ,OrderedDict 实例的行为几乎与字典相同,区别只在于记录了键-值对的添加顺序。
例如,字典虽然能够将信息关联起来,但它们不记录你添加键 -值对的顺序。要创建字典并记录其中的键 - 值对的添加顺序,可使用模块 collections 中的 OrderedDict 类。
代码:
1 from collections import OrderedDict 2 favorite_languages = OrderedDict() 3 favorite_languages['jen'] = 'python' 4 favorite_languages['sarah'] = 'c' 5 favorite_languages['edward'] = 'ruby' 6 favorite_languages['phil'] = 'python' 7 for key, value in favorite_languages.items(): 8 print(key.title() + "'s favorite language is " + value.title() + ".")
说明:
第1行,从标准库collections 模块中导入类OrderedDict。
第2行,使用OrderedDict创建一个空的有序字典。
第3~6行,忘空字典中增加键-值对。
第7~8行,循环遍历字段favorite_languages,然后打印相应信息。
运行结果:
1 Jen's favorite language is Python. 2 Sarah's favorite language is C. 3 Edward's favorite language is Ruby. 4 Phil's favorite language is Python.
5. 类编码风格
类名应采用驼峰命名法,即将类名中的每个单词的首字母都大写,而不使用下划线。实例名和模块名都采用小写格式,并在单词之间加上下划线。
对于每个类,都应紧跟在类定义后面包含一个文档字符串。这种文档字符串简要地描述类的功能,并遵循编写函数的文档字符串时采用的格式约定。每个模块也都应包含一个文档字符串,对其中的类可用于做什么进行描述。
可使用空行来组织代码,但不要滥用。在类中,可使用一个空行来分隔方法;而在模块中,可使用两个空行来分隔类。
需要同时导入标准库中的模块和你编写的模块时,先编写导入标准库模块的 import 语句,再添加一个空行,然后编写导入你自己编写的模块的 import 语句。在包含多条 import 语句的程序中,这种做法让人更容易明白程序使用的各个模块都来自何方。