一切皆对象,类也是对象,类来自于元类type,如果一个类没有声明自己的元类,默认它就是元类。
即类是元类的实例,通过type(类)会显示type,而实例来自于类。
类有两个属性,数据属性和函数属性,下面是一个创建类和实例化对象的例子
class animal: \'This is class for animal\' #类的说明 type=\'animal\' def __init__(self,name,sex,leg): self.name = name self.sex = sex self.leg = leg def eat(self,food): print(\'%s likes to eat %s\'%(self.name,food)) def play(self): print(\'%s is playing\'%self.name) print(animal.__name__)#打印类的名称 print(animal.__doc__) #打印类的说明,__doc__属性不能继承给子类 print(animal.__dict__) #打印类的属性字典 cat=animal(\'cat\',\'male\',4) print(cat.__dict__) #打印类的属性字典 print(cat.type) cat.eat(\'mouse\') cat.play() #执行结果 # animal # This is class for animal # {\'__module__\': \'__main__\', \'__doc__\': \'This is class for animal\', \'haveTeeth\': True, \'__init__\': <function animal.__init__ at 0x00000000021AA598>, \'eat\': <function animal.eat at 0x00000000021AA620>, \'__dict__\': <attribute \'__dict__\' of \'animal\' objects>, \'__weakref__\': <attribute \'__weakref__\' of \'animal\' objects>} # {\'name\': \'cat\', \'sex\': \'male\', \'leg\': 4} # cat likes to eat mouse # animal
在class animal:范围下面的都是对animal类的定义,其中def __init__()是定义animal类的数据属性,__init__()不应该有返回值,否则会报错,其他函数则是animal类的函数属性,可以看到类下面的函数的第一个参数都是self。
当执行cat=animal(\'cat\',\'male\',4),触发animal类的__init__()函数生成一个cat实例。
__dict__表示属性字典,以字典形式存放,通过打印animal.__dict__和cat.__dict__可以发现,类有数据属性和函数属性,而实例只有数据属性没有函数属性,但是实例可以继承和调用对象的函数属性。
实例调用类的函数时,会自动将实例本身作为第一个参数传给函数,但是类自己调用函数时不会自动将实例本身作为参数传入,例如要通过类调用play()函数,则animal.play(cat)。
类的属性字典是共用的,而实例的属性字典是私有的。
类属性的查看、增加、修改和删除
#查看类的数据属性 print(animal.type) #修改类的数据属性 animal.type=\'Animal\' print(animal.type) #增加类的数据属性 animal.haveteeth=True print(cat.haveteeth) #删除类的数据属性 del animal.haveteeth #增加类的函数属性,修改类似 def play_bal(self,ball): print(\'The %s is playing %s\'%(self.name,ball)) animal.play_ball=play_bal cat.play_ball(\'tennis\')
实例属性的增加
#增加实例的数据属性,cat.__dict__[\'key\']=\'value\'也可以增加数据属性但不建议使用 cat.living=\'land\' print(cat.__dict__) #{\'name\': \'cat\', \'sex\': \'male\', \'leg\': 4, \'living\': \'land\'} #删除实例的数据属性 del cat.living print(cat.__dict__) #{\'name\': \'cat\', \'sex\': \'male\', \'leg\': 4} #修改实例的数据属性 cat.sex=\'female\' print(cat.sex) #female #增加实例的函数属性 def test(): print(\'hello\') cat.test=test cat.test() #hello
对于实例增加的函数属性,实例在调用时不会自动将自身作为参数传入。
需要注意的是:
如果在类前面定义了与类的数据属性同名的全局变量,那么只要不通过类或者实例+.调用这个变量,这个变量就是指类前面定义的全局变量
如果实例增加了与类的数据属性同名的属性,相当于给实例增加了这个属性,对类的属性没有影响。
type=\'mouse\' class animal: type=\'animal\' l=[\'a\',\'b\'] def __init__(self,name): self.name = name print(type) #此处的type是指全局变量,而不是类内部的数据属性变量 cat=animal(\'cat\') cat.type=\'male\' #相当于给cat增加了一个数据属性type,对类的type属性没有影响 print(cat.__dict__) print(cat.type) cat.l.append(\'c\')#此处修改的是类的数据属性l,与通过=赋值(给实例增加属性)不同
__class__:实例来自哪个类
__module__:实例来自哪个模块
类的组合
即在类实例化时,将另一个类的实例作为参数传入,这样可以将两个实例关联起来。
当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好。
例如,描述一个机器人类,这个大类是由很多互不相关的小类组成,如机械胳膊类、腿类、电池类等。
当类之间有很多相同的属性,提取这些统统的属性做成基类,用继承比较好。
class course: def __init__(self,name,price,period,teacher): self.name=name self.price=price self.period=period self.teacher=teacher class teacher: def __init__(self,name,sex): self.name=name self.sex=sex class student: def __init__(self,name,age,course): self.name=name self.age=age self.course=course t1=teacher(\'Bob\',38) t2=teacher(\'Jack\',45) t3=teacher(\'Jane\',45) c1=course(\'python\',6000,\'3 months\',t2)#将teacher作为参数传递给课程实例 c2=course(\'linux\',7000,\'5 months\',t1) c3=course(\'mysql\',6500,\'5 months\',t3) d={\'1\':c1,\'2\':c2,\'3\':c3} name=\'Alice\' age=21 while True: choice=input(\'please choice course:\') if choice in d.keys(): s1=student(name,age,d[choice])#将课程实例作为参数传递给学生实例 print(s1.__dict__) print(\'%s choose course %s,%s is the teacher\'%(s1.name,s1.course.name,s1.course.teacher.name)) elif int(choice)==0: exit(0) else: print(\'please input correct choice\')
运行结果如下图