面向对象:
相对于面向过程编程来讲,面向对象的扩展性比较强。但是同时带来的问题是可控性差,面向对象编程不像面向过程那样可以很精准的预测结果。面向对象程序一旦开始就由对象之间进行交互解决问题。
面向对象程序设计只是用来解决程序扩展性的。
什么是对象:
举一个例子:每个人都有自己特征和技能,那么每个人就是一个对象。对象就是特征与技能的结合体。
什么是类:
每个人都有自己独有特征也有和别人同样的技能或者特征。例如:基本每个人都会吃饭,都会睡觉,都会说话或者某两个人眼睛都挺大。我们可以把这些共同的技能或者特征归为一类。所以类就是一系列对象的共同特征与技能的结合体。
先有对象还是先有类:
在现实生活中,我们都知道只有一个新生事物诞生的时候,我们人类才能根据这个新生事物的特征去给它划分类。所以在现实生活中是先有对象之后才有的类。然而在程序中不是这样的,在Python中我们使用类来生成一个个对象。Python的类包含了这些对象共同的特征或者技能。
创建类:
class 不同于 def,如果不调用def定义的函数,那么Python只会去定义,我们原来讲过,函数分为定义阶段和调用阶段,定义阶段只检查语法是否正确。而class在定义的时候就会把class内部的指令都执行一遍。
#定义一个中国人 类class Chinese: #class 类名: #一般类名都会首字母大写 country = ‘china‘ #共同的国家 def use(self): #共同的技能 print(‘use chopsticks‘) #我们都会使用筷子 print(‘from chinese‘) #打印一段内容 执行结果: D:\Python\Python36-32\python.exe E:/Python/Test/t.py from chinese #发现class 在定义的时候会执行一遍内部的指令,不仅仅像定义函数那样 Process finished with exit code 0
建立对象:
实例化的概念:从抽象的类生成对象的这一过程称为实例化。
class Chinese: country = ‘china‘ def use(self): print(‘use chopsticks‘) #假装生成了两个中国人(生成了两个对象p1,p2) p1 = Chinese() #加括号运行的意思,这就是实例化。 p2 = Chinese()
上面的建立的两个中国人,他们的特征和技能都一样。但是每个人的还有不同的特征或者技能,例如:名字,年龄,工作等等,这时候我么可以通过 __init__来给它填上去。
注:__init__函数不能有返回值,或者说返回值必须为None。
class Chinese: country = ‘china‘ def __init__(self,name,age,job): #定义一个init函数,self会自己把对象的名字拿过来传给init函数的第一个参数(可自定义self的名字,但是不推荐),所以我们在定义三个形参,name,age,job。 self.name = name #这个翻译过来就是 对象的名字 = 输入的名字 #前面那个name跟后面那个name没有关系的,下面同这个一样的意思 self.age = age self.job = job def use(self): print(‘use chopsticks‘) #这时候我们就需要在原本的括号内加点东西了,为什么这里是三个参数,而不是四个参数(位置参数必须跟形参一一对应),上面说了self会自动找到对象的名字传给init的第一个参数,所以我们只需传后三个就行。 p1 = Chinese(‘ZhangSan‘,28,‘teacher‘) p2 = Chinese(‘LiSi‘,18,‘student‘) print(p1.__dict__) #使用 objectname.__dic__ 来查看对象的属性信息,字典形式key为属性名,value为属性值。 print(p2.__dict__) 执行结果: D:\Python\Python36-32\python.exe E:/Python/Test/t.py {‘name‘: ‘ZhangSan‘, ‘age‘: 28, ‘job‘: ‘teacher‘} #这里我们能看见上面定义__init__时,里面的self.name ... 都是属性名。 {‘name‘: ‘LiSi‘, ‘age‘: 18, ‘job‘: ‘student‘} Process finished with exit code 0
查看类的属性:
dir(类名):查出的是一个名字列表 类名.__dict__:查出的是一个字典,key为属性名,value为属性值 二:特殊的类属性 类名.__name__# 类的名字(字符串) 类名.__doc__# 类的文档字符串 类名.__base__# 类的第一个父类(在讲继承时会讲) 类名.__bases__# 类所有父类构成的元组(在讲继承时会讲) 类名.__dict__# 类的字典属性 类名.__module__# 类定义所在的模块 类名.__class__# 实例对应的类(仅新式类中)
类/对象的修改:
class Chinese: country = ‘china‘ def __init__(self,name,age,job): self.name = name self.age = age self.job = job def use(self): print(‘use chopsticks‘) return ‘a‘ p1 = Chinese(‘ZhangSan‘,28,‘teacher‘) p2 = Chinese(‘LiSi‘,18,‘student‘) Chinese.name = ‘abc‘ #向类添加属性 p1.sex = ‘man‘ #向对象添加属性 p2.sex = ‘woman‘ print(p1.__dict__) #查看对象的属性(没有公共属性)返回的是字典形式 key是属性名,value是属性值 print(p2.__dict__) print(Chinese.__dict__) #查看的是类的属性 del p1.sex #删除对象的属性 del Chinese.name #删除类的属性 print(p1.__dict__) print(Chinese.__dict__) 执行结果: #红色结果为删除某一属性之后的属性信息 D:\Python\Python36-32\python.exe E:/Python/Test/t.py {‘name‘: ‘ZhangSan‘, ‘age‘: 28, ‘job‘: ‘teacher‘, ‘sex‘: ‘man‘} {‘name‘: ‘LiSi‘, ‘age‘: 18, ‘job‘: ‘student‘, ‘sex‘: ‘woman‘} {‘__module__‘: ‘__main__‘, ‘country‘: ‘china‘, ‘__init__‘: <function Chinese.__init__ at 0x02A938A0>, ‘use‘: <function Chinese.use at 0x02A937C8>, ‘__dict__‘: <attribute ‘__dict__‘ of ‘Chinese‘ objects>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘Chinese‘ objects>, ‘__doc__‘: None, ‘name‘: ‘abc‘} {‘name‘: ‘ZhangSan‘, ‘age‘: 28, ‘job‘: ‘teacher‘} {‘__module__‘: ‘__main__‘, ‘country‘: ‘china‘, ‘__init__‘: <function Chinese.__init__ at 0x02A938A0>, ‘use‘: <function Chinese.use at 0x02A937C8>, ‘__dict__‘: <attribute ‘__dict__‘ of ‘Chinese‘ objects>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘Chinese‘ objects>, ‘__doc__‘: None}
对象去修改类中的不可变数据和可变数据对比:
class Chinese: list_1 = [] count = 0 country = ‘china‘ def __init__(self,name,age,job): self.name = name self.age = age self.job = job self.list_1.append(name) #每实例化一次,对象就会把自己的name信息加入列表 self.count += 1 #每实例化一次,对象就会把count 加 1 def use(self): print(‘use chopsticks‘) return ‘a‘ p1 = Chinese(‘ZhangSan‘,28,‘teacher‘) p2 = Chinese(‘LiSi‘,18,‘student‘) p3 = Chinese(‘Huang‘,20,‘student‘) print(p1.list_1,p1.__dict__) #查看对象的list_1 信息和 对象的属性信息 print(p2.list_1,p1.__dict__) print(p3.list_1,p3.__dict__) print(Chinese.list_1) #查看类的list_1信息
print(id(p1.list_1),‘P1 list_1‘) #查看 对象的list_1内存地址print(id(Chinese.list_1),‘Chinese list_1‘) #查看 类的list_1内存地址
print(id(p1.count),p1.count) print(id(p2.count),p2.count) print(id(p3.count),p3.count) print(id(Chinese.count),Chinese.count) #根据执行结果发现,发现每个对象的属性中没有list_1的属性,但是多出来一个count属性。我们查看了 类的list_1属性跟count属性发现了不同。 执行结果: D:\Python\Python36-32\python.exe E:/Python/Test/t.py [‘ZhangSan‘, ‘LiSi‘, ‘Huang‘] {‘name‘: ‘ZhangSan‘, ‘age‘: 28, ‘job‘: ‘teacher‘, ‘count‘: 1} [‘ZhangSan‘, ‘LiSi‘, ‘Huang‘] {‘name‘: ‘ZhangSan‘, ‘age‘: 28, ‘job‘: ‘teacher‘, ‘count‘: 1} [‘ZhangSan‘, ‘LiSi‘, ‘Huang‘] {‘name‘: ‘Huang‘, ‘age‘: 20, ‘job‘: ‘student‘, ‘count‘: 1} [‘ZhangSan‘, ‘LiSi‘, ‘Huang‘] # <------:这里发现类的list_1属性值跟上面对象中的一致并且内存地址也一致。所以对于可变数据,在类中是可以被修改的。51806496 P1 list_151806496 Chinese list_1 499930864 1 #P1 499930864 1 #P2 499930864 1 #P3 499930848 0 #类的 <----:这里发现内存地址不同,并且count数值也不同。所以对于不可变的数据,对象又开辟了新的内存空间进行引用,是建立在对象中的,而不是类中。 Process finished with exit code 0
类修改自己的可变数据和不可变数据对比:
通过下面的测试,发现类自己修改自己的数据的时候在实例化的时候不会对 对象造成任何影响,都是通过类去调用。
class Chinese: list_1 = [] count = 0 country = ‘china‘ def __init__(self,name,age,job): self.name = name self.age = age self.job = job Chinese.list_1.append(name) #每次实例化 类就会把实例化的对象的name加入列表 Chinese.count += 1 #每次实例化 类都会把count 加 1 def use(self): print(‘use chopsticks‘) return ‘a‘ p1 = Chinese(‘ZhangSan‘,28,‘teacher‘) p2 = Chinese(‘LiSi‘,18,‘student‘) p3 = Chinese(‘Huang‘,20,‘student‘) print(p1.list_1,p1.__dict__) print(p2.list_1,p1.__dict__) print(p3.list_1,p3.__dict__) print(Chinese.list_1) print(id(p1.list_1),‘P1 list_1‘) print(id(Chinese.list_1),‘Chinese list_1‘) print(id(p1.count),p1.count) print(id(p2.count),p2.count) print(id(p3.count),p3.count) print(id(Chinese.count),Chinese.count) 执行结果: D:\Python\Python36-32\python.exe E:/Python/Test/t.py [‘ZhangSan‘, ‘LiSi‘, ‘Huang‘] {‘name‘: ‘ZhangSan‘, ‘age‘: 28, ‘job‘: ‘teacher‘} [‘ZhangSan‘, ‘LiSi‘, ‘Huang‘] {‘name‘: ‘ZhangSan‘, ‘age‘: 28, ‘job‘: ‘teacher‘} [‘ZhangSan‘, ‘LiSi‘, ‘Huang‘] {‘name‘: ‘Huang‘, ‘age‘: 20, ‘job‘: ‘student‘} [‘ZhangSan‘, ‘LiSi‘, ‘Huang‘] 45973792 P1 list_1 45973792 Chinese list_1 493180688 3 493180688 3 493180688 3 493180688 3 Process finished with exit code 0