1. 概述

1.1 面向过程

(1) 定义:分析出解决问题的步骤,然后逐步实现。

例如:婚礼筹办

-- 请柬(选照片、措词、制作)

-- 宴席(场地、找厨师、准备桌椅餐具、计划菜品、购买食材)

-- 仪式(定婚礼仪式流程、请主持人)

(2) 公式:程序 = 算法 + 数据结构

(3) 优点:所有环节、细节自己掌控。

(4) 缺点:考虑所有细节,工作量大。

image

1.2 面向对象

(1) 定义:找出解决问题的人,然后分配职责。

例如:婚礼筹办

-- 发请柬:找摄影公司(拍照片、制作请柬)

-- 宴席:找酒店(告诉对方标准、数量、挑选菜品)

-- 婚礼仪式:找婚庆公司(对方提供司仪、制定流程、提供设备、帮助执行)

(2) 公式:程序 = 对象 + 交互

(3) 优点

a. 思想层面:

-- 可模拟现实情景,更接近于人类思维。

-- 有利于梳理归纳、分析解决问题。

b. 技术层面:

-- 高复用:对重复的代码进行封装,提高开发效率。

-- 高扩展:增加新的功能,不修改以前的代码。

-- 高维护:代码可读性好,逻辑清晰,结构规整。

(4) 缺点:学习曲线陡峭。

image

2. 类和对象

(1) 抽象:从具体事物中抽离出共性、本质,舍弃个别、非本质过程。

具体

image

抽象 --------------------------- 数据:品牌、价格、颜色.. --------------------------- 行为:通话..

(2) 类:一个抽象的概念,即生活中的”类别”。

(2) 对象:类的具体实例,即归属于某个类别的”个体”。

(3) 类是创建对象的”模板”。

2.1 语法

2.1.1 定义类

(1) 代码

 class 类名:
     """
         文档说明
     """
      def __init__(self,参数):
         self.实例变量 = 参数
 ​
      def 实例方法(self,参数):
         pass

(2) 说明

-- 类名所有单词首字母大写.

-- init 也叫构造函数,创建对象时被调用,也可以省略。

-- self 变量绑定的是被创建的对象,名称可以随意。

2.1.2 实例化对象

(1) 代码

 对象名 = 类名(数据)

(2) 说明

-- 对象名存储的是实例化后的对象地址

-- 类名后面的参数按照构造函数的形参传递

(3) 演示

 class Wife:
     """
         自定义老婆类
     """
     # 数据
     def __init__(self, name, age, sex):
         # 初始化对象数据
         self.name = name
         self.age = age
         self.sex = sex
 ​
     # 行为(方法=函数)
     def play(self):
         print(self.name, "玩耍")
 ​
 # 调用构造函数(__init__)
 shang_er = Wife("双儿", 26, "女")
 # 操作对象的数据
 shang_er.age += 1
 print(shang_er.age)
 # 调用对象的函数
 shang_er.play()# 通过对象地址调用方法,会自动传递对象地址.
 # play(shanger)
 print(shang_er)# <__main__.Wife object at 0x7f390e010f28>

练习:创建手机类,实例化两个对象并调用其函数,最后画出内存图。

 数据:品牌、价格、颜色
 ​
 行为:通话

2.2 实例成员

2.2.1 实例变量

(1) 语法

a. 定义:对象.变量名

b. 调用:对象.变量名

(2) 说明

a. 首次通过对象赋值为创建,再次赋值为修改.

 lili = Wife()
 lili.name = "丽丽"
 lili.name = "莉莉"

b. 通常在构造函数(__init_)中创建

 lili = Wife("丽丽",24)
 print(lili.name)

(3) 每个对象存储一份,通过对象地址访问

(4) 作用:描述某个对象的数据。

(5) dict:对象的属性,用于存储自身实例变量的字典。

2.2.2 实例方法

(1) 定义

     def 方法名称(self, 参数):
          方法体

(2) 调用:

     对象.方法名称(参数)
     # 不建议通过类名访问实例方法

(3) 说明

-- 至少有一个形参,第一个参数绑定调用这个方法的对象,一般命名为self。

-- 无论创建多少对象,方法只有一份,并且被所有对象共享。

(4) 作用:表示对象行为。

