面向对象详解,面向对象的三大特征:封装、继承、多态-1

简介: 面向对象详解,面向对象的三大特征:封装、继承、多态

一、面向对象与面向过程

面向对象编程(Object-Oriented Programming,简称OOP)和面向过程编程(Procedural Programming,简称PP)是两种不同的编程范式。


面向对象编程强调把问题分解成对象,通过封装、继承和多态等机制,来处理对象之间的关系。每个对象都可以独立地处理自己的数据和行为,而不需要依赖其他对象。面向对象编程更加注重代码的重用性、可维护性和可扩展性,适用于大型、复杂的软件系统开发。


而面向过程编程则是一种以过程为中心的编程方式,它将问题分解成一系列的步骤,然后按照顺序执行这些步骤,以达到求解问题的目的。在面向过程编程中,数据和操作是分离的,函数是处理数据的主要手段。面向过程编程更加注重效率和速度,适用于小型、简单的程序或者性能要求较高的场景。


1、什么是面向过程?

面向过程:问题分解成一系列的步骤,然后按照顺序执行这些步骤

举个简单的例子

相信大家都被问过这样一个问题: 把大象装入冰箱需要几步?

7d83032c40496f69f75c23d2173b2c05_ec2c9cd70b8047c891c4c2b6f2e8278c.png

按照面向过程的思想:需要三步

第一步:打开冰箱

第二步:把大象塞进去

第三步:关上冰箱

389072dfabfdf3cc31afd37682a3046f_0ce72eb1965141c785eb690e62ae8687.png

从这里就可以看出:面向过程就是把一件事按步骤一步一步来实现


代码实现:


# 第一步:打开冰箱门
def open_door():
    print("打开冰箱门")

# 第二步:把大象放进去
def put_elephant():
    print("把大象放进去")

# 第三步:关闭冰箱门
def close_door():
    print("关闭冰箱门")

# 完成三个步骤
def put_elephant_in_fridge():
    open_door()
    put_elephant()
    close_door()

# 测试程序
put_elephant_in_fridge()

这就是面向过程代码的具体实现啦


2、什么是面向对象?

对象:就是对问题中的事物的抽象

对象可以说是对现实事物的一种抽象映射。

面向对象:就是把现实中的事物都抽象为“对象”。每个对象是唯一的,且都可以拥有它的属性与行为。我们就可以通过调用这些对象的方法、属性去解决问题。


按照面向对象的思想

515dc80267bed2ed855372be64235c45_d252df9caf9741a0b020eff8d88eb573.png

在这个例子中:

我们可以把大象看作一个对象,冰箱看作一个对象。

冰箱的一些功能:开门、装物体、关门


class Elephant:  # 大象类
    def Eat(self):  # 吃
        print('吃')

class Fridge:  # 冰箱类
    def open_door(self):  # 打开冰箱门
        print('打开冰箱门')
    
    def Put_In(self):  # 放入东西
        print('放入东西')
    
    def close_door(self):  # 关闭冰箱门
        print('关闭冰箱门')

在面向对象中,每个对象是独立的,有属于它自己的功能,只需要专心实现自己的功能就好。所以在建立对象模型阶段,仅仅关注对象有什么的功能,但不考虑如何实现这些功能。


面向对象对象的特点:有很好的延展性,比如我给大象赋予了一个吃的功能,它通过调用就可以在冰箱里去吃东西。面向对象就是把现实问题抽象为对象,通过调用每个对象的属性或功能去解决问题。


二、类与对象

1. 初识对象

什么是对象?

对象是面向对象编程中的一个概念,它是类的一个实例化(即具体化)的结果。对象是具体的、实际存在的,可以在程序中被创建、操作和销毁。

面向对象编程中,对象是由属性 和方法组成的。属性表示对象的状态和特征,方法表示对象可以执行的操作和行为。

每个对象都属于某个类,类是对象的抽象,它定义了对象所具有的属性和方法的结构和行为。对象通过实例化类来创建,并且可以根据类的定义进行属性和方法的访问和调用。


以下是一个简单的示例:


class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def say_hello(self):
        print(f"Hello, 我叫 {self.name}.")

# 创建两个Person对象
person1 = Person("张三", 25)
person2 = Person("李四", 30)

# 调用对象的方法
person1.say_hello()  # 输出: Hello, 我叫张三.
person2.say_hello()  # 输出: Hello, 我叫李四.

通过创建对象,我们可以根据类的定义来操作和管理数据,并执行对象所具有的行为。


2. 类的成员方法

2.1 类的定义和使用

在python中,用关键字class来定义类


dec50a93c9bbfa7ee7c77dc9ad3db974_8926ff292e6d4245bc87381b446e1bcd.png

