python面向对象(基础)
一 面向对象介绍
面向过程:
核心是:“过程”二字
过程的终极奥义就是将程序流程化
过程是“流水化”,用来分步骤解决问题的
面向对象:
核心是“对象”二字
对象的终极奥义就是将程序“整合”
对象是“容器”,用来盛放数据与功能的
类也是“容器”,该容器用来存放同类对象共有的数据与功能
python这门语言到底提供了什么语法来允许我们将数据与功能很好地整合到一起
程序=数据+功能
学生的容器=学生的数据+学生的功能
课程的容器=课程的数据+课程的功能
1、编程范式/思想 面向过程 介绍: 核心是“过程”二字 过程就是“流水化" 过程终极奥义是将程序流程化 优点: 1、将程序流程化,进而程序的设计会变得简单化 缺点: 1、可扩展性差 面向对象 介绍: 核心是“对象”二字 对象就是“容器",用来盛放数据与功能 对象终极奥义是将程序进行高度整合 优点: 1、提升程序的解耦合程度,进而增强程序的可扩展性 缺点: 1、设计复杂 2、面向对象编程 一:现实生活中: 1)先找出现实生活中的对象 2)然后总结归纳出现实生活中的类 二:程序中: 1)先定义程序中的类 2)后调用类产生程序中的对象(调用类的过程又称之为实例化)
二 什么是面向对象的程序设计及为什么要有它
面向过程的程序设计:核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么......面向过程的设计就好比精心设计好一条流水线,是一种机械式的思维方式。
优点是:复杂度的问题流程化,进而简单化(一个复杂的问题,分成一个个小的步骤去实现,实现小的步骤将会非常简单)
缺点是:一套流水线或者流程就是用来解决一个问题,生产汽水的流水线无法生产汽车,即便是能,也得是大改,改一个组件,牵一发而动全身。
应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。
面向对象的程序设计:核心是对象二字,(要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来。面向对象的程序设计好比如来设计西游记,如来要解决的问题是把经书传给东土大唐,如来想了想解决这个问题需要四个人:唐僧,沙和尚,猪八戒,孙悟空,每个人都有各自的特征和技能(这就是对象的概念,特征和技能分别对应对象的数据属性和方法属性),然而这并不好玩,于是如来又安排了一群妖魔鬼怪,为了防止师徒四人在取经路上被搞死,又安排了一群神仙保驾护航,这些都是对象。然后取经开始,师徒四人与妖魔鬼怪神仙交互着直到最后取得真经。如来根本不会管师徒四人按照什么流程去取),对象是特征与技能的结合体,基于面向对象设计程序就好比在创造一个世界,你就是这个世界的上帝,存在的皆为对象,不存在的也可以创造出来,与面向过程机械式的思维方式形成鲜明对比,面向对象更加注重对现实世界的模拟,是一种“上帝式”的思维方式。
优点是:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
缺点:
1. 编程的复杂度远高于面向过程,不了解面向对象而立即上手基于它设计程序,极容易出现过度设计的问题。一些扩展性要求低的场景使用面向对象会徒增编程难度,比如管理linux系统的shell脚本就不适合用面向对象去设计,面向过程反而更加适合。
2. 无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法准确地预测最终结果。于是我们经常看到对战类游戏,新增一个游戏人物,在对战的过程中极容易出现阴霸的技能,一刀砍死3个人,这种情况是无法准确预知的,只有对象之间交互才能准确地知道最终的结果。
应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方
面向对象的程序设计并不是全部。对于一个软件质量来说,面向对象的程序设计只是用来解决扩展性。
三 实现面向对象编程
# 一、先定义类 # 类是对象相似数据与功能的集合体 # 所以类中最常见的是变量与函数的定义,但是类体其实是可以包含任意其他代码的 # 注意:类体代码是在类定义阶段就会立即执行,会产生类的名称空间 # 类的命名应该使用“驼峰体” class Student: # 1、变量的定义 school = '清华大学' # 数据 # 2、功能的定义 def tell_stu_info(stu_obj): print('学生信息:名字:{} 年龄:{} 性别:{}'.format( stu_obj['stu_name'], stu_obj['stu_age'], stu_obj['stu_gender'], )) def set_info(stu_obj, x, y, z): stu_obj['stu_name'] = x stu_obj['stu_age'] = y stu_obj['stu_gender'] = z # print('---->') # 类的定义阶段,就会立即执行 print(Student.__dict__) print(Student.__dict__['school']) # 属性访问的语法 # 1、访问数据属性 print(Student.school) # 等同于Student.__dict__['school'] # 2、访问函数属性 print(Student.set_info) # 等同于Student.__dict__['set_info'] # 二、再调用类产生对象 # 产生对象名称空间,并与类名称空间产生关联 Stu1_obj = Student() Stu2_obj = Student() Stu3_obj = Student() print(Stu1_obj.__dict__) print(Stu2_obj.__dict__) print(Stu2_obj.__dict__) # 对象定制自己独有的属性 # 问题1:代码重复 # 问题2:属性的查找顺序 Stu1_obj.stu_name = 'lq' # Stu1_obj.__dict__['stu_name']='lq' Stu1_obj.stu_age = 18 # Stu1_obj.__dict__['stu_age']=18 Stu1_obj.stu_gender = 'female' # Stu1_obj.__dict__['stu_gender']='female' print(Stu1_obj.__dict__) Stu2_obj.stu_name = 'zd' Stu2_obj.stu_age = 19 Stu2_obj.stu_gender = 'male' print(Stu2_obj.__dict__) Stu3_obj.stu_name = 'xiaobao' Stu3_obj.stu_age = 5 Stu3_obj.stu_gender = 'female' print(Stu3_obj.__dict__) # 解决问题: # 解决方案一: def init(obj, x, y, z): obj.stu_name = x obj.stu_age = y obj.stu_gender = z init(Stu1_obj, 'lq', 18, 'male') print(Stu1_obj.__dict__) # 解决方案二: # 一:先定义类 class Student: # 类的命名应该使用“驼峰体” # 1、变量的定义 school = '清华大学' # 数据 # 空对象,'egon',18,'male' def __init__(obj, x, y, z): obj.stu_name = x # 空对象.stu_name='egon' obj.stu_age = y # 空对象.stu_age=18 obj.stu_gender = z # 空对象.stu_gender='male' # 2、功能的定义 def tell_stu_info(stu_obj): print('学生信息:名字:{} 年龄:{} 性别:{}'.format( stu_obj['stu_name'], stu_obj['stu_age'], stu_obj['stu_gender'], )) def set_info(stu_obj, x, y, z): stu_obj['stu_name'] = x stu_obj['stu_age'] = y stu_obj['stu_gender'] = z # 二:再调用类产生对象 # 调用类的过程又称之为实例化,发生了三件事 # 1、先产生一个空对象 # 2、python会自动调用类中的__init__方法,然后将空对象已经调用类是括号内传入的参数一同传给__init__方法 # 3、返回初始完的对象 Stu1_obj = Student('lq', 19, 'male') Stu2_obj = Student('zd', 19, 'male') Stu3_obj = Student('xiaobao', 18, 'male') print(Stu1_obj.__dict__) print(Stu2_obj.__dict__) print(Stu3_obj.__dict__) # 总结__init__方法 # 1、会在调用类时自动触发执行,用来为对象初始化自己独有的数据 # 2、__init__内应该存放是为对象初始化属性的功能,但是可以存放任意其他代码,想要在 # 类调用时就立刻执行的代码都可以放到该方法内 # 3、__init__方法必须返回None
四 属性查找
先查找对象名称空间中查找数据属性,找不到,再到类的名称空间里找
class Student: # 类的命名应该使用“驼峰体” # 1、变量的定义 school = '清华大学' # 数据 count = 0 def __init__(self, x, y, z): Student.count += 1 # 实例化计数 self.stu_name = x # 空对象.stu_name='egon' self.stu_age = y # 空对象.stu_age=18 self.stu_gender = z # 空对象.stu_gender='male' # 2、功能的定义 def tell_stu_info(obj): print('学生信息:名字:{} 年龄:{} 性别:{}'.format( obj.stu_name, obj.stu_age, obj.stu_gender, )) def set_info(obj, x, y, z): obj.stu_name = x obj.stu_age = y obj.stu_gender = z Stu1_obj = Student('lq', 19, 'male') Stu2_obj = Student('zd', 19, 'male') Stu3_obj = Student('xiaobao', 18, 'male') # 类中存放的是对象共有的数据与功能 # 一、类可以访问: # 1、类的数据属性 print(Student.school) # 2、类的函数属性 print(Student.set_info) print(Student.tell_stu_info) # 二、但其实类中的东西是给对象用的 # 1、类的数据属性是共享给所有对象用的,大家访问的地址都一样 print(Student.school) print(Stu1_obj.school) print(Stu2_obj.school) print(Stu3_obj.school) Stu1_obj.school = '上海中学' # 对象Stu1,自己名称空间里建school数据属性 print(Stu1_obj.school) # 2、类中定义的函数主要是给对象使用的,而且是绑定给对象的,虽然所有对象指向的都是相同的功能, # 但是绑定到不同的对象就是不同的绑定方法,内存地址各不相同 # 类调用自己的函数属性必须严格按照函数的用法来 Student.tell_stu_info(Stu1_obj) Student.tell_stu_info(Stu2_obj) Student.tell_stu_info(Stu3_obj) Student.set_info(Stu1_obj, 'LQ', 33, 'MALL') Student.set_info(Stu2_obj, 'ZD', 33, 'MALL') Student.set_info(Stu3_obj, 'XIAOBAO', 6, 'MALL') ''' 学生信息:名字:lq 年龄:19 性别:male 学生信息:名字:zd 年龄:19 性别:male 学生信息:名字:xiaobao 年龄:18 性别:male 学生信息:名字:LQ 年龄:33 性别:MALL 学生信息:名字:ZD 年龄:33 性别:MALL 学生信息:名字:XIAOBAO 年龄:6 性别:MALL ''' # 绑定方法的特殊之处在于:谁来调用绑定方法就会将谁当做第一个参数自动传入, # 所以类中定义的函数第一个参数默认self,类中函数方法(无参函数,也需要有self的原因) print(Student.tell_stu_info) print(Stu1_obj.tell_stu_info) # 绑定方法, print(Stu2_obj.tell_stu_info) print(Stu3_obj.tell_stu_info) ''' <function Student.tell_stu_info at 0x000001D76D422550> <bound method Student.tell_stu_info of <__main__.Student object at 0x000001D76D3C30A0>> <bound method Student.tell_stu_info of <__main__.Student object at 0x000001D76D3C3310>> <bound method Student.tell_stu_info of <__main__.Student object at 0x000001D76D3C9550>> ''' # 直接对象来调用函数方法,对象直接当第一个参数自动传入,不用再像类调用函数方法时,传对象参数 # 比从类中调用,更简单,并且语意明确 Stu1_obj.tell_stu_info() Stu2_obj.tell_stu_info() Stu3_obj.tell_stu_info() Stu1_obj.set_info('LQ', 33, 'MALL') Stu2_obj.set_info('ZD', 33, 'MALL') Stu3_obj.set_info('XIAOBAO', 6, 'MALL') ''' 学生信息:名字:lq 年龄:19 性别:male 学生信息:名字:zd 年龄:19 性别:male 学生信息:名字:xiaobao 年龄:18 性别:male 学生信息:名字:LQ 年龄:33 性别:MALL 学生信息:名字:ZD 年龄:33 性别:MALL 学生信息:名字:XIAOBAO 年龄:6 性别:MALL ''' # Python中一切皆为对象,且Python3中类与类型是一个概念 # 在上述介绍类与对象的使用过程中,我们更多的是站在底层原理的角度去介绍类与对象之间的关联关系, # 如果只是站在使用的角度,我们无需考虑语法“对象.属性 # "中”属性“到底源自于哪里,只需要知道是通过对象获取到的就可以了,所以说,对象是一个高度整合的产物, # 有了对象,我们只需要使用“对象.xxx”的语法就可以得到跟这个对象相关的所有数据与功能,十分方便且解耦合程度极高。
五 练习
对象可以当参数传递
# 整合---》解耦合---》扩展性增强 # 学校 class School: school_name = 'OLDBOY' def __init__(self, nickname, addr): self.nickname = nickname self.addr = addr self.classes = [] def related_class(self, grade_obj): # 传对象,在.'属性' self.classes.append(grade_obj) # 列表存储的班级对象 # self.classes.append(班级名称) def class_tell_info(self): print(self.nickname) for grade_obj in self.classes: grade_obj.tell_course() # 1、学校 # 1)创建校区 school_obj1 = School('上海校区', '上海') school_obj2 = School('北京校区', '北京') # 2)为学校开设班级 # school_obj1.related_class('脱产14期') # school_obj1.related_class('脱产15期') # school_obj2.related_class('脱产29期') # 3)查看每个校区开设的班级 # school_obj1.class_tell_info() # 班级 class Grade: def __init__(self, name): self.name = name self.course = None def related_course(self, course_obj): self.course = course_obj # 变量名有,就是修改,没有,就是新建 def tell_course(self): print('班级名:{}'.format(self.name),end=' ') self.course.tell_info() # 2、班级 # 1)创建班级 grade_obj1 = Grade('脱产14期') grade_obj2 = Grade('脱产15期') grade_obj3 = Grade('脱产29期') # 2)为班级关联一个课程 # grade_obj1.related_course('python全栈开发') # grade_obj2.related_course('linux运维') # grade_obj3.related_course('python全栈开发') # 3)查看班级开设的课程信息 # grade_obj1.tell_course() # grade_obj2.tell_course() # grade_obj3.tell_course() # 4) 为学校开设办班级 # 上海校区开了:脱产14期,上海校区开了脱产15期 school_obj1.related_class(grade_obj1) school_obj1.related_class(grade_obj2) # print(school_obj1.classes) # 课程列表里,是对象 # 北京校区开了:脱产29期 school_obj2.related_class(grade_obj3) # school_obj1.class_tell_info() # 课程 class Course: def __init__(self, name, period, price): self.name = name self.period = period self.price = price def tell_info(self): print('<课程名:{},课程周期:{},课程价格{}>'.format(self.name, self.period, self.price)) # 1)创建课程 course_obj1 = Course('python全栈开发', '6个月', 20000) course_obj2 = Course('linux运维', '5个月', 18000) # 2) 查看课程的详细信息 # course_obj1.tell_info() # course_obj2.tell_info() # 3) 为班级关联课程对象 grade_obj1.related_course(course_obj1) grade_obj2.related_course(course_obj2) grade_obj3.related_course(course_obj1) # grade_obj1.tell_course() # grade_obj2.tell_course() # grade_obj3.tell_course() school_obj1.class_tell_info() school_obj2.class_tell_info() class Student: pass