一:对象的 加载顺序
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,不打印1111111
print(A.country) # English
class 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):
pass
print(A.wahaha) # <function A.wahaha at 0x00000178CB465730>
a = A()
print(a.wahaha)
# <bound method A.wahaha of <__main__.A object at 0x00000178CB2C7358>>
# wahaha方法把变量给覆盖了,就是后加载进来的方法覆盖了之前加载的属性
class A:
wahaha = 'adGa'
def t(self):
pass
print(A.wahaha) # adGa
print(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 = country
zhang = Student('Ivan','日本人')
zou = Student('Jone','法国人')
print(Student.country) # China
print(zou.country) # 法国人
print(zhang.country) # 日本人
# 对象去找类空间中的名字的前提 : 在自己的空间中没有这个名字
class Student:
country = 'China'
def __init__(self,name):
self.name = name
zhang = Student(''Ivan ')
zou = Student(' Jone ')
print(zhang.country) # China
Student.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) # 2
class B:
a = [0]
def __init__(self,name):
self.name = name
b1 = B('Ivan')
b2 = B('Merry')
print(B.a) # [0]
print(b1.a) # [0]
print(b2.a) # [0]
b1.a[0] += 1
print(b2.a[0]) # 1
b1.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,最后才把对象的内存空间,交给yang
4,yang.func() 先找到自己的对象内存空间,每个对象的内存 空间都会有类对象指针,类对象指针指向类。最后找到类中定义的fun
5,每个对象都共享类里的内容,但是内找不到对象,内里没有指向对象的指针