# 定义一个带有成员方法的类
class Student:
    # 成员变量
    name = None  # 学生的姓名
    # 定义方法
    def say_hi1(self):
        print(f'大家好,我叫{self.name}')  # 成员方法中访问成员变量必须要用self关键字!

    def say_hi2(self, msg):
        print(f'大家好,我是{self.name},{msg}')  # msg为外部传入的不需要用self!

stu1 = Student()
stu1.name = '张三'
stu1.say_hi1()
stu2 = Student()
stu2.name = '李四'
stu2.say_hi2('请多多关照')

运行结果:

可以看出,在类中:

  • 不仅可以定义属性用来记录数据
  • 也可以定义函数,用来记录行为

其中:

  • 类中定义的属性(变量),我们称之为:成员变量
  • 类中定义的行为(函数),我们称之为:成员方法

2.2 成员方法

语法:

在类中定义成员方法和定义函数基本一致,只存在细微区别:

97b1de6ff638f6966c5449a812a3b925_7366c3d0f5eb44369ee4d2112805626b.png


注意:self关键字是成员方法定义的时候,必须填写的。

  • 它用来表示类对象自身的意思
  • 当我们使用类对象调用方法的是,self会自动被python传入
  • self出现在形参列表中,但是不占用参数位置,无需理会
  • 在方法内部,想要访问类的成员变量,必须使用self

例如:

class Student:
    # 成员变量
    name = None  # 学生的姓名
    # 定义方法
    def say_hi(self):
        print(f'大家好,我叫{self.name}')
class Student:
    # 成员变量
    name = None  # 学生的姓名
    def say_hi(self, msg):
        print(f'大家好,{msg}')  # msg为外部传入的不需要用self!
        
stu = Student()
stu.say_hi('请多多关照')

可以看到,在传入参数的时候,没有传入self,但也没有报错。


3. 类和对象


基于类创建对象的语法:

对象名 = 类名称()

为什么非要创建对象才能使用呢?


类只是一种程序内的“设计图纸”或者摸具,需要基于图纸或摸具生产实体(对象),才能正常工作这种套路,称之为:面向对象编程


举一个简单的例子:

类就相当于是闹钟的设计图纸,而对象就相当于按照闹钟的设计图纸所生产出来的闹钟。


从上面可以看出,设计出来的类包含编号和价格,具有响铃的功能。而基于类所创建的对象也有对应的编号和价格

所以面向对象编程就是设计类,基于类创建对象,由对象做具体的工作。


4. 魔法方法

内置的类方法,各自有各自特殊的功能,这些内置方法我们称之为:魔术方法

常见的魔法方法:

image.png

上述表格因为语法限制,把下面的下划线之间都空了一格,实际上两条下划线之间并没有空格!


常见的魔法方法


fbd438fb3571185920e590414b49fcbb_b9ad703c48284798a114c5a5c630f86e.png

1. _ _ inint _ _ 构造方法

class Student:
    name = None  # 姓名
    age = None  # 年龄
    tel = None  # 手机号

stu1 = Student()
stu1.name = '张三'
stu1.age = 18
stu1.tel = "1686400001"
stu2 = Student()
stu2.name = '李四'
stu2.age = 19
stu2.tel = "163200002"

上面代码中,为对象的属性赋值需要依次进行,略显繁琐。可不可以像函数传参那样直接一次性对属性进行赋值呢?

答案是肯定的,需要使用构造方法:_ _ init _ _()


Python类可以使用:_ _ init _ _() 方法,称之为构造方法。

可以实现:

  • 在创建类对象(构造类)的时候,会自动执行。
  • 在创建类对象(构造类)的时候,将传入参数自动传递给__init__方法使用。
class Student:
    # 成员对象
    """
    __init__构造方法里对成员变量进行了声明并赋值
    所以成员对象这里可省略
    """
    name = None
    age = None
    tel = None

    def __init__(self, name, age, tel):
        self.name = name
        self.age = age
        self.tel = tel
        print('Student类创建了一个类对象')  # 输出:Student类创建了一个类对象

stu1 = Student('张三', '18', '13066660')
print(stu1.name)  # 输出:张三
print(stu1.age)  # 输出:18
print(stu1.tel)  # 输出:13066660

注意:

在构造方法内定义成员变量,需要使用self关键字

224bd7dbe4e033defe3d09ba2387a411_3036a35f73a24ce9ad24ded22243bf1b.png

这是因为:变量是定义在构造方法内部,如果要成为成员变量,需要用self来表示。


2. _ _ str _ _ 字符串方法
  • 方法名:_ _ str _ _
  • 返回值:字符串
  • 内容:自行定义
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

stu1 = Student('张三', 18)
print(stu1)  # 输出:<__main__.Student object at 0x000001EDFFB09FD0>
print(str(stu1))  # 输出:<__main__.Student object at 0x000001EDFFB09FD0>

当类对象需要被转换为字符串之时,会输出如上结果(内存地址)


内存地址没有多大作用,我们可以通过 _ _ str _ _ 方法,控制类转换为字符串的行为。


