面向对象进阶:类成员、类成员的修饰符、类的特殊成员
类成员
类成员分为三大类:字段、方法、属性
一、字段
- 静态字段 (属于类)
- 普通字段(属于对象)

1 class City: 2 # 静态字段 3 country = "中国" 4 5 def __init__(self,city_name): 6 # 普通字段 7 self.city_name = city_name 8 9 def show(self): 10 print(self.city_name) 11 12 13 obj1 = City("Harbin") 14 obj2 = City("Shanghai") 15 # 普通字段对象来访问 16 print(obj1.city_name,obj2.city_name) 17 # 静态字段通过类名访问 18 print(City.country)
内存中分布:
- 静态字段在内存中只保存一份
- 普通字段在每个对象中都要保存一份
静态字段定义及应用:随着这个程序的执行产生,随着程序的结束而消失,这样和程序‘共存亡’的字段,我们就叫它静态字段。它就像是一个全局变量,不属于任何一个对象,我们可以直接使用类来调用,也可以在对象使用方法的时候使用它。它是对象共享的变量,存在类的内存里。
特殊:对象也可以访问静态字段。静态字段在代码加载时已经创建。
遵循规则:普通字段只能对象访问;静态字段用类访问。(万不得已用对象访问)
二、方法
- 静态方法:由类调用;无默认参数;
- 类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;
- 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;

