一、面向对象与面向过程
面向对象编程(Object-Oriented Programming,简称OOP)和面向过程编程(Procedural Programming,简称PP)是两种不同的编程范式。
面向对象编程强调把问题分解成对象,通过封装、继承和多态等机制,来处理对象之间的关系。每个对象都可以独立地处理自己的数据和行为,而不需要依赖其他对象。面向对象编程更加注重代码的重用性、可维护性和可扩展性,适用于大型、复杂的软件系统开发。
而面向过程编程则是一种以过程为中心的编程方式,它将问题分解成一系列的步骤,然后按照顺序执行这些步骤,以达到求解问题的目的。在面向过程编程中,数据和操作是分离的,函数是处理数据的主要手段。面向过程编程更加注重效率和速度,适用于小型、简单的程序或者性能要求较高的场景。
1、什么是面向过程?
面向过程:问题分解成一系列的步骤,然后按照顺序执行这些步骤
举个简单的例子
相信大家都被问过这样一个问题: 把大象装入冰箱需要几步?
按照面向过程的思想:需要三步
第一步:打开冰箱
第二步:把大象塞进去
第三步:关上冰箱
从这里就可以看出:面向过程就是把一件事按步骤一步一步来实现
代码实现:
# 第一步:打开冰箱门 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、什么是面向对象?
对象:就是对问题中的事物的抽象
对象可以说是对现实事物的一种抽象映射。
面向对象:就是把现实中的事物都抽象为“对象”。每个对象是唯一的,且都可以拥有它的属性与行为。我们就可以通过调用这些对象的方法、属性去解决问题。
按照面向对象的思想
在这个例子中:
我们可以把大象看作一个对象,冰箱看作一个对象。
冰箱的一些功能:开门、装物体、关门
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来定义类
# 定义一个带有成员方法的类 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 成员方法
语法:
在类中定义成员方法和定义函数基本一致,只存在细微区别:
注意: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. 魔法方法
内置的类方法,各自有各自特殊的功能,这些内置方法我们称之为:魔术方法
常见的魔法方法:
上述表格因为语法限制,把下面的下划线之间都空了一格,实际上两条下划线之间并没有空格!
常见的魔法方法
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关键字
这是因为:变量是定义在构造方法内部,如果要成为成员变量,需要用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个对象进行比较是不可以的
在类中实现 _ _ 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)
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