6. 类
6.1 创建和使用类
1、创建类
面向对象编程是最有效的软件编写之一,在面向对象编程中,编写表示现实生活中的事情和情景的类,并基于这些类来创建对象。
编写类时,你定义一大类对象都有的通用行为;基于类创建对象时,每个对象都自动具备这种通用行为,然后可根据具体需要赋予每个对象独立的个性。
class Dog():
"""模拟小狗动作"""
def __init__(self, name, age):
"""初始化name和age"""
"""获取存储在形参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!')
2、方法 __ init __()
Python 中,首字母大写的名称指的是类,类中的函数称为方法。__ init __() 是一个特殊方法,开头和末尾各有两个下划线,这是一种约定,旨在避免Python默认方法与普通方法发生名称冲突。
上述 __ init __() 方法中包含了三个形参:self、name和age,其中 self 是自动生成的,必不可少且必须在其他形参之前,因为Python 在调用 __ init __() 方法创建实例时,将自动传入实参 self,每个与类相关联的方法都自动传递实参 self,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。
3、根据类创建实例
通常用小写名称表示根据类创建的实例。
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!')
"""创建实例"""
my_dog = Dog('xiaohei', 6)
print("My dog's name is " + my_dog.name.title() + '.')
print('My dog is ' + str(my_dog.age) + ' years old.')
"""调用方法,使用句点表示法来调用"""
my_dog.sit()
my_dog.roll_over()
输出:
My dog's name is Xiaohei.
My dog is 6 years old.
Xiaohei is now sitting.
Xiaohei rolled over!
进程已结束,退出代码 0
6.2 使用类和实例
1、使用类和实例
下面来编写一个表示汽车的类,它存储了相关汽车的信息,还有一个汇总信息的方法。
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()
new_car = Car('audi', 'a4', 2016)
print(new_car.get_descriptive_name())
输出:
2016 Audi A4
进程已结束,退出代码 0
2、给属性指定默认值
类中每个属性都必须有初始值,哪怕是0或空字符串。如设置默认值时在方法 __ init __ () 内指定初始值,就无需包含为它提供初始值的形参。
下面添加一个名为 odomenter_reading ,其初始值为0,注意在输出时调用改参数必须将其数据类型给为 str,即使用 str(odomenter_reading) 将其改变为字符串。
class Car():
"""模拟汽车"""
def __init__(self, make, model, year):
"""初始化描述汽车的属性"""
self.make = make
self.model = model
self.year = year
self.odomenter_reading = 0 # 添加新属性
def get_descriptive_name(self):
"""返回整洁的描述信息"""
long_name = str(self.year) + ' ' + self.make + ' ' + self.model
return long_name.title()
def read_odomenter(self):
"""打印一条指出汽车历程的信息"""
print('This car has ' + str(self.odomenter_reading) + ' miles on it.')
new_car = Car('audi', 'a4', 2016)
print(new_car.get_descriptive_name())
new_car.read_odomenter()
输出:
2016 Audi A4
This car has 0 miles on it.
进程已结束,退出代码 0
3、修改属性的值
– 直接修改属性值
要修改属性值,最简单的方法是通过实例直接访问它。
class Car():
"""模拟汽车"""
def __init__(self, make, model, year):
"""初始化描述汽车的属性"""
self.make = make
self.model = model
self.year = year
self.odomenter_reading = 0 # 添加新属性
def get_descriptive_name(self):
"""返回整洁的描述信息"""
long_name = str(self.year) + ' ' + self.make + ' ' + self.model
return long_name.title()
def read_odomenter(self):
"""打印一条指出汽车历程的信息"""
print('This car has ' + str(self.odomenter_reading) + ' miles on it.')
new_car = Car('audi', 'a4', 2016)
print(new_car.get_descriptive_name())
new_car.odomenter_reading = 23 # 直接访问属性值并进行修改
new_car.read_odomenter()
输出:
2016 Audi A4
This car has 23 miles on it.
进程已结束,退出代码 0
– 通过方法修改属性值
如果有替你更新属性的方法,那你就无需直接访问属性,而是可将值传递给一个方法,让它在内部进行更新。
class Car():
"""模拟汽车"""
def __init__(self, make, model, year):
"""初始化描述汽车的属性"""
self.make = make
self.model = model
self.year = year
self.odomenter_reading = 0 # 添加新属性
def get_descriptive_name(self):
"""返回整洁的描述信息"""
long_name = str(self.year) + ' ' + self.make + ' ' + self.model
return long_name.title()
def read_odomenter(self):
"""打印一条指出汽车历程的信息"""
print('This car has ' + str(self.odomenter_reading) + ' miles on it.')
def update_odomenter(self, mileage):
"""将里程表读数设置为指定值,在方法内部更新"""
self.odomenter_reading = mileage
new_car = Car('audi', 'a4', 2016)
print(new_car.get_descriptive_name())
new_car.update_odomenter(24) # 添加方法进行属性值修改
new_car.read_odomenter()
输出:
2016 Audi A4
This car has 24 miles on it.
进程已结束,退出代码 0
– 通过方法对属性值进行递增
有时需要将属性值递增特定量,而不是将其设置为全新值,添加一个方法来实现。
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
my_used_car = Car('subaru', 'outback', 2013)
print(my_used_car.get_descriptive_name())
my_used_car.update_odometer(2500)
my_used_car.read_odometer()
my_used_car.increment_odometer(100)
my_used_car.read_odometer()
输出:
2013 Subaru Outback
This car has 2500 miles on it.
This car has 2600 miles on it.
进程已结束,退出代码 0
6.3继承
一个类继承另一个类时,它将自动获得另一个类的所有属性和方法;原有的类成为父类,而新类成为子类。子类继承了其父类所有属性和方法,同时还可以定义自己的属性和方法。
1、子类的方法 __ init __()
创建子类实例时,Python 首先需要完成的任务是给父类所有属性赋值,此时子类的 __ init __() 方法需要施以援手。
例:下面模拟一个电动汽车类,它是以前面的汽车类为父类创建。
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 ElectricCar(Car):
"""电动汽车的独特之处"""
def __init__(self, make, model, year):
"""初始化父类属性"""
super().__init__(make, model, year)
my_tesla = ElectricCar('tesla', 'model Y', 2021)
print(my_tesla.get_descriptive_name())
输出:
2021 Tesla Model Y
进程已结束,退出代码 0
super() 是一个特殊函数,帮助 Python 将父类和子类关联起来,super().init(make, model, year) 这句代码让 Python 调用父类 Car 的 __ init __()方法进行初始化,让 ElectricCar 实例包含父类的所有属性,父类也称为(superclass),名称 super 因此而来。
2、给子类定义属性和方法
一个子类继承一个类后,可添加区分子类和父类的所需的新属性和方法。
例:下面添加一个电动汽车特有的属性(电瓶),以及一个描述该属性的方法,我们将存储电瓶容量 battery_size,并编写一个打印点评描述的方法 describe_battery。
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 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 hattery.")
my_tesla = ElectricCar('tesla', 'model Y', 2021)
print(my_tesla.get_descriptive_name())
my_tesla.describe_battery()
输出:
2021 Tesla Model Y
This car has a 70-KWh hattery.
进程已结束,退出代码 0
3、重写父类的方法
对于父类的方法,只要它不符合子类模拟的实物行为,都可以对其进行重写。为此,可在子类中定义一个这样的方法,即它与要重写的父类方法同名,这样 Python 将不会考虑这个父类方法,而只关注你在子类中定义的相应方法。
例:假设 Car 类有一个名为 fill_gas_tank() 的方法,它对电动汽车来说毫无意义,因此对其进行重写。
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
def fill_gas_tank(self):
"""描述汽车油箱"""
print('This car has a gas tanks.')
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 hattery.")
def fill_gas_tank(self):
"""电动汽车没有油箱"""
print("This car doesn't need a gas tank.")
my_tesla = ElectricCar('tesla', 'model Y', 2021)
print(my_tesla.get_descriptive_name())
my_tesla.describe_battery()
my_tesla.fill_gas_tank()
输出:
2021 Tesla Model Y
This car has a 70-KWh hattery.
This car doesn't need a gas tank.
进程已结束,退出代码 0
4、将实例用作属性
使用代码模拟实物时,你会发现给类添加的细节越来越多:属性和方法清单以及文件都越来越长。这种情况可将类的一部分作为一个独立的类提取出来,将大型类拆分成多个协同工作的小类。
例:不断给 ElectricCar 类添加细节,导致其中包含很多专门针对汽车电瓶的属性好方法,此时可将这些属性和方法提取出来,放到一个名为 Battery 的类中,并将 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
def fill_gas_tank(self):
"""描述汽车油箱"""
print('This car has a gas tanks.')
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() # 注意此处 Battery 后有括号
def fill_gas_tank(self):
"""电动汽车没有油箱"""
print("This car doesn't need a gas tank.")
my_tesla = ElectricCar('tesla', 'model Y', 2021)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
输出:
2021 Tesla Model Y
This car has a 70-KWh battery.
进程已结束,退出代码 0