1. 创建和使用类 1.1 创建Dog类 下面将创建一个表示小狗的Dog类,根据Dog类创建的每个示例都将存储名字和年龄,并且赋予每条小狗蹲下(sit())和打滚(roll_over())的能力:
dog.py
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class  Dog ():    """ 创建一个表示小狗的类 """      def  __init__ (self, name, age ):         """ 初始化属性name和age """          self .name = name         self .age = age     def  sit (self ):         """ 模拟小狗被命令时蹲下 """          print (self .name.title() + " is now sitting." )     def  roll_over (self ):         """ 模拟小狗被命令时打滚 """          print (self .name.title() + " rolled over!" ) 
 
在上面的代码中,定义了一个名为Dog的类。根据约定,在Python中,首字母大写的名称指的是类 。这个类定义中的括号是空的,说明该类并没有需要继承的父类。
1.1.1 方法__init__() 类中的函数称为方法,而__init__()是一个特殊的方法,每当你根据Dog类创建新示例时,Python都会自动运行它,类似于C++类中的构造函数,在这个方法的名称中,开头和末尾各有两个下划线,这是一种约定,旨在避免Python默认方法与普通方法发生名称冲突。
我们将方法__init__()定义成了包含三个实参:self、name和age。在这个方法的定义中,形参self是必不可少的,还必须位于其他形参的前面,每个与类相关联的方法调用都自动传递实参self,它是一个指向示例本身的引用,让实例能够访问类中的属性和方法 。我们将通过实参向Dog()传递名字和年龄,self会自动传递,因此我们不需要传递它,只需要给最后两个形参(name和age)提供值。
在类中,以self为前缀的变量都可供类中的所有方法使用,我们还可以通过类的实例来访问这些变量。self.name = name获取存储在形参name中的值,并将其存储到变量name中,然后该变量被关联到当前创建的实例。self.age = age的作用相同。像这样在类中可通过实例访问的变量称为属性 。
1.2 根据类创建实例 可将类视为有关如何创建实例的说明,Dog类是一系列说明,让Python知道如何创建表示特定小狗的实例。下面来创建一个表示特定小狗的实例:
1 2 3 4 5 6 7 class  Dog ():    --snip-- my_dog = Dog('willie' , 6 ) print ("My dog's name is "  + my_dog.name.title() + "." )print ("My dog is "  + str (my_dog.age) + " years old." )
 
在上面这段代码中,创建了一个名字为’willie’、年龄为6的小狗。遇到这行代码时,Python将实参'willie'和6传入Dog类中的方法__init__()。方法__init__()创建一个便是特定小狗的实例,并使用实参的值来设置属性name和age。方法__init__()并未显式地包含return语句,但Python自动返回一个表示这条小狗的实例,并将这个实例存储在变量my_dog中。在Python中,我们通常可以认为首字母大写的名称(如Dog)指的是类,而小写的名称(如my_dog)指的是根据类创建的实例。
1.2.1 访问属性 要访问实例的属性,可使用句点表示法:
 
在这里,Python先找到实例my_dog,再查找与这个实例相关联的属性name。在Dog类中引用这个属性时,使用的是self.name,因此,在上面的实例化代码中,打印出的结果如下所示:
1 2 My dog's name is Willie.  My dog is 6 years old. 
 
1.2.2 调用方法 根据Dog类创建实例后,就可以使用句点表示法来调用Dog类中定义的任何方法:
1 2 3 4 5 6 class  Dog ():    --snip-- my_dog = Dog('willie' , 6 ) my_dog.sit() my_dog.roll_over() 
 
要调用方法,可指定实例的名称和要调用的方法,并用句点分隔它们。上面的代码中运行的输出结果如下所示:
1 2 Willie is  now sitting. Willie rolled over! 
 
2. 使用类和实例 在类编写好后,你的大部分时间都将花在使用根据类创建的实例上,你需要执行的一个重要任务是修改实例的属性。你可以直接修改实例的属性,也可以编写方法以特定的方式进行修改。
2.1 Car类 下面是一个表示汽车的类,它存储了有关汽车的信息,还有一个汇总这些信息的方法:
car.py
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class  Car ():    """ 创建一个表示汽车的类 """      def  __init__ (self, make, model, year ):         """ 初始化描述汽车的属性 """          self .make = make         self .model = model         self .year = year     def  get_descriptive_name (self ):         """ 返回整洁的描述信息 """          long_name = str (self .year) + ' '  + self .make + ' '  + self .model         return  long_name.title() my_new_car = Car('audi' , 'a4' , 2016 ) print (my_new_car.get_descriptive_name())
 
在上面的代码中,输出结果如下所示:
 
2.2 给属性指定默认值 类中的每个属性都必须有初始值,哪怕这个值是0或是空字符。在有些情况下,如设置默认值时,在方法__init__()内指定这种初始值是可行的,如如果你对某个属性这样做了,就无需包含为它提供初始值的形参。
下面来添加一个名为odometer_reading的属性,其初始值总是为0。除此之外,还添加了一个名为read_odometer()的方法,用于读取汽车的里程表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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." ) my_new_car = Car('audi' , 'a4' , 2016 ) print (my_new_car.get_descriptive_name())my_new_car.read_odometer() 
 
上面这段代码打印的结果如下,由于未对汽车里程进行修改,因此汽车的里程还是0:
1 2 2016  Audi A4This car has 0  miles on it. 
 