1 class Province: 2 3 country = "China" 4 def __init__(self,name): 5 self.name = name 6 7 # 普通方法 由对象调用。 8 def show(self): 9 print(self.name) 10 11 # 静态方法 ,无self参数;方法前边加上关键字@staticmethod 由类调用 12 @staticmethod 13 def display(a,b,c): 14 print(a,b,c) 15 16 # 类方法(相当于静态方法特殊形式),至少要有一个cls参数。由类调用 17 @classmethod 18 def listen(cls,b): 19 ''' 20 cls:类名 21 ''' 22 print(cls.country,b) 23 24 obj = Province("黑龙江") 25 obj.show() # 普通方法由对象调用 26 Province.display(1,2,3) # 静态方法由类调用执行 27 Province.listen(2) # cls是python自动传递
三、属性
- 属性的基本使用
1 class Page: 2 3 def __init__(self,all_counts): 4 self.all_counts = all_counts 5 6 # 属性: 分页 7 @property 8 def divpages(self): 9 a,b = divmod(self.all_counts,10) 10 if b == 0: 11 return a 12 else: 13 return a+1 14 15 16 p = Page(101) 17 ret = p.divpages# 调用属性 直接返回 18 print(ret)
属性的定义和调用:
- 定义时,在普通方法的基础上添加 @property 装饰器;
- 定义时,属性仅有一个self参数
- 调用时,无需括号
属性:p.divpages
Python的属性的功能是:属性内部进行一系列的逻辑计算,最终将计算结果返回
注意:属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象
属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能。
1 class Page: 2 3 def __init__(self,all_counts): 4 self.all_counts = all_counts 5 6 # 属性: 分页 7 @property 8 def divpages(self): 9 a,b = divmod(self.all_counts,10) 10 if b == 0: 11 return a 12 else: 13 return a+1 14 # 设置属性:支持赋值操作 15 @divpages.setter 16 def divpages(self,value): 17 self.all_counts = value 18 # 删除 19 @divpages.deleter 20 def divpages(self): 21 print("del property") 22 p = Page(101) 23 p.divpages = 111 #自动执行 @divpages .setter 修饰的 divpages 方法,并将 123 赋值给方法的参数 24 ret = p.divpages # 自动执行 @property 修饰的 divpages方法,并获取方法的返回值 25 del p.divpages # 自动执行 @divpages.deleter 修饰的 divpages方法 26 print(ret)
属性操作:不同属性调用形式,触发不同装饰器的方法,见下图。
- 属性另一种表达方式
class Page: def __init__(self,count): self.count = count def f1(self): return 123 def f2(self): print("fset:赋值") def f3(self): print("fdel:删除") foo = property(fget=f1,fset=f2,fdel=f3) p = Page(100) ret = p.foo # 自动回找到fool,会找到fget对应函数f1并执行,并将返回值 p.foo =113 #会找到fset对应函数f2并执行 del p.foo # 会找到fdel并执行f3
类成员修饰符
- 公有:在类内和类外均可以访问
- 私有:仅在类的内部可以访问;私有成员命名时,前两个字符是下划线
- 公有字段和私有字段
1 class Person: 2 # 私有 静态字段 3 __school = "北大" 4 def __init__(self,name,sex): 5 # 普通字段,公有,name ;私有 sex 6 self.name = name 7 self.__sex = sex 8 9 # 均可在类内调用 10 def f1(self): 11 print(self.name) 12 print(self__sex) 13 14 def f2(self): 15 print(Person.__school) 16 17 class ChianPerson(Person): 18 def f2(self): 19 print(self.__sex) 20 21 obj = Person("lcy","man") 22 print(obj.name) # 类外访问公有普通字段 23 # print(obj.__sex) # 无法访问 报错 no attribute 24 #print(Person.__school) # 无法访问 25 obj.f3() # 打印 "北大" 26 # ----- 继承,派生类不能访问基类私有的普通字段------- 27 obj2 = ChinaPerson("alex","female") 28 #obj2.f2() # 执行 失败,只有Person类内方法可以访问 29 obj2.f1() # 可以执行f1是Person类中的方法
2. 公有方法和私有方法
(略)
这里公有方法和私有方法与上边字段访问限制是一样的。私有方法命名同私有字段命名相同。只要在函数名前加两个下划线,就表示私有方法。
类的特殊成员
- __init__:构造方法
- __del__:析构方法
- __doc__:注释类
- __module__:对象所在模块
- __class__:对象类名
- __call__: obj() 或类名()触发执行
- __str__:print(obj)自动调用
- 其他:__add__
1 class Person: 2 ''' 3 这是一个人类 4 ''' 5 def __init__(self,name): 6 self.name = name 7 8 def __del__(self): 9 print("这是析构函数一般不自定义,python有自己的回收机制") 10 11 def __call__(self, *args, **kwargs): 12 print("call") 13 14 def __str__(self): 15 return ("__str__:%s"%self.name) 16 17 def __add__(self, other): 18 print(self.name,other.name) 19 20 21 22 # 创建对象,自动调用__init__ 23 obj_p1 = Person("lcy")# 24 obj_p2 = Person("alex") 25 print(obj_p1.__doc__) 26 print(obj_p1.__module__) 27 print(obj_p1.__class__) 28 # 自动调用 __call__ 29 obj_p1() 30 #Person("lcy")() 同 obj_p1() 31 # 触发__str__方法 32 print(obj_p1) 33 res = str(obj_p1) 34 print(res) 35 # 会触发 __add__ /同理会有其他的方法,加减乘除。。。 36 obj_p1+obj_p2 37 # 程序会自动调用__del__析构函数,对象在回收机制之前,这里会调用两次,因为创建了两次
- __dict__:重点 (默认已经存在类或者对象中)
获取类成员:静态字段,方法。
1 class Game: 2 3 Game_name = "SIM3" 4 5 def __init__(self): 6 pass 7 8 def show(self): 9 pass 10 11 print(Game.__dict__) 12 ''' 13 {'__init__': <function Game.__init__ at 0x00503E88>, 14 'show': <function Game.show at 0x00503DF8>, 15 '__weakref__': <attribute '__weakref__' of 'Game' objects>, 16 '__module__': '__main__', '__dict__': <attribute '__dict__' of 'Game' objects>, 17 'Game_name': 'SIM3', '__doc__': None} 18 '''
对象:获取对象的字段
1 class Game: 2 3 Game_name = "SIM3" 4 5 def __init__(self,level,money): 6 self.level = level 7 self.money = money 8 9 def show(self): 10 pass 11 obj = Game(12,199) 12 print(obj.__dict__) 13 ''' 14 {'money': 199, 'level': 12} 15 '''
- __getitem__、__setitem__、__delitem__
对象用于索引,如字典相关操作。获取、设置以及删除操作
1 class Foo: 2 3 def __getitem__(self, item): 4 print(item) 5 6 def __setitem__(self, key, value): 7 print(key,value) 8 9 def __delitem__(self, key): 10 print(key) 11 12 obj = Foo() 13 obj["k1"] # 触发 __getitem__ 14 obj[3] #触发 __getitem__ 15 obj[2] = 234 # 触发__setitme 16 del obj[3] # 触发__delitem
支持对象切片操作。(python3 用触发上边的方法来实现)
1 class Foo: 2 3 def __getitem__(self, item): 4 print(type(item)) 5 print(item.start) 6 print(item.stop) 7 print(item.step) 8 9 def __setitem__(self, key, value): 10 print(type(key)) 11 print(key.start,key.stop,key.step,value) 12 13 def __delitem__(self, key): 14 print(type(key)) 15 print(key.start,key.stop,key.step) 16 17 obj = Foo() 18 obj[1:3:2] # 触发 __getitem__ 19 obj[1:3:2] = [11,22,44] #触发 __setitem__ 20 del obj[1:3:2] # 触发__delitem__
输出:
<class 'slice'>
1
3
2
<class 'slice'>
1 3 2 [11, 22, 44]
<class 'slice'>
1 3 2
(待续,天冷,打字都动手啊)