Python-面向对象编程
一、如何基于面向对象的思想写程序
利用面向过程方式书写面向对象:
上一个笔记已经写到,面向对象是一种编程思想,不同语言都可以实现面向对象。在python中也专门为我们提供了面向对象的各种方法,但并不意味着一定要使用python定制的方法来写面向对象。
通过字典也可以实现面向对象思想,只要能把相关的数据和功能装到一起,就是面向对象,所以可以用面向过程的方式,表达出面向对象的思想。如下为使用字典书写面向对象:
def choose(stu_self):
print('%s:%s:%s 正在选课' % (stu_self["stu_name"], \
stu_self["stu_age"], stu_self["stu_gender"],))
stu_obj = {
"stu_name": "yang",
"stu_age": 18,
"stu_gender": "male",
"choose":choose
}
print(stu_obj["stu_name"])
stu_obj["choose"](stu_obj)
python的面向对象语法:
为了简便性,python专门有一个语法,实现面向对象
把对象中的所有数据放到两个地方存
①开辟一个内存空间盛放 所有对象相同的数据;类
②对象自己的空间中,存放 对象自己独有的数据;对象
建立好关联,这样一个对象仍能访问到属于自己的所有数据,拥有的还是完整的数据
取数据的时候,先从对象中找到,找不到再从类中找,存在着查找优先级
补充内容,各个名字的命名规范:
①变量名、函数名:纯小写+下划线
eg:student_name
②类名:驼峰体,首字母大写
eg:Student
③对于缩略词:全大写/全小写
eg:HTML
类体代码会在类定义阶段立即执行(如果你在类里写一个print会直接打印出来),然后将产生的名字空间都丢到类的名称空间
class Student:
# 相同的数据
school = "MIT"
# 相同的功能
def choose_course(self):
print("正在选课")
类体里面放的是:
各个对象相同的数据
各个对象相同的功能(方法)
只要调用类(即类加括号),就造一个对象的内存空间(为何会这样在后续的元类中会说到),将这个对象的内存空间与类的内存空间相绑定,即对象可以访问类的内存空间
造好了对象之后,就可以添加对象自己的数据
通过 obj.数据名 = value,代码如下。
class Student:
# 相同的数据
school = "MIT"
# 相同的功能
def choose_course(self):
print("正在选课")
student1 = Student()
student1.name = 'yang'
python底层也是用字典来实现面向对象的
用两个字典:
一个字典存 类
一个字典存 对象
可以通过对象名._dict__和 类名.__dict__ 查看这两个字典中的内容,代码如下
class Student:
# 相同的数据
school = "MIT"
# 相同的功能
def choose_course(self):
print("正在选课")
student1 = Student()
student1.name = 'yang'
print(Student.__dict__)
print(student1.__dict__)
------------------------------
{'__module__': '__main__', 'school': 'MIT', 'choose_course': <function Student.choose_course at 0x7fb77debd6a8>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}
{'name': 'yang'}
二、初始化方法
在上面的例子中,我们已经可以实例化(类加括号的过程就叫实例化,就像创造了一个实际的对象)出来一个对象,但是对象只拥有类里公共的属性和方法。如果要添加自己的姓名还得自己对象.属性 = value,这太麻烦了,我们希望一个对象在创建出来的时候就应该由一些自己的属性。这也更加符合实际情况,每个人的名字,身份证号码应该是不一样的。
python针对这一情况提供了初始化方法,__init__初始化方法,注意,在类中,双下划线开头和结尾的方法又叫魔术方法,他们会在某些情况下自动触发,不需要手动调用,当然,也可以手动调用。
__init__ 在当类被调用时,自动触发执行。
class Student:
'''
当定义了__init__方法后,类()就会触发这个方法,他本质也是一个函数,需要几个参数就要传几个参数.
self参数python会自动帮我们把对象传入,就是下面例子的student1
'''
def __init__(self, name, age, gender): # 通常形参与对象属性一样,方便识别
self.name = name
self.age = age
self.gender = gender
# return None 只能返回None
# 如果返回了其他的值,那么就会和类返回的对象地址相冲突(在元类中还会再提到)
student1 = Student('yang',18,'male') # self = student1,自动传
调用类,发生的3件事:
1、创建一个空对象与类相关
2、把空对象、"yang", 18, "male"一起传给__init__方法,完成对象的初始化
3、赋值符号把初始化好的对象的内存地址绑定变量名student1
三、属性查找
优先级: 对象的字典(内存空间)> 类的字典(内存空间)
1、类中定义的数据是直接共享给所有对象使用的
2、类中定义的函数是绑定给所有对象用的,绑定给谁就应该由哪个对象来调用(即不同的对象调用同一个类方法你拿到的函数内存地址是不同的。这个也算很符合我们的实际生活,比如学生有学习的功能,我们学生一学到的知识不可能被学生二拿去)
对象.绑定方法()会把对象当作第一个参数传入
类.函数()就是一个函数的用法,没有自动传参的效果
class Student:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def choose(self): # self 值得是自己本身
print("正在选课")
stu1 = Student('yang',18,'male')
stu2 = Student('ai',18,'female')
print(stu1.choose) # 对象调用叫绑定方法,bound method,会自动把stu1 作为self参数传入
print(stu2.choose) # 不同对象调用同一个类的方法,是不同的两个方法,看下列的内存地址
print(Student.choose) # 类调用就是一个函数,function
------------------------------
<bound method Student.choose of <__main__.Student object at 0x7ff823abe390>>
<bound method Student.choose of <__main__.Student object at 0x7ff823abe3c8>>
<function Student.choose at 0x7ff823aba510>
绑定方法:
类.方法,就是普通的方法
对象.类中的方法,称为绑定方法
方法的内容一样,不过地址(这个地址其实就是一个遥控器,每个对象都有一个专属于自己的地址不同的遥控器)不同
每个对象使用的相同内容的方法,但地址不同
绑定方法的特殊之处:
对象用的时候无需另外传self,默认传的都是自己
所以,类中的方法,是绑定给对象用的