天天看点

Python 面向对象系列(一)01 面向对象的基本概念02 类和对象的基本概念03 类的设计04 面向对象基础语法

面向对象基础

  • 01 面向对象的基本概念
    • 1.1 过程和函数(科普)
    • 1.2 面向过程 和 面向对象 基本概念
  • 02 类和对象的基本概念
    • 2.1 类
    • 2.2 对象
    • 2.3 类和对象的关系
  • 03 类的设计
    • 3.1 类名的确定
    • 3.2 属性和方法的确定
  • 04 面向对象基础语法
    • 4.1 dir内置函数(了解即可)
    • 4.2 定义简单的类 (只包含方法)
      • 4.2.1 定义只包含方法的类
      • 4.2.2 创建对象
      • 4.2.3 第一个面向对象程序
    • 4.3 方法中的self参数
      • 4.3.1 案例改造(给对象增加属性)
      • 4.3.2 使用 self 在方法内部输出每一只猫的名字
    • 4.4 初始化方法
      • 4.4.1 之前代码存在问题(在类的外部给对象增加属性)
      • 4.4.2 初始化方法
      • 4.4.3 在初始化方法内部定义属性
      • 4.4.4 改造初始化方法(初始化的同时设置初始值)
    • 4.5 内置方法和属性
      • 4.5.1 __ del __ 方法(了解即可)
      • 4.5.2 __ str __ 方法

01 面向对象的基本概念

  • 我们之前学习的编程方式就是 面向过程 的
  • 面向对象和面向过程,是两种不同的 编程方式
  • 对比 面向过 程的特点,可以更好地了解什么是 面向对象

1.1 过程和函数(科普)

  • 过程 是早期的一个编程概念
  • 过程 类似于函数,只能执行,但是没有返回值
  • 函数 不仅能执行,还可以返回结果

1.2 面向过程 和 面向对象 基本概念

1)面向过程 ——怎么做?

  1. 把完成某一个需求 所有步骤 从头到尾 逐步实现
  2. 根据开发需求,将某些 功能独立 的代码 封装 成一个又一个 函数
  3. 最后完成的代码,就是顺序地调用 不同的函数

特点

  1. 注重 步骤与过程,不注重职责分工
  2. 如果需求复杂,代码会变得很复杂
  3. 开发复杂项目,没有固定的套路,开发难度很大
Python 面向对象系列(一)01 面向对象的基本概念02 类和对象的基本概念03 类的设计04 面向对象基础语法

2)面向对象 ——谁来做?

相比较函数,面向对象 是 更大 的 封装,根据职责 在 一个对象中 封装 多个方法
  1. 在完成某一个需求时,首先确定 职责 —— 要做的事情(方法)
  2. 根据 职责 确定不同的 对象,在 对象 内部封装不同的 方法 (多个)
  3. 最后完成代码,就是让 不同的对象 调用 不同的方法

特点

  1. 注重 对象和职责 ,不同的对象承担不同的职责
  2. 更加适合应对复杂的需求变化,是专门应对复杂项目开发,提供的固定套路
  3. 需要在面向对象的基础上,在学习一些面向对象的语法

02 类和对象的基本概念

类 和 对象 是 面向对象编程的 两个 核心概念

2.1 类

  • 类 是一对具有 相同 特征 或者 行为 的事务的一个统称,是抽象的,不能直接使用
    • 特征 被称为 属性
    • 行为 被称为 方法
  • 类 就是相当于制造飞机时的图纸,是一个 模板,是 负责创建对象的
    Python 面向对象系列(一)01 面向对象的基本概念02 类和对象的基本概念03 类的设计04 面向对象基础语法

2.2 对象

  • 对象 是 由类创建出来的一个具体存在,可以直接使用
  • 由 哪一个类 创建出来的 对象,就拥有在 哪一个类 中定义的 属性和方法
  • 对象 就相当于用 图纸 制造 的飞机
在程序开发中,应该先有类,再有对象
Python 面向对象系列(一)01 面向对象的基本概念02 类和对象的基本概念03 类的设计04 面向对象基础语法

2.3 类和对象的关系

  • 类是模板,对象 是根据 类 这个模板创建出来的,应该 先有类,再有对象
  • 类 只有一个,而 对象 可以有很多个
    • 不同对象 之间 属性 可能会各不相同
  • 类 中定义了什么 属性和方法,对象 中就有什么属性和方法,不可能多,也不可能少

