理解面向对象编程(OOP: Object Oriented Programming)
面向过程与面向对象
什么是面向过程编程?
答:按照先干什么、再干什么、最后干什么的思路。事情都自己干,流水线,程序员是打工仔视角
优点:使复杂的问题简单化、流程化
缺点:可扩展性差
什么是面向对象编程?
答:在面向对象编程中,程序员就好像是在创造一个世界,在这个世界中,程序员创造了一个个对象,用来帮自己解决问题。事情都交给对象干,程序员是老板视角。
优点:可扩展性强
缺点:复杂度略到与面向过程
对象和类的概念
对象:
- 特征(变量)与技能(函数)的结合体。
- 对象是具体的存在的事物
类:
- 一系列对象的相同特征(变量)与技能(函数。)的结合体
- 类是抽象的概念
在现实世界中:是先有具体的对象,然后将这些具有相同特征和技能的对象归结为一个类。比如:是先有人这个对象,然后把所有人归结为人类这个抽象的概念。
在程序中:是先定义一个类,然后由这个类,实例化为一个个对象。
类
在一个类中,最常定义的是变量和函数。重点:类体代码会在定义阶段就执行,然后产生一个类名称空间,将类体代码中产生的名称,丢进类名称空间中。
类里的函数里面的代码体只有调用的时候才执行,但是,类里面的__init__函数会在定义的时候就执行。
#查看类名称空间里面的名称:__dict__
class Student:
school = '社会大学'
def __init__(self, name):
self.name = name
def study(self):
print('我是学生,我会学习')
print(Student.__dict__)
'''
结果:{'__module__': '__main__', 'school': '中北大学', '__init__': <function Student.__init__ at 0x108e685f0>, 'study': <function Student.study at 0x108e684d0>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}
school、study、__init__: 类定义时产生的名称
__module__:当前文件的模块,因为是执行文件,所以是__main__
__doc__:类的文档注释
'''
print(Student.school) #结果:社会大学 #相当于:print(Student.__dict__['school'])
print(Student.study)
#结果: <function Student.study at 0x1013244d0> #相当于:print(Student.__dict__['study'])
Student.school = '北京大学' # 相当于Student.__dict__['school'] = '北京大学'
(****)类本质就是一个名称空间,里面存放变量和函数的名字,是一个存放变量和函数的容器
类的用途之一:从名称空间中找名字
类的用途之二:生对象
类中定义的变量是所有对象共享的,如果类改变了该变量,所有对象.这个变量的时候都会改变。对象是不能改变类的变量的,对象.一个类变量,并没有改变类的这个变量,本质上是在自己对象的命名空间中添加了一个属性。
class Student:
age = 18
def __init__(self):
pass
stu1 = Student()
stu2 = Student()
print(stu1.age) # 18
print(stu2.age) # 18
Student.age = 10
print(stu1.age) # 10
print(stu2.age) # 10
stu1.age = 20
print(stu1.age) # 20
print(stu2.age) # 10
print(stu1.__dict__) # {'age': 20}
对象
调用类可以产生对象。
调用类之后的返回值称为一个对象/实例。
调用类的过程称为类的实例化。
对象的本质也是一个命名空间。如果类的init没有参数,对象的命名空间为空。
例1:
class Student:
def __init__(self):
print(1)
stu = Student()
print(stu.__dict__) #结果:{}
例2:
class Student:
def __init__(self, name):
self.name = name
stu = Student('你爹')
print(stu.__dict__) #结果:{'name':'你爹'}
重点:调用类发生了什么?
1、生成一个空对象返回
2、触发类中init函数的执行,将这个空对象传给init的第一个参数。调用类括号内的参数再一次传给init第一个参数后面的参数。
init补充:1、init函数在类调用的时候就执行了。2、init函数不能有返回值。
属性查找顺序
对象.属性,.后面的叫做属性
对象.属性的时候,现在对象的命名空间里面找有没有这个属性,如果没有,就从类的名称空间里面找属性。
class Student:
school = '中北大学'
age = 18
def __init__(self, name):
self.name = name
def study(self):
print(1)
stu = Student('你爹')
print(stu.name)
print(stu.age)
'''
说明:stu的命名空间只有name, stu.__dict__ = {'name':'你爹'}, 没有age,这时候就在类的名称空间中找。
类名称空间在类定义的时候有:school, age, __init__, study等,有age,则返回18
'''
绑定方法: 当函数的逻辑中需要访问对象时,那就绑定给对象,仅需要类中数据就绑定给类
1、类中定义的变量类可以用,对象也可以用。不管谁调用,都指向同一个地址。类变量值一旦改变,所有对象调用时都跟着变。
class Student:
age = 18
def __init__(self):
pass
stu = Student()
print(id(stu.age)) # 4362244432
print(id(Student.age)) # 4362244432
Student.age = 20
stu1 = Student()
print(stu.age) # 20
print(stu1.age) # 20
2、类中定义的函数,类也可以用,类调用的时候,这个函数就是一个普通的函数。类中定义的函数是用来给对象用的。而且是绑定给对象用的。
什么叫绑定给对象?
class Student:
school = 'oldboy'
def __init__(self, name, age, sex):
self.name = name #stu1.name='小白'
self.age = age #stu1.age=18
self.sex = sex #stu1.sex='male'
def choose_course(self,x): #self=stu1
print('%s choosing course' %self.name)
stu1=Student('小白',18,'male') # 小白 choosing course
stu2=Student('小花',38,'female') # 小花 choosing course
stu3=Student('小黑',28,'male') # 小黑 choosing course
'''
如上,用类实例化了三个对象,三个对象分别调用类里面的函数。调用时,会自动把对象传给类函数的第一个参数。
也就是说,类方法分别绑定给了不同的对象,哪个对象调用,用到的就是哪个对象的名称空间。不同对象互不干扰。
'''