一:对象的 加载顺序
class A: country = 'China' print(country) # China def __init__(self): print('执行我了')A.country = 'English' # China类的加载顺序 1.类内部一个缩进的所有代码都是在py文件从上到下解释的时候就已经被执行了 2.类中的代码永远是从上到下依次执行的,不需要调用 3.如果有同名的方法、属性,总是写在后面的会生效 class A: country = 'China' def __init__(self): print('执行我了') # 执行我了 def func(self): print('1111111') def func(self): print('2222222') # 2222222 只打印2222222,不打印1111111 # 如果有同名的方法、属性,总是写在后面的会生效A.country = 'English'a = A() # 执行我了a.func() # 2222222 class A: country = 'China' country = 'English' def __init__(self): print('执行我了') # 执行我了 def func(self): print('1111111') def func(self): print('2222222') # 2222222 只打印2222222,不打印1111111print(A.country) # Englishclass A: def __init__(self): print('执行我了') # 执行我了 def func(self): print('1111111') def func(self): print('2222222',A.country) # 2222222 English country = 'China' country = 'English'# a = A() # 实例化一个对象# a.func()A().func() # 对象调用函数
class A: wahaha = 'adGa' def wahaha(self): passprint(A.wahaha) # a = A()print(a.wahaha)# ># wahaha方法把变量给覆盖了,就是后加载进来的方法覆盖了之前加载的属性class A: wahaha = 'adGa' def t(self): passprint(A.wahaha) # adGaprint(A().wahaha) # adGa一:我们定义的类的属性到底存到哪里了?有两种方式查看dir(类名):查出的是一个名字列表类名.__dict__:查出的是一个字典,key为属性名,value为属性值二:特殊的类属性类名.__name__ # 类的名字(字符串)类名.__doc__ # 类的文档字符串类名.__base__ # 类的第一个父类(在讲继承时会讲)类名.__bases__ # 类所有父类构成的元组(在讲继承时会讲)类名.__dict__ # 类的字典属性类名.__module__ # 类定义所在的模块类名.__class__ # 实例对应的类(仅新式类中)
二:类和对象的命名空间
类 和 对象 存储在两块命名空间里的class Student: country = 'China' def __init__(self,name,country): self.name = name self.country = countryzhang = Student('Ivan','日本人')zou = Student('Jone','法国人')print(Student.country) # Chinaprint(zou.country) # 法国人print(zhang.country) # 日本人# 对象去找类空间中的名字的前提 : 在自己的空间中没有这个名字class Student: country = 'China' def __init__(self,name): self.name = namezhang = Student(''Ivan ')zou = Student(' Jone ')print(zhang.country) # ChinaStudent.country = '法国人'print(zhang.country) # 法国人zhang.country = '日本人' # 给一个对象添加了一个属性print(zou.country) # 法国人print(zhang.country) # 日本人在操作静态变量的时候应该尽量的使用类名来操作而不是使用对象名人物class Person: money = 0 def __init__(self,name): self.name = name def salary_deliery(self): Person.money += 1000
练习 :写一个类,能够自动的统计这个类有多少个对象class A: Count = 0 def __init__(self,name): self.name = name A.Count += 1 # 不推荐在类的内部使用类的名字a = A('alex') # 创建了一个新对象a2 = A('alex2')print(A.Count) # 2class B: a = [0] def __init__(self,name): self.name = nameb1 = B('Ivan')b2 = B('Merry')print(B.a) # [0]print(b1.a) # [0]print(b2.a) # [0]b1.a[0] += 1print(b2.a[0]) # 1b1.a = [123]print(b2.a) # [1]只要是对一个对象.名字直接赋值,那么就是在这个对象的空间内创建了新的属性只要是对一个可变的数据类型内部的变化,那么仍然是所有的对象和类共享这个改变的成果 b1.a[0] += 1所有的静态变量都是用类名来操作,这样修改就能被所有的对象感知到如果是对于可变数据类型的静态变量 操作的是这个数据内部的内容,也可以使用对象来调用类的命名空间 是在定义类的阶段被加载进来的: 静态变量、类变量 —— 直接定义在类中的变量 动态变量、方法 —— 定义在类中的函数 魔术方法、双下方法 内置的方法 :__init__ 内置的变量 : __dict__对象的命名空间 实例化的时候创建出来的: 类指针、类对象指针 执行init之前就已经在了 对象的属性 是在执行init以及之后被添加的
1,执行完init里面的内容以后,才把student指向内存地址,相当于给内存一个命名,student不先指向内存,是因为还不知道这块内存有多大,如果先命名了,在加一个属性,修改会比较麻烦2,执行第7步init之前,偷偷的新开了一个对象的内存(每个对象都会有自己各自的命名空间),然后执行第7步init,self指向新开的内存3,最后才把对象的内存空间,交给yang4,yang.func() 先找到自己的对象内存空间,每个对象的内存 空间都会有类对象指针,类对象指针指向类。最后找到类中定义的fun5,每个对象都共享类里的内容,但是内找不到对象,内里没有指向对象的指针