类与对象

类和对象

  类是用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。基于类创建 对象时,每个对象都自动具备这种通用行为,然后可根据需要赋予每个对象独特的个性。根据类来创建对象被称为 实例化,这让我们能够使用类的实例。

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 语句的程序中,这种做法让人更容易明白程序使用的各个模块都来自何方。

 

  

 

posted @ 2018-01-09 00:10  晴天云  阅读(256)  评论(0编辑  收藏  举报