本章内容如目录 所示:
文章目录
- 1. 创建和使用类
- 1.1 创建第一个python 类
- 1.2 版本差异
- 1.3 根据类创建实例
- 1. 访问属性
- 2. 调用方法
- 3. 创建多个实例
- 2. 使用类和实例
- 2.1 给属性指定默认值
- 2.2 修改属性的值
- 3. 继承
- 3.1 子类的 __init __()
- 3.2 给子类定义属性和方法
- 3.3 重写父类的方法
- 3.4 将实例用作属性
- 4. 导入类
- 4.1 导入单个类
- 4.2 在一个模块中存储多个类
- 4.3 在一个模块中存储多个类
- 4.4 导入整个模块
- 4.5 导入模块中的所有类
导言
面向对象编程是最有效的软件编写方法之一。在面向对象编程中你编写表示显示世界中的事务和情景类,并基于这些类来创建对象。
编写类时,你定义一大类对象都有的通用行为。基于类创建对象时,每个对象都自动具备这种通用行为,然后可根据需要赋予每个对象独特的个性。
根据类来创建对象被称为实例化,这让你能够使用类的实例。
.
.在本章中,你将编写一些类并创建其实例。你将指定可在实例中存储什么信息,定义可对这些实例执行哪些操作。你还将编写一些类来扩展既有类的功能,让相似的类能够高效地共享代码。还可以将自己编写的类存储在模块中,并在自己的程序文件中导入其他程序员编写的类。
1. 创建和使用类
1.1 创建第一个python 类
使用类几乎可以模拟任何东西。下面我们来编写一个简单的 小狗 dog 类,它表示的不是某个特定的小狗,而是任何小狗,它具备姓名,年龄,还有属于小狗的某种行为。
现在我们来编写这个表示小狗的类:
# 创建小狗类
class Dog():
#初始化函数
def __init__(self,name,age):
#self 这个参数代表 当前对象的实例本身,
#所以通过self 来调用,self不是固定关键词,可以起成任意一个名字
#在类当中定义的所有函数的第一个参数都是 当前对象实例的本身
self.name = name
self.age = age
#定义狗子 蹲下函数
def sit(self):
print("狗子:"+self.name+",现在已经蹲下来了....")
#定义狗子 打滚函数
def roll_over(self):
print("狗子:"+self.name+"正在打滚....")
现在我们已经创建好了一个简单的 python 类,
在python 中,类的名称是以大写字母开头的,类定义中的括号是空的,因为我们要从空白创建这个类。
关于 __ init __() 方法:
在类中的函数称为方法;我们前面学到的有关函数的一切都适用于方法,需要注意的有差别的一点是:调用方法的方式。
__ init __() 是一个特殊的方法,每当我们根据 Dog 类创建实例时, python 都会自动运行它。在这个方法的名称中,开头黑末尾各有两个下划线,这是一种约定:旨在避免 python 默认方法与普通方法发生名称冲突。
关于 self 参数具体说明
在__ init ()方法中,我们一共定义了三个参数:self、name、age。 形参 self
是必不可少的,且必须位于参数列表的最前面。为何必须定义 self 形参呢? 因为 python 调用这个 init __()
方法来创建Dog类的实例时,将自动传入 实参self,每个与类相关的方法调用都自动传递实参
self,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。
通过实例访问的变量称为属性。
1.2 版本差异
在 python 2.+ 的版本定义类的语法:
class Dog(object):
在 python 3.+ 的版本定义类的语法:
class Dog():
1.3 根据类创建实例
我们可将类视为有关如何创建实例的说明。Dog类是一系列说明,让 python 知道如何创建表示特定小狗的实例:
class Dog():
#初始化函数
def __init__(self,name,age):
#self 这个参数代表 当前对象的实例本身,
#所以通过self 来调用,self不是固定关键词,可以起成任意一个名字
#在类当中定义的所有函数的第一个参数都是 当前对象实例的本身
self.name = name
self.age = age
#定义狗子 蹲下函数
def sit(self):
print("狗子:"+self.name+",现在已经蹲下来了....")
#定义狗子 打滚函数
def roll_over(self):
print("狗子:"+self.name+"正在打滚....")
# Dog类的实例创建过程
my_dog = Dog('小白',4)
print('我的小狗叫:'+my_dog.name+',它今年'+str(my_dog.age)+'岁')
通常:类的命名以大写字母开头,而类的实例以小写字母开头。
1. 访问属性
想要访问实例的属性,可使用句点表示法。
例如在上述代码当中:
my_dog.name
就是对属性的使用。
句点在 python 当中很有用,在这个调用过程当中,python 会先找到实例 my_dog。在查找与这个实例相关联的属性 name。
在 Dog 类中引用这个属性时,使用的是 self.name。我们也使用同样的方法来获取属性 age 的值。
2. 调用方法
Dog类创建实例后,就可以使用句点表示法来调用 Dog类中定义的任何方法。
下面我们来调用 小狗打滚和蹲下的方法。
my_dog.sit()
my_dog.roll_over()
3. 创建多个实例
一个类 可以对应多个实例,实例并非只有一个。类是抽象的概念,
比如小狗,小狗可能有多只,可能是小白,小黑,小黄。它们都是小狗,所以一个类,
可以创建多个实例。
例如,我的小狗 我会将代码写成:
my_dog = Dog()
而你也有一只小狗,我还可以继续使用这个类进行实例化。
your_dog= Dog()
至于你的小狗叫什么名字,我的小狗叫什么名字,它们年龄是几岁?
直接通过变量名调用属性,给它们赋值就行了。
或者你也可以将参数写在括号里,通过 初始化方法进行赋值。
2. 使用类和实例
现在我们来编写一个表示汽车的类,使其存储有关汽车的信息。
class Car():
#初始化方法
def __init__(self,model,colour):
self.model =model
self.colour =colour
#小汽车的基本信息描述
def get_carInfo(self):
info = '它是一辆'+self.colour+'颜色的'+self.model+'车'
return info
my_car = Car('BMW','白')
print(my_car.get_carInfo())
我们看一下这段代码的运行结果。
一个基本的 汽车类的模板,我们就定义好了,下面我们利用新的知识,不断对模板进行改进。
2.1 给属性指定默认值
类中的每个属性都必须有初始值,哪怕这个值是 0 或 空的字符串。
在有些情况下,设置默认值时, 在 初始化方法内 指定初始值也是可行的。
如果对某个属性这样设置了,就无需包含为它提供初始值的形参。
给小汽车添加 里程的属性。
class Car():
#初始化方法
def __init__(self,model,colour,mileage):
self.model =model
self.colour =colour
self.mileage = 0
#小汽车的基本信息描述
def get_carInfo(self):
info = '它是一辆'+self.colour+'颜色的'+self.model+'车'
return info
# 小汽车的行驶里程记录
def get_carMileage(self):
print('该汽车已经行驶了:'+'self.mileage'+'公里')
设置好了小汽车的模板,我们在来生产一辆崭新的黑色大众汽车。
my_car = Car('大众','黑')
print(my_car.get_carInfo())
print(my_car.get_carMileage())
2.2 修改属性的值
刚才我们给属性设置了默认值,而这里给大家介绍三种修改属性值的方法:
一种是 通过实例进行修改,
对属性的值,直接进行修改,最简单的方式是通过实例直接访问它。
以上面的小汽车类举例。
# 实例化一个新的小汽车
new_Car = Car('大众汽车','黑')
#获取该小汽车的信息
print(new_Car.get_carInfo())
#现在,我们将小汽车颜色修改为 白色
new_Car.colour ='白'
#重新获取该小汽车的信息
print(new_Car.get_carInfo())
接下来,我们看一下修改后的输出信息:
我们看到小汽车的参数值已经修改成功了。
一种是 通过方法进行设置,
如果有更新属性的方法,可以将参数值传递给方法,无需在直接访问属性。
因为此时的参数值会在该方法的内部进行更新。
#计算小汽车里程数信息的方法
def update_CarInfo(self,mileage):
self.mileage=mileage
'''该方法被调用时,接收调用处传递的实参,将该参数重新赋值到计录里程变量中'''
#下面正常创建小汽车类
new_car =Car('大众汽车','黑色')
print(new_car.get_carInfo())
#得到小汽车信息以后,在调用获取里程数方法,查看里程
print(new_car.get_carMileage())
#经过一段时间的驾驶后,通过小汽车里程更新方法更新它的里程
new_car.update_CarInfo(20)
#重新打印小汽车的里程数
print(new_car.get_carMileage())
写好代码以后,我们来输出查看小汽车的里程数:
发现小汽车的里程数已经更新到20公里了。
一种是 通过方法进行递曾。
有时候我们需要给属性值传递特定的量,而不是将其设置为全新的值。
就像小汽车的里程,总是在增加的。
我们写一个实例来说明如何传递这个增量。
#设置小汽车里程增量方法
def increment_mileage(self,miles):
self.mileage+=miles
#购买新的小汽车
new_car = Car("大众甲壳虫",'黄')
#每日用车 10公里,设置没人增加里程
new_car.increment_mileage(10)
#获取小汽车的信息
print(new_car.)
我们来看一下程序的执行结果:
3. 继承
编写类时,不一定总是从零开始,如果你要编写的类是另一个现成类的特殊版本。
可以使用继承,一个类继承另一个类时,它将自动获得另一个类的所有属性和方法;
原有的类称为父类,而新的类被称为子类。
子类会继承父类的所有属性和方法,同时还可以定义自己的属性和方法。
3.1 子类的 __init __()
创建子类的实例时,python 首先需要完成的任务是给父类的所有属性赋值。为此,子类的方法__init __() 需要父类施以援手。
例如我们创建一个电动汽车类,电动汽车是一种特殊的汽车,因此我们可以基于前面创建的 Car类,创建一个新的类。这样我们就只需要为电动汽车特有的属性和行为编写代码。
#电动汽车类
class ElectricCar(Car):
def __init__(self,model,colour):
super().__init__(model,colour)
#实例化子类
eCar = ElectricCar('特斯拉','黑')
#显示该汽车信息
print(eCar.get_carInfo())
这里需要注意,创建子类时,必须要在同一个文件内有父类的代码包含其中。
在这个示例中,没写父类代码是因为省略了。
而且父类的代码必须位于子类代码的前面。
现在我们来运行一下这段程序代码,
看看子类是否成功继承父类了,并且是否可以成功调取到父类的方法。
关于 super() 方法的说明:
super() 是一个特殊的函数,帮助python将父类和子类关联起来。
super().init(model,colour) 这行代码,让python 调取 ElecticCar 的父类的方法 __init __(),让其子类也包含其父类的所有属性。
3.2 给子类定义属性和方法
让一个类继承另一个类以后,可添加区分子类和父类所需的新属性和方法。
下面我们来给子类添加一个独有的显示电动汽车的 电池相关描述的属性和方法。
#电动汽车类
class ElectricCar(Car):
def __init__(self,model,colour):
super().__init__(model,colour)
self.battery_size = 60
#电池汽车信息状态
def describe_battery(self):
print('您汽车的电池能源剩余:'+str(self.battery_size))
#实例化子类
eCar = ElectricCar('特斯拉','黑')
#显示该汽车信息
print(eCar.get_carInfo())
#显示电池状态
print(eCar.describe_battery())
其实在这段代码当中,跟我们之前设置属性的初始化参数时意思相同,不同的是这次的默认值是设置在子类当中,而父类没有这个方法。其实本质还是对默认值的一个设置和使用。在初始化方法中新添加一个独有的属性,然后设置好默认值。在新定义一个显示电池信息状态的方法,在这个方法中调到独有属性。最后,哪里实例化子类,调用这个方法,就会在哪里成功显示出电池信息。
3.3 重写父类的方法
对于父类的方法,只要它不符合子类模拟的实物的行为,都可以对其进行重写。
在我们编写的父类代码当中,这个方法 大家还记不记得?
# 小汽车的行驶里程记录
def get_carMileage(self):
print('该汽车已经行驶了'+str(self.mileage)+'公里')
我们就用这个方法来做重写的测试,
在汽车中,里程数是不断记录的。而在电动车中,我们将其重写成另一种记录形式:
#电动汽车类
class ElectricCar(Car):
def __init__(self,model,colour):
super().__init__(model,colour)
self.battery_size = 60
#汽车电池信息状态
def describe_battery(self):
print('您汽车的电池能源剩余:'+str(self.battery_size))
#电动车的行驶里程记录
def get_carMileage(self):
print('该汽车电池已消耗:'+str(self.mileage)+'公里')
#实例化子类
eCar = ElectricCar('特斯拉','黑')
#显示该汽车信息
print(eCar.get_carInfo())
#显示电池状态
print(eCar.describe_battery())
#别忘了调用一下修改 里程数的方法
eCar.update_CarInfo(10)
#调用 动车的行驶里程记录
print(eCar.get_carMileage())
现在我们来看一下输出结果,看看子类重写父类的方法是否成功?
3.4 将实例用作属性
使用代码模拟事务时,你可能会发现自己给类添加的细节越来越多:属性和方法清单以及文件都越来越长。在这种情况下,可能需要将类的一部分作为一个独立的类提取出来。你可以将大型的类拆分成多个协同工作的小类。
例如,不在给电动汽车类添加细节,我们可能会发现其中包含很多专门针对汽车点评的属性和方法。在这种情况下,我们可将这些属性和方法提取出来,放到另一个名为 Battery的类中,并将一个Battery实例用作 ElectricCar类的一个属性:
其实就是将属性封装到一个类里,然后在将这个类作为 本类的属性。
class Battery():
def __init__(self,battery_size=60):
#初始化电池信息
self.battery_size=battery_size
#汽车电池信息状态
def describe_battery(self):
print('您汽车的电池能源剩余:'+str(self.battery_size))
#创建电动汽车类
class ElectricCar(Car):
def __init__(self,model,colour):
super().__init__(model,colour)
self.battery = Battery()
#实例化子类
eCar = ElectricCar('特斯拉','黑')
#显示该汽车信息
print(eCar.get_carInfo())
#显示电池状态
print(eCar.battery.describe_battery())
其实这里并没有改动代码的逻辑,只是将一些属性进行了封装,当然这是 java中的概念,简单来说,就是将 某个类的 过多属性 或者是方法 定义到一个类中,在将这个类作为 我们要操作类的属性,通过这个属性来操作繁多的内容。
我们来看一下输出结果:
4. 导入类
随着不断给类添加功能,文件可能变的很长,即便妥善地使用了继承亦然如此。为遵循python的总体理念,应让文件尽可能整洁。为在这方面提供帮助, python 允许你将类存储在模块中,然后在主程序中导入所需的模块。
4.1 导入单个类
from 文件名 import 类名
4.2 在一个模块中存储多个类
虽然在一个模块当中的类应该存在相关性,但也可以根据需要在一个模块中存储任意数量的类。
from 文件名 import 之类名 #同时可以调用与该类的相关的类,如 父类,封装的属性和方法的类
4.3 在一个模块中存储多个类
可以根据需要在程序文件中存储任意多个类
from 文件名 import 类名,类名 #用小写逗号分隔
4.4 导入整个模块
也可以导入整个模块,然后在通过句点表示法访问需要的类。
import 文件名
4.5 导入模块中的所有类
from module_name模块名 import *