(5) 演示

 class Wife:
     def __init__(self, name):
         self.name = name
 ​
     def print_self(self):
         print("我是:", self.name)
 ​
 lili = Wife("丽丽")  # dict01 = {"name":"丽丽"}
 lili.name = "莉莉"  # dict01["name"] = "莉莉"
 print(lili.name)  # print(dict01["name"])
 lili.print_self()
 print(lili.__dict__)  # {"name":"丽丽"}
 ​
 """
 # 支持动态创建类成员
 # 类中的成员应该由类的创造者决定
 class Wife:
     pass
 ​
 w01 = Wife()
 w01.name = "莉莉"
 print(w01.name)#对象.变量名
 """
 ​
 """
 # 实例变量的创建要在构造函数中__init__
 class Wife:
     def set_name(self,name):
         self.name = name
 ​
 w01 = Wife()
 w01.set_name("丽丽")
 print(w01.name)
 """

练习:

创建汽车类,实例化两个对象并调用其函数,画出内存图。

数据:品牌、车牌、颜色、油量

行为:启动(油量减少2),加速(油量减少5)

image

2.2.3 跨类调用

 # 写法1:直接创建对象
 # 语义:老张每次创建一辆新车去
 class Person:
     def __init__(self, name=""):
         self.name = name
 ​
     def go_to(self,position):
         print("去",position)
         car = Car()
         car.run()
 ​
 class Car:
     def run(self):
         print("跑喽~")
 ​
 lz = Person("老张")
 lz.go_to("东北") 
 # 写法2:在构造函数中创建对象
 # 语义:老张开自己的车去
 class Person:
     def __init__(self, name=""):
         self.name = name
         self.car = Car()
 ​
     def go_to(self,position):
         print("去",position)
         self.car.run()
 ​
 class Car:
     def run(self):
         print("跑喽~")
 ​
 lz = Person("老张")  
 lz.go_to("东北") 
 # 方式3:通过参数传递
 # 语义:老张用交通工具去
 class Person:
     def __init__(self, name=""):
         self.name = name
 ​
     def go_to(self,vehicle,position):
         print("去",position)
         vehicle.run()
 ​
 class Car:
     def run(self):
         print("跑喽~")
 ​
 lz = Person("老张")
 benz = Car()
 lz.go_to(benz,"东北")

练习1:以面向对象思想,描述下列情景.

小明请保洁打扫卫生

练习2:以面向对象思想,描述下列情景.

玩家攻击敌人,敌人受伤(头顶爆字).

练习3:以面向对象思想,描述下列情景.

张无忌教赵敏九阳神功

赵敏教张无忌玉女心经

张无忌工作挣了5000元

赵敏工作挣了10000元

2.3 静态方法

(1) 定义:

 @staticmethod
 def 方法名称(参数):
     方法体

(2) 调用:

 类名.方法名称(参数) 
 # 不建议通过对象访问静态方法

(3) 说明

-- 使用@ staticmethod修饰的目的是该方法不需要隐式传参数。

-- 静态方法不能访问实例成员和类成员

(4) 作用:定义常用的工具函数。

3. 三大特征

3.1 封装

3.1.1 数据角度

(1) 定义:将一些基本数据类型复合成一个自定义类型。

(2) 优势:

-- 将数据与对数据的操作相关联。

-- 代码可读性更高(类是对象的模板)。

3.1.2 行为角度

(1) 定义:

向类外提供必要的功能,隐藏实现的细节。

(2) 优势:

简化编程,使用者不必了解具体的实现细节,只需要调用对外提供的功能。

(3) 私有成员:

-- 作用:无需向类外提供的成员,可以通过私有化进行屏蔽。

-- 做法:命名使用双下划线开头。

-- 本质:障眼法,实际也可以访问。

 私有成员的名称被修改为:_类名__成员名,可以通过_\_\_dict\__属性查看。

-- 演示

 class MyClass:
     def __init__(self, data):
         self.__data = data
 ​
     def __func01(self):
         print("func01执行了")
 ​
 m01 = MyClass(10)
 # print(m01.__data) # 无法访问
 print(m01._MyClass__data)
 print(m01.__dict__)  # {'_MyClass__data': 10}
 # m01.__func01() # 无法访问
 m01._MyClass__func01()

3.1.3 案例:信息管理系统

3.1.3.1 需求

实现对用户信息的增加、删除、修改和查询。

3.1.3.2 分析

界面可能使用控制台,也可能使用Web等等。

(1) 识别对象:界面视图类 逻辑控制类 数据模型类

(2) 分配职责:

-- 界面视图类:负责处理界面逻辑,比如显示菜单,获取输入,显示结果等。