03 类的设计

在使用面向对象开发前,应该首先分析需求,确定一下,程序中需要包含哪些类!

Python 面向对象系列(一)01 面向对象的基本概念02 类和对象的基本概念03 类的设计04 面向对象基础语法

在程序开发中,要设计一个类,通常需要满足一下三个要素:

  • 类名 这类事物的名字,满足大驼峰命名法(CapWords 1、每个单词首字母大写2、单词与单词之间没有下划线)
  • 属性 这类事物具有什么样的特征
  • 方法 这类事物具有什么样的行为

3.1 类名的确定

名词提炼法 分析 整个业务流程,出现的 名词,通常就是找到的类

3.2 属性和方法的确定

  • 对 对象的特征描述,通常可以定义为 属性
  • 对象具有的行为(动词),通常可以定义成 方法
提示:需求中没有涉及的属性或者方法,在设计类时,不需要考虑

练习1 需求

1、小明今年 10岁,身高 1.75米 每天早上跑步,吃东西

2、小美今年 17岁,身高 1.65米 每天不跑步,喜欢吃东西

属性 方法
Person name、age、height run()、 eat()

练习2 需求

1、一只 黄颜色 的狗狗 叫 大黄

2、看见生人 汪汪叫

3、看见家人 摇尾巴

属性 方法
Dog name、color shout()、 shake()

04 面向对象基础语法

4.1 dir内置函数(了解即可)

  • 在Python中, 对象几乎时无所不在的,我们之前学习的 变量、数据、函数 都是对象

    在Python中可以使用以下两个方法验证:

  1. 在 标识符/数据 后面输入一个 .,然后按下 Tab键,iPython会提示该对象能够调用的 方法列表
  2. 在使用内置函数dir传入 标识符/数据,可以查看对象内的 所有属性和方法
提示:__ 方法名 __ 格式()的方法是 Python提供的 内置方法/属性,下面类别展示常用的 内置方法/属性
序号 方法名 类型 作用
1 __ new __ 方法 创建对象时,会被 自动 调用
2 __ init __ 方法 对象初始化时,会被 自动 调用
3 __ del __ 方法 对象被从内存中销毁前,会被 自动 调用
4 __ str __ 方法 返回对象的描述信息,会被 自动 调用
提示:利用好 dir() 函数,在学习中很多内容就不用死记硬背了

4.2 定义简单的类 (只包含方法)

面向对象 是 更大 的 封装,在一个类中 封装 多个方法,这样 通过这个类创建出来的对象,就可以直接调用这些方法了!

4.2.1 定义只包含方法的类

  • 在Python 中 要定义一个只包含方法的类,语法格式如下:
class 类名:
    
    def 方法一(self,参数列表):
        pass
    def 方法二(self,参数列表):
        pass

           
  • 方法 的定义格式和之前学过的函数 几乎一样
  • 区别在于第一个参数必须是self
注意:类名 的 命名规则 要符合 大驼峰命名法(1、每个单词首字母大写2、单词与单词之间没有下划线)

4.2.2 创建对象

  • 当一个类定义完成之后,要使用这个类来创建对象,语法格式如下:

4.2.3 第一个面向对象程序

需求

小猫 爱 吃 鱼,小猫 要 喝 水

分析

  1. 定义一个猫类 Cat
  2. 定义两个方法 eat和drink
  3. 按照需求 ,不需要定义属性
方法
Cat eat(self)、 drink(self)

代码实现

class Cat:
    """定义一个猫类"""

    def eat(self):
        print("小猫爱吃鱼")

    def drink(self):
        print("小猫爱喝水")


# 创建猫对象
tom = Cat()
tom.eat()
tom.drink()

           

引用概念

在面向对象开发中,引用的概念是同样适用的!
  • 在Python中使用类 创建对象之后,tom变量中 仍然记录的是 对象在内存中的地址
  • 也就是 tom 变量 引用了 新建的猫对象
  • 使用 print 输出 对象变量,默认情况下,是能够输出这个变量 引用对象 是 有哪一个类创建的对象,以及 在内存中的地址(十六进制表示)
