@@@文章内容参照老男孩教育 Alex金角大王,武Sir银角大王@@@
一、类的成员
类的成员可以分为三大类:字段、方法和属性
注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段。而其他的成员,则都是保存在类中,即:无论对象的多少,在内存中只创建一份。
1、字段
字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同。
- 普通字段属于对象
- 静态字段属于类
1 class Province(object): 2 3 country = ‘CN‘ # 静态字段 4 5 def __init__(self,name): 6 7 self.name = name # 普通字段 8 9 # 直接访问普通字段 10 obj = Province(‘北京‘) 11 print(obj.name) 12 13 # 直接访问静态字段 14 print(Province.country) 15 # 由上述代码可以看出普通字段需要通过对象来访问;静态字段通过类访问, 16 # 在使用上可以看出普通字段和静态字段的归属是不同的。
2、方法
方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。
- 普通方法:由对象调用,至少一个self参数,执行普通方法时,自动将调用该方法的对象赋值给self
- 类方法:由类调用,至少一个cls参数,执行类方法时,自动将调用该方法的类复制给cls
- 静态方法:由类调用,无默认参数
1 class Foo(object): 2 name = ‘我是类变量‘ 3 def __init__(self,name): 4 self.name = name 5 6 def ord_func(self): 7 ‘‘‘定义普通方法,至少有一个self参数‘‘‘ 8 print(‘普通方法:‘,self.name) 9 10 @classmethod 11 def cls_func(cls): 12 ‘‘‘定义类方法,至少有一个cls参数‘‘‘ 13 print(‘类方法:‘,cls.name) 14 15 @staticmethod 16 def sta_func(): 17 ‘‘‘定义静态方法,无默认参数‘‘‘ 18 print(‘静态方法‘) 19 20 # f = Foo(‘jack‘) # 调用普通方法 21 # f.ord_func() 22 Foo.cls_func() # 调用类方法 23 Foo.sta_func() 24 25 # 相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。 26 # 不同点:方法调用者不同、调用方法时自动传入的参数不同。
3、属性
属性方法的作用就是通过@property把一个方法变成一个静态属性
属性的基本使用
1 class Foo(object): 2 3 def __init__(self,name): 4 self.name = name 5 6 @property 7 def func(self): 8 print(‘Hello %s‘ %self.name) 9 10 f = Foo(‘jack‘) 11 # f.func() 12 # 调用会出以下错误, 说TypeError: ‘NoneType‘ object is not callable, 因为func此时已经变成一个静态属性了, 13 # 不是方法了, 想调用已经不需要加()号了,直接f.func就可以了 14 f.func
属性的定义方式
1 # 经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法 2 class Goods: 3 @property 4 def price(self): 5 print(‘Hello‘) 6 7 obj = Goods() 8 obj.price # 自动执行 @property 修饰的 price 方法 9 10 # 新式类中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法 11 class Goods(object): 12 @property 13 def price(self): 14 print(‘@property‘) 15 16 @price.setter 17 def price(self,value): 18 print(‘@price.setter‘,value) 19 20 @price.deleter 21 def price(self): 22 print(‘@price.deleter ‘) 23 24 obj = Goods() 25 obj.price # 自动执行 @property 修饰的 price 方法 26 obj.price = 123 # 自动执行 @price.setter 修饰的 price 方法,并将 123 赋值给方法的参数 27 del obj.price # 自动执行 @price.deleter 修饰的 price 方法
由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除
1 class Goods(object): 2 3 def __init__(self): 4 self.original_price = 100 # 原价 5 self.discount = 0.8 # 折扣 6 7 @property 8 def price(self): 9 ‘‘‘实际价格 = 原价 * 折扣‘‘‘ 10 new_price = self.original_price * self.discount 11 return new_price 12 13 @price.setter 14 def price(self,value): 15 self.original_price = value 16 17 @price.deleter 18 def price(self): 19 del self.original_price 20 21 obj = Goods() 22 print(obj.price) # 获取商品价格 23 obj.price = 200 # 修改商品原价 24 print(obj.price) 25 del obj.price # 删除商品原价
二、类成员的修饰符
类的所有成员在上一步骤中已经做了详细的介绍,对于每一个类的成员而言都有两种形式:
- 公有成员,在任何地方都能访问
- 私有成员,只有在类的内部才能访问
私有成员和公有成员的定义不同:私有成员命名时,前两个字符是下划线。(特殊成员除外,例如:__init__、__call__、__dict__等)
1 class C(object): 2 3 def __init__(self): 4 self.name = ‘公有字段‘ 5 self.__foo = ‘私有字段‘
私有成员和公有成员的访问限制不同:
静态字段
- 公有静态字段:类可以访问,类内部可以访问,派生类中可以访问
- 私有静态字段:仅类内部可以访问
1 # 公有静态字段 2 class C(object): 3 name = ‘公有静态字段‘ 4 def func(self): 5 print(C.name) 6 7 class D(C): 8 def show(self): 9 print(C.name) 10 11 print(C.name) # 类访问 12 obj = C() 13 obj.func() # 类内部可以访问 14 15 obj_son = D() 16 obj_son.show() # 派生类中可以访问 17 18 # 私有静态字段 19 class C(object): 20 __name = ‘私有静态字段‘ 21 def func(self): 22 print(C.__name) 23 24 class D(C): 25 def show(self): 26 print(C.__name) 27 28 # print(C.__name) # 类访问 ----错误 29 obj = C() 30 obj.func() # 类内部可以访问 31 32 # obj_son = D() 33 # obj_son.show() # 派生类中可以访问 ----错误
普通字段
- 公有普通字段:对象可以访问,类内部可以访问,派生类中可以访问
- 私有普通字段:仅类内部可以访问
ps:如果想要强制访问私有字段,可以通过[对象._类名__私有字段明]访问(如:obj._C__foo),不建议强制访问私有成员。
1 # 公有字段 2 class C(object): 3 4 def __init__(self): 5 self.name = ‘公有字段‘ 6 def func(self): 7 print(self.name) # 类内部访问 8 9 class D(C): 10 def show(self): 11 print(self.name) 12 13 14 obj = C() 15 print(obj.func) # 通过对象访问 16 obj.func() # 类内部访问 17 18 obj_son = D() 19 obj_son.show() # 派生类中访问 20 21 # 私有字段 22 class C(object): 23 24 def __init__(self): 25 self.__name = ‘私有字段‘ 26 def func(self): 27 print(self.__name) # 类内部访问 28 29 class D(C): 30 def show(self): 31 print(self.__name) 32 33 34 obj = C() 35 obj.func() # 类内部访问 36 37 # obj_son = D() 38 # obj_son.show() # 派生类中访问 ----错误
方法、属性的访问于上述方式相似,即:私有成员只能在类内部使用
三、类的特殊成员
1、__doc__ 表示类的描述信息
1 class Foo: 2 """ 描述类信息,这是用于看片的神奇 """ 3 4 def func(self): 5 pass 6 7 print(Foo.__doc__)
2、__module__和__class__
__module__ 表示当前操作的对象在那个模块
__class__ 表示当前操作的对象的类是什么
1 # lib/aa.py 2 class C: 3 4 def __init__(self): 5 self.name = ‘Hello‘
1 from lib.aa import C 2 3 obj = C() 4 print(obj.__module__) # 输出 lib.aa,即:输出模块 5 print(obj.__class__) # 输出 lib.aa.C,即:输出类
3、__init__ 构造方法,通过类创建对象时,自动触发执行
4、__del__ 析构方法,当对象在内存中被释放时,自动触发执行
注:此方法一般无须定义,因为python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作是交给python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的
1 class Foo: 2 3 def __del__(self): 4 pass 5
5、__call__ 对象后面加括号,触发执行
1 class Foo: 2 3 def __init__(self): 4 pass 5 6 def __call__(self, *args, **kwargs): 7 print(‘__call__‘) 8 9 obj = Foo() # 执行 __init__ 10 obj() # 执行 __call__
6、__dict__ 查看类或对象中的所有成员
1 class Foo: 2 country = ‘CN‘ 3 4 def __init__(self,name,count): 5 self.name = name 6 self.count = count 7 8 def func(self, *args, **kwargs): 9 print(‘func‘) 10 11 print(Foo.__dict__) # 获取类的成员,即:静态字段、方法 12 13 obj1 = Foo(‘北京‘,10000) 14 print(obj1.__dict__) # 获取 对象obj1 的成员 15 16 obj2 = Foo(‘河南‘,3888) 17 print(obj2.__dict__) # 获取 对象obj2 的成员
7、__str__ 如果一个类中定义了__str__方法,那么在打印对象时,默认输出该方法的返回值
1 class Foo: 2 3 def __str__(self): 4 return ‘Hello World‘ 5 6 obj = Foo() 7 print(obj)
8、__getitem__、__setitem__、__delitem__
用于索引操作,如字典。以上分别表示获取、设置、删除数据
1 class Foo(object): 2 3 def __getitem__(self, key): 4 print(‘__getitem__‘,key) 5 6 def __setitem__(self, key,value): 7 print(‘__setitem__‘,key,value) 8 9 def __delitem__(self, key): 10 print(‘__delitem__‘,key) 11 12 obj = Foo() 13 14 ret = obj[‘k1‘] # 自动触发执行 __getitem__ 15 obj[‘k2‘] = ‘jack‘ # 自动触发执行 __setitem__ 16 del obj[‘k1‘]
9、__new__、__metaclass__
1 class Foo(object): 2 3 def __init__(self,name): 4 self.name = name 5 6 f = Foo(‘jack‘) 7 8 print(type(f)) # 输出:<class ‘__main__.Foo‘> 表示,obj 对象由Foo类创建 9 print(type(Foo)) # 输出:<type ‘type‘> 表示,Foo类对象由 type 类创建 10 11 # 所以,f对象是Foo类的一个实例,Foo类对象是 type 类的一个实例, 12 # 即:Foo类对象 是通过type类的构造方法创建。 13 # 那么,创建类就可以有两种方式: 14 # 普通方式 15 class Foo(object): 16 17 def func(self): 18 print(‘Hello World1‘) 19 20 obj1 = Foo() 21 obj1.func() 22 23 24 # 特殊方式 25 def func(self): 26 print(‘Hello World2‘) 27 28 Foo = type(‘Foo‘,(object,),{‘func‘:func}) 29 #type第一个参数:类名 30 #type第二个参数:当前类的基类 31 #type第三个参数:类的成员 32 33 obj2 = Foo() 34 obj2.func() 35 36 # 加上构造方法 37 def func(self): 38 print("hello %s"%self.name) 39 40 def __init__(self,name,age): 41 self.name = name 42 self.age = age 43 Foo = type(‘Foo‘,(object,),{‘func‘:func,‘__init__‘:__init__}) 44 45 f = Foo("jack",22) 46 f.func()
那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?
答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。
1 class MyType(type): 2 def __init__(self,*args,**kwargs): 3 4 print("Mytype __init__",*args,**kwargs) 5 6 def __call__(self, *args, **kwargs): 7 print("Mytype __call__", *args, **kwargs) 8 obj = self.__new__(self) 9 print("obj ",obj,*args, **kwargs) 10 print(self) 11 self.__init__(obj,*args, **kwargs) 12 return obj 13 14 def __new__(cls, *args, **kwargs): 15 print("Mytype __new__",*args,**kwargs) 16 return type.__new__(cls, *args, **kwargs) 17 18 print(‘here...‘) 19 20 class Foo(object,metaclass=MyType): 21 22 def __init__(self,name): 23 self.name = name 24 25 print("Foo __init__") 26 27 def __new__(cls, *args, **kwargs): 28 print("Foo __new__",cls, *args, **kwargs) 29 return object.__new__(cls) 30 31 f = Foo("jack") 32 print("f",f) 33 print("fname",f.name)
类的生成 调用 顺序依次是 __new__ --> __init__ --> __call__
metaclass 详解文章:http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python 得票最高那个答案写的非常好
四、其他相关
1、isinstance(obj,cls)
检查是否obj是否是类cls的对象
1 class Foo(object): 2 3 pass 4 5 obj = Foo() 6 print(isinstance(obj,Foo))
2、issubclass(sub,super)
检查sub类是否是super类的派生类
1 class Foo(object): 2 3 pass 4 5 class Bar(Foo): 6 7 pass 8 9 print(issubclass(Bar, Foo))