面向对象进阶二(组合补充、主动调用其他类的成员、特殊成员)
一、组合补充(重要程度*****)
分析如下几个示例的代码和结果,并作出总结:
# #####示例一:验证 类 或 对象 是否能做字典的key class Foo: pass user_info = { Foo : 1, # 类 做字典的key Foo() : 5 # 对象 做字典的key } print(user_info) # {<class '__main__.Foo'>: 1, <__main__.Foo object at 0x00000000029284E0>: 5}
# #####示例二:对象中到底有什么? class Foo(object): def __init__(self,age): self.age = age def display(self): print(self.age) data_list = [Foo(8),Foo(9)] for item in data_list: print(item.age,item.display()) # 结果为: # 8 # 8 None # 9 # 9 None
# #####示例三. class StarkConfig(object): def __init__(self,num): self.num = num def changelist(self,request): print(self.num,request) class RoleConfig(StarkConfig): def changelist(self,request): print('666') # 创建了一个列表,列表中有三个对象(实例) config_obj_list = [StarkConfig(1),StarkConfig(2),RoleConfig(3)] for item in config_obj_list: print(item.num) # 结果为: # 1 # 2 # 3 # 分析:RoleConfig类中没有__init__方法,创建对象时又传了一个参数3, # 所以就去父级查找有没有__init__,有则执行,在所创建的对象中封装数据3
# #####示例四 class StarkConfig(object): def __init__(self,num): self.num = num def changelist(self,request): print(self.num,request) def run(self): self.changelist(999) class RoleConfig(StarkConfig): def changelist(self,request): print(666,self.num) config_obj_list = [StarkConfig(1),StarkConfig(2),RoleConfig(3)] config_obj_list[1].run() # 2 999 config_obj_list[2].run() # 666 3
# #####示例五 class UserInfo(object): pass class Department(object): pass class StarkConfig(object): def __init__(self,num): self.num = num def changelist(self,request): print(self.num,request) def run(self): self.changelist(999) class RoleConfig(StarkConfig): def changelist(self,request): print(666,self.num) class AdminSite(object): def __init__(self): self._registry = {} def register(self,k,v): self._registry[k] = v(k) site = AdminSite() site.register(UserInfo,StarkConfig) site.register(Department,StarkConfig) print(len(site._registry)) # 2 for k,row in site._registry.items(): row.run() # 结果为: # <class '__main__.UserInfo'> 999 # <class '__main__.Department'> 999
总结:
1)对象 和 类 可以做字典的key;
2)明确对象中到底封装了什么;
3)哪个对象.方法,那么self就是这个对象,就从这个对象的类开始找;
二、主动调用其他类的成员(***)
如何主动调用其他类的成员,如下两种方式:
# #####方式一:Base.实例方法(自己传self) 与继承无关 class Base(object): def f1(self): print('5个功能', self) class Foo(object): def f1(self): print('3个功能') Base.f1(self) # 此时,参数必须要写,python不会自动传,写什么传什么 obj = Foo() obj.f1() # 结果为: # 3个功能 # 5个功能 <__main__.Foo object at 0x0000000002718D68>
# #####方式二:按照类的继承顺序,找下一个. class Foo(object): def f1(self): super().f1() print('3个功能') class Bar(object): def f1(self): print('6个功能') class Info(Foo,Bar): # 查找顺序:Info Foo Bar pass obj = Info() obj.f1() # 结果为: # 6个功能 # 3个功能
三、特殊成员(目前是***,越往后期越重要,越看源码用的越多)
1、按照某种语法会自动执行某些方法,如下示例:
class Foo(object): def __init__(self, a1, a2): self.a1 = a1 self.a2 = a2 def __call__(self, *args, **kwargs): print('call', args, kwargs) return 123 def __getitem__(self, item): print(item) return 8 def __setitem__(self, key, value): print(key, value, 'setitem') def __delitem__(self, key): print(key) def __add__(self, other): return self.a1 + other.a2 def __enter__(self): print('enter') return '执行__enter__方法' def __exit__(self, exc_type, exc_val, exc_tb): print('exit') # 1. 类名() 自动执行 __init__ obj = Foo(1,2) # 2. 对象() 自动执行 __call__ ret = obj(6,4,2,k1=456) # call (6, 4, 2) {'k1': 456} print(ret) # 123 # 3. 对象['xx'] 自动执行 __getitem__ ret = obj['yu'] print(ret) # yu # 4. 对象['xx'] = 11 自动执行 __setitem__ obj['k1'] = 123 # k1 123 setitem # 5. del 对象[xx] 自动执行 __delitem__ del obj['delitem'] # delitem # 6. 对象+对象 自动执行 __add__ obj1 = Foo(1,2) obj2 = Foo(88,99) ret = obj2 + obj1 print(ret) # 90 # 7. with 对象 自动执行 __enter__ / __exit__ obj = Foo(1,2) with obj as f: print(f) # 执行__enter__方法 print('内部代码')
2、真正的构造方法
class Foo(object): def __init__(self, a1, a2): # 初始化方法 """ 为空对象进行数据初始化 """ self.a1 = a1 self.a2 = a2 def __new__(cls, *args, **kwargs): # 构造方法 """ 创建一个空对象 若不写__new__,则会由所有类的父类object的__new__来创建 :return: """ return object.__new__(cls) # Python内部创建一个当前类的对象并返回(初创时内部是空的.) obj1 = Foo(1,2) # 先执行 __new__() 方法,再执行 __init__() 方法 print(obj1) # 此对象内存地址与__new__方法中返回的对象内存地址一样,但一个无数据,一个有数据