class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def __str__(self):
        return f'name:{self.name}, age:{self.age}'
        
stu1 = Student('张三', 18)
print(stu1)  # 输出:name:张三, age:18
print(str(stu1))  # 输出:name:张三, age:18
3. _ _ lt _ _ 小于符号比较方法
  • 方法名:_ _ lt _ _
  • 传入参数:other,另一个类对象
  • 返回值:True 或 False
  • 内容:自行定义
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

stu1 = Student('张三', 18)
stu2 = Student('李四', 19)
print(stu1 < stu2)
print(stu1 > stu2)

像这样直接对2个对象进行比较是不可以的

f83e663236aa7d87510194e4bb058426_93f3e48c0311475787f4ceeae2f78880.png

在类中实现 _ _ lt _ _ 方法,可同时完成:小于符号和大于符号2种比较。

  • 方法名:_ _ lt _ _
  • 传入参数:other,另一个类对象
  • 返回值:True 或 False
  • 内容:自行定义
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    # __lt__魔法方法: 两个类对象进行大于或小于的比较
    def __lt__(self, other):
        return self.age < other.age

stu1 = Student('张三', 18)
stu2 = Student('李四', 19)
print(stu1 < stu2)  # 输出:True
print(stu1 > stu2)  # 输出:False

比较大于符号的魔术方法是:_ _ gt _ _, 方法和 _ _ lt _ _ 一样,所以实现了 _ _ lt _ _ ,_ _gt _ _ 就没必要实现了。


4. _ _ le _ _ 小于等于比较符号方法

这个和 _ _ lt _ _ 一样,唯一不同的是 _ _ lt _ _ 是比较大于或小于,而 _ _ le _ _ 则是比较大于等于和小于等于。

  • 方法名:_ _ le _ _
  • 传入参数:other,另一个类对象
  • 返回值:True 或 False
  • 内容:自行定义
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    # __lt__魔法方法: 两个类对象进行大于或小于的比较
    def __lt__(self, other):
        return self.age < other.age
        
stu1 = Student('张三', 18)
stu2 = Student('李四', 19)
print(stu1 <= stu2)
print(stu1 >= stu2)

2c33e08e854905c4fbc3c285a67d96ba_71cffad6b06544bfa9980cbc76b391d4.png


class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    # __lt__魔法方法: 两个类对象进行大于或小于的比较
    def __lt__(self, other):
        return self.age < other.age

  # __le__魔法方法: 两个类对象进行大于等于或小于等于的比较
    def __le__(self, other):
        return self.age <= other.age

stu1 = Student('张三', 18)
stu2 = Student('李四', 19)
print(stu1 <= stu2)  # 输出:True
print(stu1 >= stu2)  # 输出:False
5. _ _ eq _ _ 相等比较方法
  • 方法名:eq
  • 传入参数:other,另一个类对象
  • 返回值:True 或 False
  • 内容:自行定义
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
stu1 = Student('张三', 18)
stu2 = Student('李四', 19)
print(stu1 == stu2)  # 输出:False

不实现 _ _ eq _ _ 方法,对象之间也可以进行比较,但是是比较内存地址,也即是:不同对象==比较一定是False结果。


class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    # __eq__魔法方法: 两个类对象进行相等的比较
    def __eq__(self, other):
        return self.age == other.age
stu1 = Student('张三', 18)
stu2 = Student('李四', 18)
print(stu1 == stu2)  # 输出:True

实现了 _ _ eq _ _ 方法,就可以按照自己的想法来决定2个对象是否相等了。


面向对象详解,面向对象的三大特征:封装、继承、多态-2

https://developer.aliyun.com/article/1538241

相关文章
|
Java
面向对象编程的三大特征:封装;继承;多态
面向对象编程的三大特征:封装;继承;多态
66 0
|
6月前
|
Python 容器
面向对象详解,面向对象的三大特征:封装、继承、多态-2
面向对象详解,面向对象的三大特征:封装、继承、多态
|
6月前
|
安全
面向对象特征(抽象、封装、继承、多态)的具体用法
面向对象特征(抽象、封装、继承、多态)的具体用法
27 0
|
6月前
面向对象三大特征——封装,继承
面向对象三大特征——封装,继承
|
算法 Java 编译器
类和面向对象
类和面向对象
110 0
|
7月前
|
编译器 C++
[C++] 面向对象的三大特性:封装、继承和多态
[C++] 面向对象的三大特性:封装、继承和多态
93 0
|
C++
C++ 面向对象特征4 多态(Polymorphism)
C++ 面向对象特征4 多态(Polymorphism)
49 0
|
设计模式 数据安全/隐私保护
面向对象编程基础:封装、继承、多态与抽象的全面解析
面向对象编程基础:封装、继承、多态与抽象的全面解析
248 0
浅谈 面向对象三大特性:封装 继承 多态
浅谈 面向对象三大特性:封装 继承 多态
94 0