正文 【Python基础】7. 类与面向对象 拾年之璐 V管理员 /2020-08-07 /477 阅读 0807 ## 类与面向对象 [TOC] ### 1. 面向对象编程 `面向对象编程` 是最有效的软件编写方法之一。 在面向对象编程中,现实世界中的事物和情景,均可以使用 `类` 来编写表示。将要描述的对象提取公共行为,编写成类。 基于编写的类,可以创建 `对象` ,使得每个对象自动具备所提取的公共行为。 然后可根据实际情况,赋予每个对象自己独有的特性。 上面描述的根据类来创建对象的过程,被称为 `实例化` 。这让你能够使用 `类的实例` 。 ### 2. 类的创建和使用 #### 2.1 创建类 使用 `类` 几乎可以模拟任何东西。 比如 `学生类Student` ,可以用来表示任意学生。任意学生包含的信息都有 `学号no` 、 `姓名name` 、 `籍贯nativePlace` 等。对于每个学生的行为,都有 `上课attend Class` 、 `下课finish Class` 等。 所以可以创建 `Student类` 来表示。 示例(student.py): ```python class Student(): def __init__(self, no, name, nativePlace): """初始化属性no, name, nativePlace""" self.no = no self.name = name self.nativePlace = nativePlace def attend_class(self): print(self.name + '正在上课') def finish_class(self): print(self.name + '已经下课') ``` 关于这个类的定义,几点说明及注意事项如下: + Student:这是类的名字。约定所有单词的首字母大写。 + **类中的函数称为方法**。 + \__init__() :初始化方法,当根据Student类来创建实例时,该方法将自动执行。约定开头和末尾各有两个下划线,避免命名冲突。 + \__init__()中的self:self形参必不可少,还必须位于其他形参之前。这是因为类的创建、调用时,都自动传递实参self,这个self是一个指向实例本身的引用,使得实例能够访问类中的属性和方法。当创建实例时,self不需要传递参数,只需要给后边的值(no、name等)赋值即可。 + 属性:像上面的no、name变量,在初始化时,均使用了self 前缀,这种变量可以给类中的所有方法使用,还可以通过类的任何实例来访问,这种变量称为属性。 + 其他方法:如attend_class()和finish_class()方法,一般为当前类的具有的通用方法,其中的参数self使得该方法能够访问类中的属性。这些方法可以继续添加其他的,不在属性内的形参。 + 私有方法和属性:Python约定名称以双下划线“__”开头但不以它结尾的方法或属性,都是私有的,其他则都不是私有部分。 #### 2.2 使用类和示例 类如何来使?先看下面这个示例。 示例: ```python class Student: def __init__(self, no, name, nativePlace): """初始化属性no, name, nativePlace""" self.no = no self.name = name self.nativePlace = nativePlace # 【 1 】这里也可以给属性指定默认值 self.school = '武汉理工大学' def attend_class(self): return self.name + '正在上课' # 【 2 】类中的方法,可以增加必要的形参 def attend_class_2(self, address): return self.name + '正在 ' + address + ' 上课' def attend_class_3(self, address): return self.name + '正在 ' + self.school + address + ' 上课' def finish_class(self): return self.name + '已经下课' # 使用类 # 【 3 】根据类创建实例 zhangSan = Student(20200101, '张三', '湖北武汉') # 【 4 】访问属性 print('创建了一个示例,学生姓名是: ' + zhangSan.name) # 【 5 】调用方法 print(zhangSan.attend_class()) print(zhangSan.attend_class_2('第一教学楼101教室')) print(zhangSan.attend_class_3('第一教学楼101教室')) ``` 示例输出: ``` 创建了一个示例,学生姓名是: 张三 张三正在上课 张三正在 第一教学楼101教室 上课 张三正在 武汉理工大学第一教学楼101教室 上课 ``` > 注:最新的Python中,class关键字后面的类名后边的括号()可以省略 在这个类的使用的示例中,主要有这么几点: + 【1】 类中的属性可以给指定默认值。 + 【2】类中的方法,可以增加必要的形参。 + 【3】根据类来创建实例的方法如上,即 `实例名 = 类名(实参1,实参2……)` 。可以创建多个实例。 + 【4】可以直接通过 `实例名.属性名` 的格式来访问示例的属性。 + 【5】可以直接通过 `实例名.方法` 的格式来调用示例中的方法,其中有额外参数的需要在调用时给出。 **可以对属性的值进行修改**,主要有三种方法: 1. 直接通过示例进行修改 2. 通过方法进行设置 3. 通过方法进行递增(即类中的某个方法实现的是递增或自加,可以多次调用这个方法实现对属性的修改。 示例: ```python # 创建类 class Student: def __init__(self, no, name, nativePlace): """初始化属性no, name, nativePlace""" self.no = no self.name = name self.nativePlace = nativePlace # 【1】这里也可以给属性指定默认值 self.school = '武汉理工大学' def attend_class(self): return self.name + '正在上课' # 【2】类中的方法,可以增加必要的形参 def attend_class_2(self, address): return self.name + '正在 ' + address + ' 上课' def attend_class_3(self, address): return self.name + '正在 ' + self.school + address + ' 上课' def finish_class(self): return self.name + '已经下课' def setSchool(self, school): self.school = school # 这里不仅可以简单的赋值,还可以实现更多功能 # 使用类 liSi = Student(20200102, '李四', '江苏南京') # 直接通过属性名修改 liSi.school = '南京理工大学' print(liSi.attend_class_3('第二教学楼102')) # 通过方法修改属性 liSi.setSchool('华中科技大学') print(liSi.attend_class_3('第二教学楼103')) ``` 示例输出: ``` 李四正在 南京理工大学第二教学楼102 上课 李四正在 华中科技大学第二教学楼103 上课 ``` ### 3. 继承 编写类时,并非总是要从空白开始。**如果要编写的类是另一个现成类的特殊版本,可使用继承。** 一个类 `继承` 另一个类时,它将自动获得另一个类的所有属性和方法;原有的类称为 `父类` (也叫做 `超类(superClass)` ) ,而新类称为 `子类` 。**子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法**。 比如,学生都需要上课和下课。在学生这个群体中,有参加学生工作的(如monitor),还有参加志愿服务的(如volunteer)。所以这两类学生,具体普通学生的属性,还有自己的特有属性。那么这两类学生的定义可以采用继承来实现。 可以通过下面这个示例来理解继承的具体使用。 示例: ```python # 父类 class Student: # 初始化 def __init__(self, no, name, nativePlace): self.no = no self.name = name self.nativePlace = nativePlace self.school = '武汉理工大学' def attend_class(self): return self.name + '正在上课' def finish_class(self): return self.name + '已经下课' # 【 1 】monitor子类 class Monitor(Student): # 【 2 】子类初始化 def __init__(self, no, name, nativePlace): # 【 3 】初始化父类的属性 super().__init__(no, name, nativePlace) # 【 4 】定义子类属性 self.classRoom = '第五教学楼-107教室' self.meetingRoom = '321会议室' # 【 5 】定义子类方法 def attend_A_Meeting(self): return self.name + ' 正在' + self.meetingRoom + ' 开会' # 【 6 】重写父类方法 def attend_class(self): return self.name + ' 正在' + self.school + self.classRoom + ' 上课' # 使用类 liSi = Monitor(20200103, '李四', '湖北武汉') print(liSi.attend_A_Meeting()) print(liSi.attend_class()) ``` 示例输出: ``` 李四 正在321会议室 开会 李四 正在武汉理工大学第五教学楼-107教室 上课 ``` 在这个示例中,对子类的定义主要有这么几点: + 【1】创建子类是,class关键字后面的子类名后的括号内填写继承的父类名。 + 【2】子类初始化方法的形参,除了包含父类初始化方法的形参外,还可以增加子类独有的形参 + 【3】初始化父类属性的方法如上示例,使用了super()方法,即 `super().__init__(父类形参1,父类形参2,……)` 。 + 【4】子类独有的属性需要单独定义 + 【5】定义子类自己的方法,根据前述要求定义即可。 + 【6】子类可以对父类的方法进行重写。 另外,可以将一个类的示例,用作另一个类的属性。 ### 4. 导入类 #### 4.1 模块中存储类 在一个模块中,可以存储一个或者多个类。即**一个模块可以根据需要,存储任意数量的类**。 示例(student.py): ```python # 父类 class Student: # 初始化 def __init__(self, no, name, nativePlace): self.no = no self.name = name self.nativePlace = nativePlace self.school = '武汉理工大学' def attend_class(self): return self.name + '正在上课' def finish_class(self): return self.name + '已经下课' # monitor子类 class Monitor(Student): # 子类初始化 def __init__(self, no, name, nativePlace): # 初始化父类的属性 super().__init__(no, name, nativePlace) # 定义子类属性 self.classRoom = '第五教学楼-107教室' self.meetingRoom = '321会议室' # 定义子类方法 def attend_A_Meeting(self): return self.name + ' 正在 ' + self.meetingRoom + ' 开会' # 重写父类方法 def attend_class(self): return self.name + '正在' + self.school + self.classRoom + '上课' # volunteer子类 class Volunteer(Student): # 子类初始化 def __init__(self, no, name, nativePlace, community): # 初始化父类的属性 super().__init__(no, name, nativePlace) # 定义子类属性 self.serviceCommunity = community # 定义子类方法 def attend_A_Voluntary(self): return self.name + ' 正在 ' + self.serviceCommunity + ' 志愿服务' ``` 在上面这个模块中,定义了三个类。 #### 4.2 从模块导入类 可以从模块中导入一个类,也可以导入多个类,也可以导入整个模块,也可以导入模块中的所有的类,也可以在一个模块中导入另一个模块。 下面这个示例,展示了如何导入。 示例: ```python # 导入单个类,并命名别名 from student import Student as Sd # 导入多个类 from student import Monitor, Volunteer # 导入全部类 from student import * # 导入整个模块 import student ``` 示例: ```python # 导入整个模块 import student # 使用类 liSi = student.Volunteer(20200104, '李四', '湖北武汉', '余家头社区') print(liSi.attend_A_Voluntary()) ``` 示例输出: ``` 李四 正在 余家头社区 志愿服务 ``` 关于模块的导入,有几点建议。 + 一般用到模块中的哪个或者哪几个类,就导入哪个类或者哪几个类。主要是清楚的知道程序使用了哪些类。 + 如果用到了一个模块中的很多类,最好导入整个模块,然后使用 `模块名.类名` 的形式来访问类。 ### 5. 类的编码风格 + 类名应采用驼峰命名法 ,即将类名中的每个单词的首字母都大写,而不使用下划线。 + 实例名和模块名都采用小写格式,并在单词之间加上下划线。 + 对于每个类,都应紧跟在类定义后面包含一个文档字符串。这种文档字符串简要地描述类的功能,并遵循编写函数的文档字符串时采用的格式约定。 + 每个模块也都应包含一个文档字符串,对其中的类可用于做什么进行描述。 + 可使用空行来组织代码,但不要滥用。在类中,可使用一个空行来分隔方法;而在模块中,可使用两个空行来分隔类。 + 需要同时导入标准库中的模块和你编写的模块时,先编写导入标准库模块的import 语句,再添加一个空行,然后编写导入你自己编写的模块的import 语句。包含多条import 语句的程序中,这种做法让人更容易明白程序使用的各个模块都来自何方。 > 参考文献: > > [1] Python编程:从入门到实践 本文采用创作共用版权 CC BY-NC-SA 3.0 CN 许可协议,转载或复制请注明出处! -- 展开阅读全文 --