提示:在计算机中,通常使用 十六进制 表示内存地址
  • 十进制 和十六进制 都是用来表达数字的,只是表示的方式不一样
  • 十进制 和十六进制 的数字之间可以来回转换
  • %d 可以 以 十进制 输出数字
  • %x 可以 以 十六进制 输出数字

代码实现

class Cat:
    """定义一个猫类"""

    def eat(self):
        print("小猫爱吃鱼")

    def drink(self):
        print("小猫爱喝水")


# 创建猫对象
tom = Cat()

tom.eat()
tom.drink()

print(tom)

addr = id(tom)
print("%x" % addr)

           

输出结果

小猫爱吃鱼

小猫爱喝水

<main.Cat object at 0x0000023D397A3A60>

23d397a3a60

案例进阶(使用Cat类再创建一个对象)

代码实现

class Cat:
    """定义一个猫类"""

    def eat(self):
        print("小猫爱吃鱼")

    def drink(self):
        print("小猫爱喝水")


# 创建猫对象
tom = Cat()

tom.eat()
tom.drink()

print(tom)

# 再创建一只猫
lazy_cat = Cat()

lazy_cat.eat()
lazy_cat.drink()

print(lazy_cat)

lazy_cat2 = lazy_cat

print(lazy_cat2)

           

提问:tom和lazy_cat是同一个对象吗?

答案:不是

输出结果

小猫爱吃鱼

小猫爱喝水

<main.Cat object at 0x000001FF31693A60>

小猫爱吃鱼

小猫爱喝水

<main.Cat object at 0x000001FF316AD730>

<main.Cat object at 0x000001FF316AD730>

4.3 方法中的self参数

4.3.1 案例改造(给对象增加属性)

  • 在 Python中,要 给对象设置属性,非常的容易,但是不推荐使用
    • 因为:对象属性的封装应该封装在类的内部
  • 只需要在 类的外部的代码 中直接通过 . 设置一个属性即可

    注意:这种方式虽然简单,但是不推荐使用!!!

tom.name = "Tom"
...
lazy_cat.name = "大懒猫"
           

4.3.2 使用 self 在方法内部输出每一只猫的名字

由 哪一个对象 调用的方法,方法内的 self就是 哪一个对象的引用
  • 在类封装的方法内部,self就表示 当前调用方法的对象本身
  • 调用方法时,程序员不需要传递self参数
  • 在方法内部
    • 可以通过self. 访问对象的属性
    • 也可以通过self. 调用对象的其他方法
  • 在 类的外部,通过 变量名. 访问对象的 属性和方法
  • 在 类封装的方法中,通过 self. 访问对象的 属性和方法

改造代码实现

class Cat:
    """定义一个猫类"""

    def eat(self):
        # 哪一个对象调用方法,self就是哪一个对象的引用
        print("%s 爱吃鱼" % self.name)

    def drink(self):
        print("%s 爱喝水" % self.name)


# 创建猫对象
tom = Cat()

# 可以使用 .属性名,利用赋值语句就可以
tom.name = "Tom"

tom.eat()
tom.drink()

print(tom)

# 再创建一只猫对象
lazy_cat = Cat()

lazy_cat.name = "大懒猫"

lazy_cat.eat()
lazy_cat.drink()

print(lazy_cat)

           

改造代码输出结果

Tom 爱吃鱼

Tom 爱喝水

<main.Cat object at 0x0000016C4FBD3A60>

大懒猫 爱吃鱼

大懒猫 爱喝水

<main.Cat object at 0x0000016C4FBEDA60>

4.4 初始化方法

4.4.1 之前代码存在问题(在类的外部给对象增加属性)

  • 将上述改造代码进行调整,先调用方法 再设置属性,观察 执行效果
tom = Cat()
tom.eat()
tom.drink()
tom.name = "Tom"
print(tom)

           
  • 程序执行报错如下:

AttributeError: ‘Cat’ object has no attribute ‘name’

属性错误: ‘Cat’ 对象没有 ‘name’ 属性

提示

  • 在日常开发中,不推荐在 类的外部 给对象增加属性
  • 如果在运行时,没有找到属性,程序就会报错
  • 对象应该包含哪些属性,应该 封装在类的内部

