类和对象
对象是特征与技能的结合体,我可能有身高体重、而你也有身高体重,所以你会说你像我,但是你一定不会说你像阿猫阿狗。并且我和你其实就可以说成是一类,而你和选课系统不能说是一类,因此给出类的定义:类就是一系列对象相似的特征与技能的结合体。
在现实世界中:先有一个个具体存在的对象,然后随着人类文明的发展才了分类的概念,既然现实世界中有类这个概念,Python程序中也一定有类这个概念,但是在Python程序中:必须先定义类,然后调用类来产生对象。
现实世界中定义类和对象 定义对象 就拿未来我们的选课系统来讲,我们先总结一套现实世界中的学生对象:
对象1:
特征:
学校=’oldboy’
姓名=’耗哥’
年龄=18
性别=’male’
技能:
对象2:
特征:
学校=’oldboy’
姓名=’猪哥’
年龄=17
性别=’male’
技能:
定义类 站在未来选课系统的角度,我们还可以总结现实世界中的学生类:
程序中定义类和对象 定义类 1 2 3 4 5 6 7 class OldboyStudent (): school = 'oldboy' def choose_course (self ): print ('is choosing course' )
曾经定义函数,函数只检测语法,不执行代码,但是定义类的时候,类体代码会在类定义阶段就立刻执行,并且会产生一个类的名称空间,也就是说类的本身其实就是一个容器/名称空间,是用来存放名字的,这是类的用途之一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 print (OldboyStudent.__dict__)''' {'__module__': '__main__', 'school': 'oldboy', 'choose_course': <function OldboyStudent.choose_course at 0x10d653ae8>, '__dict__': <attribute '__dict__' of 'OldboyStudent' objects>, '__weakref__': <attribute '__weakref__' of 'OldboyStudent' objects>, '__doc__': None} ''' print (OldboyStudent.__dict__['school' ]) print (OldboyStudent.__dict__['choose_course' ]) try : OldboyStudent.__dict__['choose_course' ]() except Exception as e: print ('error:' , e) ''' error: choose_course() missing 1 required positional argument: 'self' ''' print (OldboyStudent.school) OldboyStudent.choose_course(111 ) print (OldboyStudent.choose_course) OldboyStudent.__dict__['choose_course' ] OldboyStudent.country='China' OldboyStudent.__dict__['country' ] OldboyStudent.country='CHINA' OldboyStudent.__dict__['country' ] del OldboyStudent.schoolprint (OldboyStudent.__dict__)''' {'__module__': '__main__', 'school': 'oldboy', 'choose_course': <function OldboyStudent.choose_course at 0x10d653ae8>, '__dict__': <attribute '__dict__' of 'OldboyStudent' objects>, '__weakref__': <attribute '__weakref__' of 'OldboyStudent' objects>, '__doc__': None, 'country': 'CHINA'} '''
定义对象
调用类即可产生对象,调用类的过程,又称为类的实例化,实例化的结果称为类的对象/实例
1 2 3 4 5 6 7 8 stu1=OldboyStudent() print (stu1.school) stu2=OldboyStudent() print (stu2.school) stu3=OldboyStudent() stu3.choose_course()
定制对象独有特征 类中定义的函数是类的函数属性,类可以使用,但使用的就是一个普通的函数而已,意味着需要完全遵循函数的参数规则,该传几个值就传几个
引入 1 2 3 4 5 6 7 8 9 10 class OldboyStudent : school = 'oldboy' def choose_course (self ): print ('is choosing course' ) stu1 = OldboyStudent() stu2 = OldboyStudent() stu3 = OldboyStudent()
对于上述的学生类,如果类的属性改了,则其他对象的属性也会随之改变
1 2 3 4 OldboyStudent.school = 'OLDBOY' print (stu1.school) print (stu2.school)
定制对象独有特征 1 2 3 print (stu1.__dict__) print (stu2.__dict__)
对象本质类似于类,也是一个名称空间,但是对象的名称空间存放对象独有的名字,而类中存放的是对象们共有的名字。因此我们可以直接为对象单独定制名字。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 stu1.name = 'tank' stu1.age = 18 stu1.gender = 'male' print (stu1.name, stu1.age, stu1.gender)tank 18 male try : print (stu2.name, stu2.age, stu2.gender) except Exception as e: print (e) stu2.name = 'sean' stu2.age = 19 stu2.gender = 'female' print (stu2.name, stu2.age, stu2.gender)
属性查找
首先从自身查找,没找到往类中找,类中没有则会报错。即对象的属性查找顺序为:自身–》类–》报错
类定义阶段定制属性 1 2 3 4 5 6 7 8 9 10 11 12 def init (obj, x, y, z ): obj.name = x obj.age = y obj.gender = z init(stu1, 'tank1' , 181 , 'male' ) print (stu1.name, stu1.age, stu1.gender) init(stu2, 'sean1' , 191 , 'female' ) print (stu2.name, stu2.age, stu2.gender)
使用上述方法虽然让我们定制属性更简单,但是还是太麻烦了,如果可以在实例化对象的时候自动触发定时属性,那就更方便了,因此可以使用类的init 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class OldboyStudent : school = 'oldboy' def __init__ (self, name, age, gender ): """调用类的时候自动触发""" self.name = name self.age = age self.gender = gender print ('*' * 50 ) def choose_course (self ): print ('is choosing course' ) try : stu1 = OldboyStudent() except Exception as e: print (e) stu1 = OldboyStudent('lqz' , 18 , 'male' )
通过上述现象可以发现,调用类时发生两件事:
创造一个空对象
自动触发类中init 功能的执行,将stu1以及调用类括号内的参数一同传入
属性查找
先从对象自己的名称空间找,没有则去类中找,如果类也没有则报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class OldboyStudent : school = 'oldboy' count = 0 aa = 10 def __init__ (self, x, y, z ): self.name = x self.age = y self.sex = z OldboyStudent.count += 1 self.aa = 1 def choose_course (self ): print ('is choosing course' ) print (OldboyStudent.count) stu1 = OldboyStudent('nick' , 18 , 'male' ) print (stu1.count) stu2 = OldboyStudent('sean' , 17 , 'male' ) print (stu2.count) stu3 = OldboyStudent('tank' , 19 , 'female' ) print (stu3.count) print (OldboyStudent.count) print (stu1.name)
由于上述修改的是类属性,类属性的count已经被修改为3,所以其他实例的count都为3
1 2 3 4 5 6 print (stu1.count) print (stu2.count) print (stu3.count)
由于aa是私有属性,因此stu们都会用自己私有的aa,不会用类的aa
1 2 3 4 5 print (stu1.__dict__) print (stu2.__dict__) print (stu3.__dict__)
对象的绑定方法 1 2 3 4 5 6 7 8 9 10 11 12 13 class OldboyStudent : school = 'oldboy' def __init__ (self, name, age, gender ): self.name = name self.age = age self.sex = gender def choose_course (self ): print (f'{self.name} choosing course' ) def func (self ): print ('from func' )
类名称空间中定义的数据属性和函数属性都是共享给所有对象用的
对象名称空间中定义的只有数据属性,而且是对象所独有的数据属性
类使用对象的绑定对象 1 2 3 4 5 6 stu1 = OldboyStudent('lqz' , 18 , 'male' ) stu2 = OldboyStudent('sean' , 17 , 'male' ) stu3 = OldboyStudent('tank' , 19 , 'female' ) print (stu1.name) print (stu1.school)
类中定义的函数是类的函数属性,类可以使用,但使用的就是一个普通的函数而已,意味着需要完全遵循函数的参数规则,该传几个值就传几个
1 2 3 4 5 6 7 8 9 10 11 print (OldboyStudent.choose_course) try : OldboyStudent.choose_course(123 ) except Exception as e: print (e) ''' 'int' object has no attribute 'name' '''
对象使用对象的绑定方法
类中定义的函数是共享给所有对象的,对象也可以使用,而且是绑定给对象用的,
绑定的效果:绑定给谁,就应该由谁来调用,谁来调用就会将谁当作第一个参数自动传入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 print (id (stu1.choose_course)) print (id (stu2.choose_course)) print (id (stu3.choose_course)) print (id (OldboyStudent.choose_course)) print (id (stu1.school)) print (id (stu2.school)) print (id (stu3.school)) print (id (stu1.name), id (stu2.name), id (stu3.name))stu1.choose_course() stu2.choose_course() stu3.choose_course()
补充:类中定义的函数,类确实可以使用,但其实类定义的函数大多情况下都是绑定给对象用的,所以在类中定义的函数都应该自带一个参数self
1 2 3 stu1.func() stu2.func()