类的属性有两种:数据属性和函数属性
类的数据属性是所对象共享的
类的函数属性是绑定给对象用的
下面分别来看一下,什么是数据属性,什么是函数属性,先简单定义一个类:
class Chinese: country='China' def __init__(self,name): self.name=name def play_ball(self,ball): print('%s 正在打 %s' %(self.name))
通过调用__dict__,会返回一个字典,这个字典就是属性字典:
print(Chinese.__dict__) >>> {'__module__': '__main__', 'country': 'China', '__init__': <function Chinese.__init__ at 0x000002085EB7B6A8>, 'play_ball': <function Chinese.play_ball at 0x000002085EB7B730>, '__dict__': <attribute '__dict__' of 'Chinese' objects>, '__weakref__': <attribute '__weakref__' of 'Chinese' objects>, '__doc__': None}
可以看到,country、__init__、play_ball都是字典里面的key,其中country就是数据属性,另外两个就是函数属性,如果要查看类的某个属性,操作如下:
class Chinese: country='China' def __init__(self,name): self.name=name def play_ball(self,ball): print('%s 正在打 %s' %(self.name)) #查看 print(Chinese.country) >>>China
直接返回就是属性对应的值,也就是说,类名加上.,本质上就是在查看属性字典,返回的就是key对应的value,如果要修改这个属性,操作如下:
class Chinese: country='China' def __init__(self,name): self.name=name def play_ball(self,ball): print('%s 正在打 %s' %(self.name)) Chinese.country='Japan' print(Chinese.country) >>> Japan
给对应的属性赋值,就是在修改这一属性,和字典的操作十分相似,所以增加和删除的属性的操作也是类似的:
class Chinese: country='China' def __init__(self,name): self.name=name def play_ball(self,ball): print('%s 正在打 %s' %(self.name)) Chinese.race='黄种人' print(Chinese.race) print(Chinese.__dict__) >>> 黄种人 >>>{'__module__': '__main__', 'country': 'China', '__init__': <function Chinese.__init__ at 0x000002BCBDF1B6A8>, 'play_ball': <function Chinese.play_ball at 0x000002BCBDF1B730>, '__dict__': <attribute '__dict__' of 'Chinese' objects>, '__weakref__': <attribute '__weakref__' of 'Chinese' objects>, '__doc__': None, 'race': '黄种人'} del Chinese.race print(Chinese.__dict__) >>>{'__module__': '__main__', 'country': 'China', '__init__': <function Chinese.__init__ at 0x0000025123EEB6A8>, 'play_ball': <function Chinese.play_ball at 0x0000025123EEB730>, '__dict__': <attribute '__dict__' of 'Chinese' objects>, '__weakref__': <attribute '__weakref__' of 'Chinese' objects>, '__doc__': None}
通过查看属性字典,可以看到增删的属性变化。那么实例的属性是怎样的呢?
class Chinese: country='China' def __init__(self,name): self.name=name def play_ball(self,ball): print('%s 正在打 %s' %(self.name,ball)) p1=Chinese('pengfy') print(p1.__dict__) print(p1.country) p1.play_ball('basketball) >>>{'name': 'pengfy'} >>>China >>>pengfy 正在打 basketball
首先,我们看到实例的属性字典里面只有一个属性,就是实例化过程中执行类的__init__方法产生的一个name属性,那为什么还能调用其他属性?如下图:
obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常 ,这个可以理解成函数的作用域中查找参数的情况。那么实例属性的增删改查和类一样,操作如下:
class Chinese: country='China' def __init__(self,name): self.name=name def play_ball(self,ball): print('%s 正在打 %s' %(self.name,ball)) p1=Chinese('alex') print(p1.__dict__) # 查看 print(p1.name) print(p1.play_ball) #增加 p1.age=18 print(p1.__dict__) print(p1.age) # 不要修改底层的属性字典 p1.__dict__['sex']='male' # print(p1.__dict__) # print(p1.sex) # 修改 p1.age=19 print(p1.__dict__) print(p1.age) #删除 del p1.age print(p1.__dict__)
现在再来看开始说的两句话:类的数据属性是所对象共享的,类的函数属性是绑定给对象用的
#类的数据属性是所有对象共享的,id都一样 print(id(Chinese.country)) print(id(p1.country)) print(id(p2.country)) print(id(p3.country)) ''' 1807264015728 1807264015728 1807264015728 1807264015728 ''' #类的函数属性是绑定给对象使用的,obj.method称为绑定方法,内存地址都不一样 #ps:id是python的实现机制,并不能真实反映内存地址,如果有内存地址,还是以内存地址为准 print(Chinese.play_ball) print(p1.play_ball) print(p2.play_ball) print(p3.play_ball) ''' <function Chinese.play_ball at 0x000001A4CB1BB730> <bound method Chinese.play_ball of <__main__.Chinese object at 0x000001A4CB1DEF98>> <bound method Chinese.play_ball of <__main__.Chinese object at 0x000001A4CB1E6198>> <bound method Chinese.play_ball of <__main__.Chinese object at 0x000001A4CB1E64A8>>