4.4.2 初始化方法

  • 当使用 类名() 创建对象时,会 自动 执行以下操作:
    1. 为对象在内存中 分配空间 —— 创建对象
    2. 为对象的属性 设置初始值 —— 初始化方法(__ init __)
  • 这个 初始化方法 就是__ init __ 方法,__ init __ 是对象的内置方法
__ init __ 方法是 专门 用来定义一个类 具有哪些属性的方法!

在Cat 增加__ init __方法,验证该方法在创建对象时会被自动调用

class Cat:

    def __init__(self):
        print("初始化方法")


# 使用类名() 创建对象的时候,会自动调用初始化方法__init__
tom = Cat()
           

输出结果

初始化方法

4.4.3 在初始化方法内部定义属性

  • 在__ init __ 方法 内部使用 self.属性名=属性的初始值 就可以定义属性
  • 定义属性之后,再使用Cat 类创建的对象,就会拥有该属性

代码实现

class Cat:

    def __init__(self):
        print("初始化方法")

        # self.属性名= 属性初始值
        self.name = "Tom"


# 使用类名() 创建对象的时候,会自动调用初始化方法__init__
tom = Cat()

print(tom.name)

           

输出结果

初始化方法

Tom

4.4.4 改造初始化方法(初始化的同时设置初始值)

  • 在开发中,如果希望在创建对象的同时,就设置对象的属性,可以对__ init __方法进行改造
    1. 把希望设置的属性值,定义成__ init __ 方法的参数
    2. 在方法内部使用 self.属性=形参 接受外部参数
    3. 在创建对象时,使用类名(属性1,属性2…)调用

代码实现

class Cat:

    def __init__(self, new_name):
        print("初始化方法")

        # self.属性名= 属性初始值
        # self.name = "Tom"
        self.name = new_name

    def eat(self):
        print("%s 爱吃鱼" % self.name)


# 使用类名() 创建对象的时候,会自动调用初始化方法__init__
tom = Cat("Tom")

print(tom.name)

lazy_cat = Cat("大懒猫")

lazy_cat.eat()

           

输出结果

初始化方法

Tom

初始化方法

大懒猫 爱吃鱼

4.5 内置方法和属性

序号 方法名 类型 作用
3 __ del __ 方法 对象被从内存中销毁前,会被 自动 调用
4 __ str __ 方法 返回对象的描述信息,会被 自动 调用

4.5.1 __ del __ 方法(了解即可)

  • 在Python中
    • 当使用 类名()创建对象时,为对象 分配完空间后,自动调用 __ init __ 方法
    • 当一个 对象被从内存中销毁前,会自动 调用 __ del __方法
  • 应用场景
    • __ init __ 改造初始化方法,可以让创建对象更加灵活
    • __ del 如果希望在对象被销毁前,再做一些使用,可以考虑一下 del __ 方法
  • 生命周期
    • 一个对象从调用类名()创建,生命周期开始
    • 一个对象的__ del __ 方法一旦被调用,生命周期结束
    • 在对象的生命周期内,可以访问对象属性,或者让对象调用方法

代码实现

class Cat:
    def __init__(self, new_name):
        self.name = new_name
        print("%s 来啦" % self.name)

    def __del__(self):
        print("%s 去啦" % self.name)


tom = Cat("Tom")
print(tom.name)

# del关键字可以主动删除一个对象
del tom

print("⭐" * 20)

           

输出结果

Tom 来啦

Tom

Tom 去啦

⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐

4.5.2 __ str __ 方法

  • 在Python中,使用print 输出 对象变量,默认情况下,会输出这个变量 引用的对象 是 由哪一个类创建的对象,以及 在内存中的地址(十六进制表示)
  • 如果在开发中,希望使用print输出 对象变量 时,能够打印 自定义内容,就可以利用 __ str __ 这个内置方法了
注意:__ str __ 方法必须返回一个字符串

代码实现

class Cat:
    def __init__(self, new_name):
        self.name = new_name
        print("%s 来啦" % self.name)

    def __del__(self):
        print("%s 去啦" % self.name)

    def __str__(self):

        # 必须返回一个字符串
        return "我是小猫【%s】" % self.name


# tom 是一个全局变量
tom = Cat("Tom")
print(tom)

           

输出结果

Tom 来啦

我是小猫【Tom】

Tom 去啦