一 对象的概念
面向对象“的核心是“对象”二字,而对象的精髓在于“整合“
所有的程序都是由”数据”与“功能“组成,因而编写程序的本质就是定义出一系列的数据,然后定义出一系列的功能来对数据进行操作。在学习”对象“之前,程序中的数据与功能是分离开的,
在学习了“对象”之后,我们就有了一个容器,该容器可以盛放数据与功能,所以我们可以说:对象是把数据与功能整合到一起的产物,或者说”对象“就是一个盛放数据与功能的容器/箱子/盒子。
面向对象编程就是要造出一个个的对象,把原本分散开的相关数据与功能整合到一个个的对象里
优点:方便使用,提高程序的解耦合程度,提升了程序的可扩展性
二 类
在学习面向对象编程之前我们还要先知道类的概念
2.1 什么是类
类即类别/种类,是面向对象分析和设计的基石,如果说对象是用来存放数据与功能的容器,那么类则是用来存放多个对象相同的数据与功能的容器。
如果多个对象有相似的数据与功能,那么该多个对象就属于同一种类。
三 面向对象编程
3.1 类的定义
面向对象的基本思路就是把程序中要用到的、相关联的数据与功能整合到对象里,然后再去使用,我们举个例子
# 学生1: 数据: 学校=清华大学 姓名=李建刚 性别=男 年龄=28 功能: 选课 # 学生2: 数据: 学校=清华大学 姓名=王大力 性别=女 年龄=18 功能: 选课 # 学生3: 数据: 学校=清华大学 姓名=牛嗷嗷 性别=男 年龄=38 功能: 选课
首先我们可以定义一个类
class Student: school = '清华' # 2、功能的定义 def tell_stu_info(stu_obj): print('学生信息:名字:%s 年龄:%s 性别:%s' %( self.stu_name, self.stu_age, self.stu_gender )) def choose(self): print('%s is choosing a course' %self.name)
类体中最常见的是变量与函数的定义,但是类体其实是可以包含任意其他代码的
注意:类体代码是在类定义阶段就会立即执行,会产生类的名称空间
可以打印Student.__dict__来查看类这个容器内盛放的东西
3.2 类的调用再产生对象
stu1_obj=Student() #没调用一次类就会产生一个学生对象 stu2_obj=Student() stu3_obj=Student()
如此stu1_obj、stu2_obj、stu3_obj全都一样了(只有类中共有的内容,而没有各自独有的数据),想在调用的过程中就为三位学生定制各自独有的数据:姓名,性别,年龄,需要我们在类内部新增一个__init__方法,如下
class Student: school = '清华' def __init__(obj,x,y,z): obj.stu_name=x obj.stu_age=y obj.stu_gender=z # return None # 2、功能的定义 def tell_stu_info(stu_obj): print('学生信息:名字:%s 年龄:%s 性别:%s' %( self.stu_name, self.stu_age, self.stu_gender )) def choose(self): print('%s is choosing a course' %self.name)
关于_init_方法
1、会在调用类时自动触发执行,用来为对象初始化自己独有的数据
2、__init__内应该存放是为对象初始化属性的功能,但是是可以存放任意其他代码,想要在类调用时就立刻执行的代码都可以放到该方法内
3、__init__方法必须返回None
stu1_obj=Student('egon',18,'male') stu2_obj=Student('lili',19,'female') print(stu1_obj.__dict__) print(stu2_obj.__dict__) # {'stu_name': 'egon', 'stu_age': 18, 'stu_gender': 'male'} # {'stu_name': 'lili', 'stu_age': 19, 'stu_gender': 'female'}
调用类的过程发生了三件事
1、先产生一个空对象
2、python会自动调用类中的__init__方法然将空对象已经调用类时括号内传入的参数一同传给__init__方法
3、返回初始完的对象
单拿stu1_obj的产生过程来分析,调用类会先产生一个空对象stu1_obj,然后将stu1_obj连同调用类时括号内的参数一起传给Student.__init__(stu1_obj,’egon’,18,;male')
3.3 属性的访问
在类中定义的名字,都是类的属性,细说的话,类有两种属性:数据属性和函数属性。
可以通过__dict__访问属性的值,比如Student.__dict__[‘school’],但Python提供了专门的属性访问语法
Student.school # 访问数据属性,等同于Student.__dict__['school'] Student.choose # 访问函数属性,等同于Student.__dict__['choose']
同理操作对象的属性也是一样的,除了查看属性外我们还可以修改属性
stu1_obj=Student('egon',18,'male') print(stu1_obj.__dict__) print(stu1_obj.stu_name)#查看属性 stu1_obj.course='python' #添加属性 stu1_obj.stu_age = 20 #修改属性 del stu1_obj.stu_gender #删除属性 print(stu1_obj.__dict__)
属性的访问顺序和查找方法:
对象的名称空间里只存放着对象独有的属性,而对象们相似的属性是存放于类中的。对象在访问属性时,会优先从对象本身的__dict__中查找,未找到,则去类的__dict__中查找
1、类的数据属性是共享给所有对象用的,大家访问的地址都一样
print(id(Student.school))# 2493299721864 print(id(stu1_obj.school))# 2493299721864 print(id(stu2_obj.school))# 2493299721864
因此当类中的变量的值改变时对象中的也会跟着改变
Student.school='OLDBOY' print(stu1_obj.school)#OLDBOY
2、类中定义的函数主要是给对象使用的,而且是绑定给对象的,虽然所有对象指向的都是相同的功能,但是绑定到不同的对象就是不同的绑定方法,内存地址各不相同
print(id(Student.choose)) # 4335426280 print(id(stu1_obj.choose)) # 4300433608 print(id(stu2_obj.choose)) # 4300433608
类调用自己的函数属性必须严格按照函数的用法来
Student.tell_stu_info(stu1_obj)
Student.tell_stu_info(stu2_obj)
绑定方法的特殊之处在于:谁来调用绑定方法就会将谁当做第一个参数自动传入
stu1_obj.tell_stu_info() #Student.tell_stu_info(stu1_obj) stu2_obj.tell_stu_info() #Student.tell_stu_info(stu2_obj)
强调一点:因为python底层代码规定,在类中定义函数时必须要在括号内定义一个变量来接收传入的对象
四 总结
Python中一切皆为对象,且Python3中类与类型是一个概念,因而绑定方法我们早就接触过
#类型list就是类 >>> list <class 'list'> #实例化的到3个对象l1,l2,l3 >>> l1=list([1,2,3]) >>> l2=list(['a','b','c']) >>> l3=list(['x','y']) #三个对象都有绑定方法append,是相同的功能,但内存地址不同 >>> l1.append <built-in method append of list object at 0x10b482b48> >>> l2.append <built-in method append of list object at 0x10b482b88> >>> l3.append <built-in method append of list object at 0x10b482bc8> #操作绑定方法l1.append(4),就是在往l1添加4,绝对不会将4添加到l2或l3 >>> l1.append(4) #等同于list.append(l1,4) >>> l1 [1,2,3,4] >>> l2 ['a','b','c'] >>> l3 ['x','y']
在上述介绍类与对象的使用过程中,我们更多的是站在底层原理的角度去介绍类与对象之间的关联关系,如果只是站在使用的角度,我们无需考虑语法“对象.属性"中”属性“到底源自于哪里,只需要知道是通过对象获取到的就可以了,所以说,对象是一个高度整合的产物,有了对象,我们只需要使用”对象.xxx“的语法就可以得到跟这个对象相关的所有数据与功能,十分方便且解耦合程度极高。