-- 逻辑控制类:负责存储用户信息,处理业务逻辑。比如添加、删除等

-- 数据模型类:定义需要处理的数据类型。比如用户信息。

(3) 建立交互:

界面视图对象 <----> 数据模型对象 <----> 逻辑控制对象

3.1.3.3 设计

(1) 数据模型类:UserModel

-- 数据:编号 id,姓名 name,年龄 login_id,密码 pwd

(2) 逻辑控制类:UserController

-- 数据:用户列表 list_user

-- 行为:添加用户 add_user,删除用户remove_student,修改用户update_student

(3) 界面视图类:UserView

-- 数据:逻辑控制对象controller

-- 行为:显示菜单__display_menu,选择菜单项__select_menu,入口逻辑main,

 输入学生\_\_input_users,输出学生\_\_display_user,删除学生\_\_delete_user,
 ​
 修改学生信息__modify_user

3.2 继承

3.2.1 继承方法

(1) 语法:

 class 父类:
    def 父类方法(self):
      方法体
 ​
 class 子类(父类):
    def 子类方法(self):
      方法体
 ​
 儿子 = 子类()
 儿子.子类方法()
 儿子.父类方法()

(2) 说明:

子类直接拥有父类的方法.

(3) 演示:

 class Person:
     def say(self):
         print("说话")
 ​
 class Teacher(Person):
     def teach(self):
         self.say()
         print("教学")
 ​
 class Student(Person):
     def study(self):
         self.say()
         print("学习")
 ​
 qtx = Teacher()
 qtx.say()
 qtx.teach()
 ​
 xm = Student()
 xm.say()
 xm.study()

3.2.2 内置函数

(1) isinstance(对象, 类型)

 返回指定对象是否是某个类的对象。

(2) issubclass(类型,类型)

 返回指定类型是否属于某个类型。

(3) 演示

 # 对象 是一种 类型: isinstance(对象,类型)
 # 老师对象 是一种 老师类型
 print(isinstance(qtx, Teacher))  # True
 # 老师对象 是一种 人类型
 print(isinstance(qtx, Person))  # True
 # 老师对象 是一种 学生类型
 print(isinstance(qtx, Student))  # False
 # 人对象 是一种 学生类型
 print(isinstance(p, Student))  # False
 ​
 # 类型 是一种 类型: issubclass(类型,类型)
 # 老师类型 是一种 老师类型
 print(issubclass(Teacher, Teacher))  # True
 # 老师类型 是一种 人类型
 print(issubclass(Teacher, Person))  # True
 # 老师类型 是一种 学生类型
 print(issubclass(Teacher, Student))  # False
 # 人类型 是一种 学生类型
 print(issubclass(Person, Student))  # False
 ​
 # 是的关系
 # 老师对象的类型 是 老师类型
 print(type(qtx) == Teacher)  # True
 # 老师对象的类型 是 人类型
 print(type(qtx) == Person)  # False

(4) 练习:

创建子类:狗(跑),鸟类(飞)

创建父类:动物(吃)

体会子类复用父类方法

体会 isinstance 、issubclass 与 type 的作用.

3.2.3 继承数据

(1) 语法

 class 子类(父类):
  def __init__(self,父类参数,子类参数):
    super().__init__(参数) # 调用父类构造函数
    self.实例变量 = 参数

(2) 说明

子类如果没有构造函数,将自动执行父类的,但如果有构造函数将覆盖父类的。此时必须通过super()函数调用父类的构造函数,以确保父类实例变量被正常创建。

(3) 演示

 class Person:
     def __init__(self, name="", age=0):
         self.name = name
         self.age = age
         
 # 子类有构造函数,不会使用继承而来的父类构造函数[子覆盖了父方法,好像它不存在]
 class Student(Person):
     # 子类构造函数:父类构造函数参数,子类构造函数参数
     def __init__(self, name, age, score):
         # 调用父类构造函数
         super().__init__(name, age)
 ​
         self.score = score
 ​
 ts = Person("唐僧",22)
 print(ts.name)
 kw = Student("悟空", 23, 100)
 print(wk.name)
 print(wk.score)

(4) 练习:

创建父类:车(品牌,速度)

创建子类:电动车(电池容量,充电功率)

创建子类对象并画出内存图。

3.2.4 定义

(1) 概念: 重用现有类的功能,并在此基础上进行扩展。

(2) 说明:子类直接具有父类的成员(共性),还可以扩展新功能。

