【一】什么是面向过程
【1】面向过程介绍
- 面向过程,核心在于 “过程” 二字
- 过程的终极奥义就是将程序 “流程化”
- 过程是 “流水线” ,用来分步骤解决问题的
- 过程指的是解决问题的步骤,即先干什么再干什么......
- 面向过程的设计就好比精心设计好一条流水线,是一种机械式的思维方式。
【2】面向过程的优点
- 复杂度的问题流程化,进而简单化(一个复杂的问题,分成一个个小的步骤去实现,实现小的步骤将会非常简单)
【3】面向过程的缺点
- 一套流水线或者流程就是用来解决一个问题,生产汽水的流水线无法生产汽车,即便是能,也得是大改,改一个组件,牵一发而动全身。
【二】什么是面向对象
【1】面向对象介绍
- 面向对象,核心在于“对象”二字
- 对象的终极奥义就是将程序 “整合”
- 对象就是 “容器” ,用来盛放数据与功能
(1)面向对象理解文字版
- 面向对象就相当于上帝,在上帝的视角,人是对象,动物是对象,石头是对象,水是对象,山是对象,存在的可以扩充,不存在的可以创造。
(2)面向对象设计理解文字版
- 面向对象的设计就好比我们要设计一个小校园模拟器,我们需要在校园中创造各种生活场景,包括上课、做饭、打球等等。
- 这些场景对应的角色就是对象,比如老师、学生、运动员、厨师等。
- 而每一个角色都会对应其具有的责任和功能
- 比如一个学生具有姓名、年龄、性别、所在班级等。
- 学生还有能做的活动,读书、写作、跑步、打篮球等。
- 比如一个老师可以教书、批改作业等。
- 比如运行员可以参加训练和比赛等。
- 当我们的角色和功能构建好以后,我们又需要创建几个学生、一些老师和运行员,让他们进行各项活动。
- 比如一个学生可以上课、写作业、运动;
- 比如一个老师可以教课、批改作业;
- 比如一个运动员可以训练、参加比赛
【2】面向对象的优缺点
(1)面向对象的优点
- 解决了程序的扩展性。
- 对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
(2)面向对象的缺点
- 编程的复杂度远高于面向过程,不了解面向对象而立即上手基于它设计程序,极容易出现过度设计的问题。
- 一些扩展性要求低的场景使用面向对象会徒增编程难度,比如管理linux系统的shell脚本就不适合用面向对象去设计,面向过程反而更加适合。
- 无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法准确地预测最终结果。
- 于是我们经常看到对战类游戏,新增一个游戏人物,在对战的过程中极容易出现阴霸的技能,一刀砍死3个人,这种情况是无法准确预知的,只有对象之间交互才能准确地知道最终的结果。
【3】什么是程序
- 程序 = 数据 + 功能
- 编写程序的本质就是定义出一系列的数据,然后定义出一系列的功能来对数据进行操作。
【4】小结
- 在了解了对象的基本概念之后,理解面向对象的编程方式就相对简单很多了
- 面向对象编程就是要造出一个个的对象,把原本分散开的相关数据与功能整合到一个个的对象里
- 这么做既方便使用,也可以提高程序的解耦合程度,进而提升了程序的可扩展性(需要强调的是,软件质量属性包含很多方面,面向对象解决的仅仅只是扩展性问题)
【三】面向对象编程
【1】引入
- 按照上述的理论我们来定义一个类
- 我们构建一个学校:先有对象,后有类
(1)对象
-
对象(Object): 对象是程序中的基本单元,它包含数据和操作数据的方法。对象可以是现实世界中的实体,如人、车,也可以是更抽象的概念,如文件、日期。
-
他们都有共同的属性:学校,能力
对象1:
heart
特征:
学校=heartschool
姓名=heart
性别=男
年龄=18
能力:
读书
写作
跑步
对象2:
god
特征:
学校=heartschool
姓名=god
性别=男
年龄=20
能力:
读书
写作
跑步
对象3:
ming
特征:
学校=heartschool
姓名=ming
性别=女
年龄=20
能力:
读书
写作
跑步
(2)类
- 类(Class): 类是对象的模板或蓝图,定义了对象的属性和方法。对象是根据类创建的实例。类可以看作是一种数据类型,描述了对象的共同特征和行为。
构建的学校的类:
相似的特征:
学校=heartschool
相似的技能:
读书
写作
跑步
class 类名():
# 定义参数
# 定义函数
(3)调用类
- 在面向对象编程中,调用类通常指的是创建类的实例(对象)并使用这个实例调用类中的方法或访问类的属性。
class HeartStudent():
school = 'heartschool'
def read(self):
print(f'可以读书')
def write(self):
print(f'可以写作')
def run(self):
print(f'可以跑步')
stu1 = HeartStudent() # 创建类的实例
print(dir(stu1)) # 查看其有的方法
stu1.read() # 调用类的方法 输出:可以读书
print(stu1.school) # 访问类的属性 输出:heartschool
-
步骤:
- 创建类的实例
stu1 = HeartStudent()
- 调用类的方法
stu1.read()
- 访问类的属性
print(stu1.school)
(4)魔法方法 init
(1)__init__
初始化类
__init__
:这是一个特殊的方法,在创建类的实例时自动调用,用于对象的初始化。self
:表示类的实例对象,即将要被初始化的对象。name
,age
,gender
:这些是构造方法的参数,用于传递对象的属性值。self.name
,self.age
,self.gender
:这些是对象的属性,通过构造方法的参数初始化。这些属性将存储有关对象的信息,如姓名、年龄和性别。- 当创建一个类的实例时,构造方法会自动调用,并将提供的参数值用于初始化对象的属性。
class ATM:
user_data_dict = {}
def __init__(self):
self.username = ''
self.password = ''
# 注册
def register(self):
username = input('请输入用户名:>>>').strip()
password = input('请输入密码:>>>').strip()
ATM.user_data_dict['username'] = username
ATM.user_data_dict['password'] = password
print('注册成功!')
# 登录
def login(self):
username_input = input('请输入用户名:>>>').strip()
password_input = input('请输入密码:>>>').strip()
if username_input == ATM.user_data_dict.get('username') and password_input == ATM.user_data_dict.get('password'):
print('登录成功!')
self.username = username_input # 将实例的username属性设置为用户输入的值
self.password = password_input # 将实例的password属性设置为用户输入的值
else:
print('登录失败!')
# 示例用法:
atm = ATM()
atm.register()
atm.login()
# 输出登录成功后的用户名和密码
print('当前用户名:', atm.username)
print('当前密码:', atm.password)
【2】属性访问
(1)类属性和对象属性
- 在类中定义的名字,都是类的属性,类有两种属性:
- 数据属性和函数属性
- 可以通过
__dict__
访问属性的值,比如DreamStudent.__dict__['school']
,但Python提供了专门的属性访问语法
# 类属性: 分为两种 一种是数据属性 一种是函数属性
class Student():
# 这个 school 其实就是数据属性,对象可以任意调用
school = 'heartschool'
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
# 函数属性
def read(self):
print(f'正在读书')
stu = Student(name='heart', age=18, gender='男')
# 访问数据属性的两种方法:
print(stu.__dict__) # {'name': 'heart', 'age': 18, 'gender': '男'}
print(Student.__dict__['school']) # heartschool
print(stu.school) # heartschool
(1)访问数据属性的两种方法:
- 一种是通过
__dict__
的字典取键
stu = Student(name='heart', age=18, gender='男')
print(stu.__dict__) # {'name': 'heart', 'age': 18, 'gender': '男'}
print(Student.__dict__['school']) # heartschool
- 另一种直接通过
类名.属性
获取到属性的值
stu = Student(name='heart', age=18, gender='男')
print(stu.school) # heartschools
(2)对象的属性查找顺序:
- 首先从自己本身开始找 从
stu.__dict__
开始找 - 找不到再去实例化他的类中找
Student.__dict__
- 别的方法没有初始化过这个属性,并且这个类没有继承其他的类,找不到就报错了
- 总结: obj(开始) ---> class(类) ---> gender_class(父类) ---> 找不到直接报错
(2)访问函数属性的两种方法
# 类属性: 分为两种 一种是数据属性 一种是函数属性
class Student():
# 这个 school 其实就是数据属性,对象可以任意调用
school = 'heartschool'
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
# 函数属性
def read(self):
print(f'正在读书')
stu = Student(name='heart', age=18, gender='男')
# 类调用对象函数属性 因为有一个位置参数self,所以需要传入对象
Student.__dict__['read'](stu) # 正在读书
# 对象调用函数属性 这里的位置参数会自动将调用该方法的对象传入,所以不用传self参数
stu.read() # 正在读书
【四】类的特殊属性
类名.__name__
:类的名字(字符串)类名.__doc__
:类的文档字符串类名.__dict__
:类的字典属性类名.__module__
:类定义所在的模块类名.__class__
:实例对应的类(仅新式类中)
class Heart():
'''2024 up up!'''
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
print(f"{self.name}跑步!")
# 类名.__name__:类的名字(字符串)
print(Heart.__name__) # Heart
# 类名.__doc__:类的文档字符串
print(Heart.__doc__) # 2024 up up!
# 类名.__dict__:类的字典属性
print(
Heart.__dict__) # {'__module__': '__main__', '__doc__': '2024 up up!', '__init__': <function Heart.__init__ at 0x000001D63734A4D0>, 'run': <function Heart.run at 0x000001D63734B0A0>, '__dict__': <attribute '__dict__' of 'Heart' objects>, '__weakref__': <attribute '__weakref__' of 'Heart' objects>}
# 类名.__module__:类定义所在的模块
print(Heart.__module__) # __main__
# 类名.__class__:实例对应的类(仅新式类中)
print(Heart.__class__) # <class 'type'>