2.3 修改属性的值 在Python中,有如下两种不同的方式可以修改属性的值:直接通过实例进行修改;通过方法进行设置。下面依次介绍这些方法。
2.3.1 直接修改属性的值 要修改属性的值,最简单的方式是通过实例直接访问它。下面的代码直接将里程表度数设置为23:
1 2 3 4 5 6 7 8 class  Car ():    --snip-- my_new_car = Car('audi' , 'a4' , 2016 ) print (my_new_car.get_descriptive_name())my_new_car.odometer_reading = 23  my_new_car.read_odometer() 
 
此时,my_new_car这个实例中的odometer_reading属性就被修改为23:
1 2 2016  Audi A4This car has 23  miles on it. 
 
2.3.2 通过方法修改属性的值 下面的例子演示了一个名为update_odometer()的方法:
1 2 3 4 5 6 7 8 9 10 11 12 class  Car ():    --snip--     def  update_odometer (self, mileage ):         """ 将里程表读书设置为指定的值 """          self .odometer_reading = mileage my_new_car = Car('audi' , 'a4' , 2016 ) print (my_new_car.get_descriptive_name())my_new_car.update_odometer(23 ) my_new_car.read_odometer() 
 
上面的代码中添加了一个新的方法update_odometer()。这个方法接受一个里程值,并将其存储到self.odometer_reading中。上面的代码打印结果如下:
1 2 2016  Audi A4This car has 23  miles on it. 
 
3. 继承 编写类时,并非总是要从空白开始。如果你要编写的类是另一个现成类的特殊版本,可使用继承。一个类继承另一个类时,它将自动获得另一个类的所有属性和方法 。原有的类称为父类,而新类称为它的子类。子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。
3.1 子类的方法__init__() 创建子类时的示例时,Python首先需要先给父类的所有属性赋值,为此,子类的方法__init__()需要依靠父类。
下面的代码创建一个简单的ElectricCar类,它具备Car类的所有功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 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!" ) class  ElectricCar (Car ):    """创建一个表示电动汽车的类 """      def  __init__ (self, make, model, year ):         """ 初始化父类的属性 """          super ().__init__(make, model, year) my_tesla = ElectricCar('tesla' , 'model s' , 2016 ) print (my_tesla.get_descriptive_name())
 
创建子类时,父类必须包含在当前文件中,且位于子类前面,在上面的代码中,我们定义了子类ElectricCar。定义子类时,必须在括号内指定父类的名称。方法__init__()接受创建Car示例所需的信息。super()是一个特殊函数,帮助Python将父类和子类关联起来,这行代码让Python调用ElectricCar的父类的方法__init__(),让ElectricCar实例包含父类的所有属性。父类也称为超类,名称super()因此而得名。上面这段代码的输出结果为:
 
可以看到继承自Car类的ElectricCar类确实具有和其父类Car相同的功能。
3.2 给子类定义属性和方法 让一个类继承另一个类后,可添加区分子类和父类所需的新属性和方法,下面的代码添加一个电动车特有的属性(电瓶),以及一个描述该属性的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class  Car ():    --snip-- class  ElectricCar (Car ):    """ 创建一个继承自汽车类的电动车类 """      def  __init__ (self, make, model, year ):         """  电动车的特点,初始化父类的属性,再初始化电动车特有的属性 """          super ().__init__(make, model, year)         self .battery_size = 70      def  describe_battery (self ):         """ 打印一条描述电瓶容量的消息 """          print ("This car has a "  + str (self .battery_size) + "-kWh battery." ) my_tesla = ElectricCar('tesla' , 'model s' , 2016 ) print (my_tesla.get_descriptive_name())my_tesla.describe_battery() 
 
在上面这行代码中,添加了新属性self.battery_size,并设置初始值为70。根据ElectricCar类创建的所有实例都将包含这个属性,但所有Car实例都不包含它。除此之外,还添加了一个describe_battery()方法,它打印有关电瓶的信息。我们调用这个方法时,将看到一条电动车特有的描述:
1 2 2016  Tesla Model SThis car has a 70 -kWh battery. 
 
3.3 重写父类方法 对于父类的方法,只要它不符合子类模拟的实物的行为,都可对其进行重写。为此,可在子类中定义一个这样的方法,即它与要重写的父类方法同名。这样,Python将不会考虑这个父类方法,而只关注你在子类中重新定义的该方法。
假设Car类有一个名为fill_gas_tank()的方法,它对全电动车来说毫无意义,下面演示了一种重写方式:
1 2 3 4 5 6 class  ElectricCar (Car ):    --snip--     def  fill_gas_tank ():         """ 电动汽车没有邮箱 """          print ("This car doesn't need a gas tank!" ) 
 
现在,如果有人对电动车调用方法fill_gas_tank(),Python将忽略Car类中的方法fill_gas_tank()。转而运行上述代码。使用继承时,可让子类保留从父类哪里继承而来的精华,并剔除不需要的糟粕。
3.4 将实例用作属性 在Python中,可以将大型类拆分成多个协同工作的小类,例如在下面的代码中,将针对汽车电瓶的属性和方法提取出来,放到另一个名为Battery的类中,并将一个Battery实例用作ElectricCar类的一个属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class  Car ():    --snip-- class  Battery ():    """ 创建一个关于电动车电瓶的类 """      def  __init__ (self, battery_size=70  ):         """ 初始化电瓶的属性 """          self .battery_size = battery_size     def  describe_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.describe_battery() 
 
在上面的代码中,定义了一个名为Battery的新类,在ElectricCar这个类中,创建了一个名为self.battery的Battery实例。现在每个ElectricCar实例都包含一个自动创建的Battery实例。输出结果如下所示:
1 2 2016  Tesla Model SThis car has a 70 -kWh battery.