Python_类对象、实例对象、类属性、实例属性、类方法、实例方法
认识类对象、实例对象、类属性、实例属性、类方法、实例方法
- 类对象:定义的类就是类对象
- 实例对象:类对象实例化后就是实例对象
- 类属性:定义在 __init__ 外部的变量
- 实例属性:定义在__init__内部的带有self.的变量
- 类方法:定义在类对象中 且 被@classmethod 装饰的方法就是类方法
- 实例方法:定义在类对象中,且 未被@classmethod 装饰的方法就是实例方法
class Foo: # 【类属性】定义在 __init__ 外部的变量 cls_attr = "我是类属性" def __init__(self): # 【实例属性】定义在__init__内部的带有self.的变量。没有self.是局部变量 self.self_attr = "我是实例属性" @classmethod def cls_func(cls): print("我是类方法") print("在类方法内部调用类属性", cls.cls_attr) def self_func(self): print("我是实例方法") print("在实例方法内部调用类属性", self.cls_attr) print("在实例方法内部调用实例属性", self.self_attr) if __name__ == '__main__': # 类对象:定义的类就是类对象 print("类对象", Foo) # 实例对象:类对象实例化后就是实例对象 self_obj = Foo() print("实例对象", self_obj) print("-" * 30) # 类属性:定义在 __init__ 外部的变量 # 类属性可以被类对象调用,也可以被实例对象调用,调用方式是【对象.类属性】调用 print("类对象调用类属性", Foo.cls_attr) print("实例对象调用类属性", self_obj.cls_attr) print("-" * 30) # 实例属性:定义在__init__内部的带有self.的变量 # 实例属性只能实例对象调用 print("实例对象调用实例属性", self_obj.self_attr) print("-" * 30) # 类方法:定义在类对象中 且 被@classmethod 装饰的方法就是类方法 # 类方法可以被类对象调用,也可以被实例对象调用,调用方式是【对象.类属性】调用 print("类对象调用类方法", Foo.cls_func()) print("实例对象调用类方法", self_obj.cls_func()) print("-" * 30) # 实例方法:定义在类对象中,且 未被@classmethod 装饰的方法就是实例方法 # 实例方法只能被实例对象调用 print("实例对象调用类方法", self_obj.self_func())
类对象实例化过程中的内存分配说明
当执行python脚本时,Python解析到类对象时,会给类对象在内存中分配一块区域,在这处内存中存储类对象的所有属性和方法。
当创建实例时,每创建一个实例就会将实例属性和方法全部复制一份,并存储到一块新的内存区域。
类属性和类方法不会被复制,但是我们可以通过实例对象调用它们,这是因为每个创建的实例对象都会添加__class__属性,该属性指向类对象,因此能够通过实例对象调用类属性和类方法。
class Foo: # 【类属性】定义在 __init__ 外部的变量 cls_attr = "我是类属性" def __init__(self): # 【实例属性】定义在__init__内部的带有self.的变量。没有self.是局部变量 self.self_attr = "我是实例属性" @classmethod def cls_func(cls): print("我是类方法") print("在类方法内部调用类属性", cls.cls_attr) def self_func(self): print("我是实例方法") print("在实例方法内部调用类属性", self.cls_attr) print("在实例方法内部调用实例属性", self.self_attr) if __name__ == '__main__': foo1 = Foo() foo2 = Foo() # 通过类对象和实例对象的内存id可以说明每次实例化类对象,都会分配新的内存地址 print(id(Foo)) print(id(foo1)) print(id(foo2)) print("-" * 30) # 通过实例方法的内存id,能说明实例化会将实例属性和方法均复制一份保存到新的内存地址中 print(id(foo1.self_func)) print(id(foo2.self_func)) print("-" * 30) # 通过对比类对象和__class__属性的内存id,能说明实例对象的__class__指向的确实是实例对象的源类对象 print(id(Foo)) print(id(foo1.__class__)) print(id(foo2.__class__)) print(id(Foo.cls_attr)) print(id(foo1.cls_attr))
综上所述,从类的维度可以简单理解为
类属性和类方法是共用的(或全局的),不管任何类对象或实例对象修改了类属性或方法中的变量值,所有调用的地方都会受影响。
实例属性和实例方法是私有的(或局部的),某个实例对象修改了实例属性或方法的变量值,只会影响其本身,不会影响其它实例对象。