(3) 相关知识

-- 父类(基类、超类)、子类(派生类)。

-- 父类相对于子类更抽象,范围更宽泛;子类相对于父类更具体,范围更狭小。

-- 单继承:父类只有一个(例如 Java,C#)。

-- 多继承:父类有多个(例如C++,Python)。

-- Object类:任何类都直接或间接继承自 object 类。

3.3 多态

3.3.1 定义

(1) 字面意思:对于一种行为有不同表现形态。

(2) 概念:对于父类的一个方法,在不同的子类上有不同体现。

(3) 说明:编码时调用父类方法,运行时传递子类对象执行子类方法。

3.3.2 重写

(1) 定义:在子类定义与父类相同的方法。

(2) 作用:改变父类行为,体现子类个性。

3.3.3 重写内置函数

(1) 定义:Python中,以双下划线开头、双下划线结尾的是系统定义的成员。我们可以在自定义类中进行重写,从而改变其行为。

(2) str 函数:将对象转换为字符串(对人友好的)

-- 演示

 class Person:
     def __init__(self, name="", age=0):
         self.name = name
         self.age = age
 ​
     def __str__(self):
         return f"{self.name}的年龄是{self.age}"
 ​
 wk = Person("悟空", 26)
 # <__main__.Person object at 0x7fbabfbc3e48>
 # 悟空的年龄是26
 print(wk) 
 # message = wk.__str__()
 # print(message)
 ​

练习:

直接打印商品对象: xx的编号是xx,单价是xx

直接打印敌人对象: xx的攻击力是xx,血量是xx

 class Commodity:
   def __init__(self, cid=0, name="", price=0):
     self.cid = cid
     self.name = name
     self.price = price
 ​
 class Enemy:
   def __init__(self, name="", atk=0, hp=0):
     self.name = name
     self.atk = atk
     self.hp = hp

(3) 算数运算符

image

-- 演示

 class Vector2:
     """
         二维向量
     """
 ​
     def __init__(self, x, y):
         self.x = x
         self.y = y
 ​
     def __str__(self):
         return "x是:%d,y是:%d" % (self.x, self.y)
 ​
     def __add__(self, other):
         return Vector2(self.x + other.x, self.y + other.y)
 ​
 v01 = Vector2(1, 2)
 v02 = Vector2(2, 3)
 print(v01 + v02)  # v01.__add__(v02)

-- 练习:创建颜色类,数据包含r、g、b、a,实现颜色对象相加。

(4) 复合运算符重载

image

-- 演示

 class Vector2:
     """
         二维向量
     """
 ​
     def __init__(self, x, y):
         self.x = x
         self.y = y
 ​
     def __str__(self):
         return "x是:%d,y是:%d" % (self.x, self.y)
 ​
     # + 创建新
     def __add__(self, other):
         return Vector2(self.x + other.x, self.y + other.y)
 ​
     # += 在原有基础上修改(自定义类属于可变对象)
     def __iadd__(self, other):
         self.x += other.x
         self.y += other.y
         return self
 ​
 v01 = Vector2(1, 2)
 v02 = Vector2(2, 3)
 print(id(v01))
 v01 += v02
 print(id(v01))
 print(v01)

-- 练习:创建颜色类,数据包含r、g、b、a,实现颜色对象累加。

(5) 比较运算重载

image

-- 演示

 class Vector2:
     """
         二维向量
     """
 ​
     def __init__(self, x, y):
         self.x = x
         self.y = y
 ​
     # 决定相同的依据
     def __eq__(self, other):
         return self.x == other.x and self.y == other.y
 ​
     # 决定大小的依据
     def __lt__(self, other):
         return self.x < other.x
 ​
 ​
 v01 = Vector2(1, 1)
 v02 = Vector2(1, 1)
 print(v01 == v02)  # True 比较两个对象内容(__eq__决定)
 print(v01 is v02)  # False 比较两个对象地址
 ​
 list01 = [
     Vector2(2, 2),
     Vector2(5, 5),
     Vector2(3, 3),
     Vector2(1, 1),
     Vector2(1, 1),
     Vector2(4, 4),
 ]
 ​
 # 必须重写 eq
 print(Vector2(5, 5) in list01)
 print(list01.count(Vector2(1, 1)))
 ​
 # 必须重写 lt
 list01.sort()
 print(list01)

-- 练习:创建颜色列表,实现in、count、index、max、sort运算。