python之面向对象进阶
Posted xiaobin12126
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python之面向对象进阶相关的知识,希望对你有一定的参考价值。
1 # 2 == 3 # 值是否相等 2 # 2 is 3 # 内存地址是否相等
isinstance和issubclass
isinstance(obj,cls)检查是否obj是否是类 cls 的对象 判断第一个参数是否是第二个参数的实例
1 class A:pass 2 class B(A):pass 3 class C(B):pass 4 c = C() 5 print(isinstance(c,A)) # 包含继承关系的判断 #true
issubclass(sub, super)检查sub类是否是 super 类的派生类 第一个参数是疑似子类,第二个参数是疑似父类.
1 class A:pass 2 class B(A):pass 3 print(issubclass(A,B)) #false 4 print(issubclass(B,A)) #true
反射
1 什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
1 # hasattr 判断某一个 变量 是否能够.调用一个名字,返回True或者False 2 # getattr 直接获取一个变量中的名字的值 3 4 class A: 5 name = ‘alex‘ # 静态 属性 6 age = 83 # 静态 属性 7 print(getattr(A,‘name‘)) #alex 8 print(hasattr(A,‘name‘)) #true
1 class Student: 2 def __init__(self,name,age): 3 self.name = name 4 self.age = age 5 def show(self): 6 for key in self.__dict__: 7 print(key,self.__dict__[key]) 8 9 yuan = Student(‘苑昊‘,38) 10 if hasattr(yuan,‘name‘): 11 print(getattr(yuan,‘name‘)) #苑昊 12 if hasattr(yuan,‘show‘): 13 func = getattr(yuan,‘show‘) 14 func() #name 苑昊 age 38
1 # setattr 为一个变量增加或者修改一个属性 2 # delattr 删除一个变量中的属性或者方法 3 4 class Student: 5 def __init__(self,name,age): 6 self.name = name 7 self.age = age 8 def show(self): 9 for key in self.__dict__: 10 print(key,self.__dict__[key]) 11 12 hei = Student(‘小黑‘,18) 13 hei.sex = ‘不详‘ 14 print(hei.sex) #不详 15 setattr(hei,‘sex‘,‘不详‘) # 增改操作 16 print(hei.sex) #不详 17 setattr(hei,‘sex‘,‘male‘) 18 print(hei.sex) #不详 19 delattr(hei,‘sex‘) # 删除操作 20 print(hei.__dict__) 21 def wahaha(a,b): # 专属于某一个对象的静态方法 22 print(a,b) #{‘name‘: ‘小黑‘, ‘age‘: 18}
1 # 反射类中的名字 2 # getattr(类名,‘静态属性‘) 3 # getattr(类名,‘类方法‘)() 4 # getattr(类名,‘静态方法‘)() 5 6 # 反射对象中的名字 7 # getattr(对象名,‘对象属性‘) 8 # getattr(对象名,‘方法名‘)() 9 10 # 反射模块中的名字 11 # import 模块名 12 # getattr(模块名,‘模块中的变量‘) 13 # getattr(模块名,‘模块中的函数‘)() 14 # getattr(模块名,‘模块中的类名‘) 15 16 # 反射当前模块中的名字 17 # import sys 18 # getattr(sys.modules[__name__],‘变量‘) 19 # getattr(sys.modules[__name__],‘函数‘)() 20 # getattr(sys.modules[__name__],‘类名‘) 21 22 # sys.modules[__name__] 23 # import sys 24 # print(sys.modules[__name__]) # 所有导入过的模块 25 # {‘字符串数据类型的模块名‘:模块的内存地址} 26 # {‘__main__‘:当前模块的内存地址}
1 class person:pass 2 hei = person() 3 setattr(hei,‘name‘,‘小黑‘) 4 setattr(hei,‘age‘,18) 5 print(hei,hei.__dict__)
1 # 怎么反射类 ? 2 # class Student: 3 # def __init__(self,name,age): 4 # self.name = name 5 # self.age = age 6 # def show_student(self): 7 # for key in self.__dict__: 8 # print(key,self.__dict__[key]) 9 # 10 # class Teacher: 11 # def __init__(self, name, age): 12 # self.name = name 13 # self.age = age 14 # 15 # def show_teacher(self): 16 # for key in self.__dict__: 17 # print(key, self.__dict__[key]) 18 # 19 # class Manager: 20 # def __init__(self, name, age): 21 # self.name = name 22 # self.age = age 23 # 24 # def show_manager(self): 25 # for key in self.__dict__: 26 # print(key, self.__dict__[key]) 27 # hei = Student(‘小黑‘,18) 28 # import sys 29 # main = sys.modules[__name__] 30 # import my_moudle 31 # cls = getattr(my_moudle,‘Student‘) 32 # hei = cls(‘小黑‘,18) 33 # print(hei,hei.__dict__) 34 35 # ‘Manager‘ ‘Teacher‘ ‘Student‘ 36 # 获取字符串数据类型的类名 37 # cls_name = input(‘>>>‘) 38 39 # 根据输入反射找到具体的类 40 # if hasattr(main,cls_name): 41 # cls = getattr(main,cls_name) 42 43 # 实例化对象 44 # alex = cls(‘alex‘,81) 45 # print(type(alex)) 46 # 展示这个对象中的所有方法 47 # for i in alex.__dict__: 48 # print(i,alex.__dict__[i])
__str__和__repr__
改变对象的字符串显示__str__,__repr__
自定制格式化字符串__format__
1 #_*_coding:utf-8_*_ 2 3 format_dict={ 4 ‘nat‘:‘{obj.name}-{obj.addr}-{obj.type}‘,#学校名-学校地址-学校类型 5 ‘tna‘:‘{obj.type}:{obj.name}:{obj.addr}‘,#学校类型:学校名:学校地址 6 ‘tan‘:‘{obj.type}/{obj.addr}/{obj.name}‘,#学校类型/学校地址/学校名 7 } 8 class School: 9 def __init__(self,name,addr,type): 10 self.name=name 11 self.addr=addr 12 self.type=type 13 14 def __repr__(self): 15 return ‘School(%s,%s)‘ %(self.name,self.addr) 16 def __str__(self): 17 return ‘(%s,%s)‘ %(self.name,self.addr) 18 19 def __format__(self, format_spec): 20 # if format_spec 21 if not format_spec or format_spec not in format_dict: 22 format_spec=‘nat‘ 23 fmt=format_dict[format_spec] 24 return fmt.format(obj=self) 25 26 s1=School(‘oldboy1‘,‘北京‘,‘私立‘) 27 print(‘from repr: ‘,repr(s1)) 28 print(‘from str: ‘,str(s1)) 29 print(s1) 30 31 ‘‘‘ 32 str函数或者print函数--->obj.__str__() 33 repr或者交互式解释器--->obj.__repr__() 34 如果__str__没有被定义,那么就会使用__repr__来代替输出 35 注意:这俩方法的返回值必须是字符串,否则抛出异常 36 ‘‘‘ 37 print(format(s1,‘nat‘)) 38 print(format(s1,‘tna‘)) 39 print(format(s1,‘tan‘)) 40 print(format(s1,‘asfdasdffd‘))
1 class B: 2 3 def __str__(self): 4 return ‘str : class B‘ 5 6 def __repr__(self): 7 return ‘repr : class B‘ 8 9 10 b=B() 11 print(‘%s‘%b) 12 print(‘%r‘%b)
__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
1 import time 2 class A: 3 def __init__(self): 4 self.f = open(‘userinfo‘,‘a‘) 5 def consume(self): 6 pass 7 def __del__(self): 8 ‘‘‘在删除一个对象之前做一些收尾工作‘‘‘ 9 self.f.close() 10 print(‘删除一个对象的时候调用我‘) 11 12 a = A() 13 time.sleep(1) 14 del a 15 # 删除一个对象的时候,如果内部存在__del__方法, 16 # 那么在删除一个对象之前先执行__del__方法中的代码 17 print(a) # 报错 name ‘a‘ is not defined
item系列
__getitem__\__setitem__\__delitem__
1 class A: 2 def __init__(self,name): 3 self.name = name 4 self.age = 81 5 def __getitem__(self, item): 6 return self.__dict__[item] 7 def __setitem__(self, key, value): 8 self.__dict__[key] = value 9 def __delitem__(self, key): 10 del self.__dict__[key] 11 a = A(‘alex‘) 12 print(a[‘name‘]) # 对应了类中一个方法的语法 #alex 13 a.name 14 print(a[‘age‘]) # 对应了类中一个方法的语法 #81 15 a.age 16 # 增加 和 修改一个属性 17 a[‘sex‘] = ‘不详‘ 18 a.sex = ‘不详‘ 19 print(a.__dict__) #{‘name‘: ‘alex‘, ‘age‘: 81, ‘sex‘: ‘不详‘} 20 print(a.sex) #不详 21 print(a[‘sex‘]) #不详 22 a[‘sex‘] = ‘女‘ 23 print(a.__dict__) #‘{‘name‘: ‘alex‘, ‘age‘: 81, ‘sex‘: ‘女‘} 24 del a[‘sex‘] 25 print(a.__dict__) #‘name‘: ‘alex‘, ‘age‘: 81}
__new__
1 # 元类 2 # 有一个元类 在创建类 3 # type() 所有直接用class创建出来的类的元类都是type 4 5 # class 类名(B,classMeta = 元类名) 6 # class 类名(B,classMeta = type) # 默认 7 8 # 元类 创造 类 所以所有的类的type都是它的元类,默认是type 9 # 类 创造 对象 具体创造对象的方法 __new__方法,所有的对象的type都是它对应的类 10 11 # python中 一切皆对象 12 # 变量 都有它属于的数据类型
1 class A: 2 def __init__(self): 3 print(‘执行init方法了‘) 4 def __new__(cls): 5 print(‘执行new方法了‘) 6 return object.__new__(cls) # 创造对象,将对象返回 7 8 a = A() 9 print(type(a)) 10 # 执行new方法了 11 # 执行init方法了 12 # <class ‘__main__.A‘> 13 print(type(A)) 14 # 执行new方法了 15 # 执行init方法了 16 # <class ‘type‘> 17 18 # 先执行__new__方法 创造出一个对象 19 # 然后把创造出来的对象传递给__init__方法 20 # 会把self自动的返回,被a接收
1 # 一个类 可以被多次实例化 但是同一时间在python的内存中,只能有一个实例 2 class A: 3 _instance = None 4 def __init__(self,name): 5 ‘‘‘给娃穿衣服‘‘‘ 6 self.name = name 7 def __new__(cls, *args, **kwargs): 8 ‘‘‘生娃的过程‘‘‘ 9 if not A._instance: 10 A._instance = object.__new__(cls) 11 return A._instance 12 a1 = A(‘alex‘) # 第一次实例化的时候创造一个实例 13 print(a1.name) 14 a2 = A(‘egon‘) 15 print(a1.name,a2.name) # ‘alex‘ ‘alex‘
__call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
1 class A: 2 def __call__(self,a): 3 print(‘执行我了‘,a) 4 def call(self,a): 5 print(‘执行我了‘,a) 6 a = A() 7 a(‘abc‘) # __call__ #执行我了 abc 8 a.call(‘aaa‘) #执行我了 aaa
__len__
1 def len(obj): 2 return obj.__len__() 3 print(len(hei)) #4
__eq__
1 class A: 2 def __init__(self,name,cls,age,sex): 3 self.name = name 4 self.cls = cls 5 self.age = age 6 self.sex = sex 7 def __eq__(self, other): 8 # if self.__dict__ == other.__dict__:return True 9 return True 10 def __len__(self): 11 return len(self.__dict__) 12 13 hei = A(‘小黑‘,‘py10期‘,18,‘无‘) 14 hei2 = A(‘小2黑‘,‘py11期‘,17,‘无‘) 15 print(hei.__dict__) #{‘name‘: ‘小黑‘, ‘cls‘: ‘py10期‘, ‘age‘: 18, ‘sex‘: ‘无‘} 16 print(hei2.__dict__) #‘name‘: ‘小2黑‘, ‘cls‘: ‘py11期‘, ‘age‘: 17, ‘sex‘: ‘无‘} 17 print(hei == hei2) #True 18 # 两个对象就算值是完全相等的,但是仍然内存地址不同 19 # == 实际上是比较内存地址的 20 # == 实际上是调用了__eq__方法
__hash__
# hash(obj)函数,obj对象对应的类必然内部实现了__hash__方法 # hash的结果就是__hash__方法的返回值 # 且在一次成的执行过程中是不会发生变化的 # 且要想作为字典的key或者作为集合的元素,这个对象对应的类必须实现__hash__方法
1 # 不可变的数据类型都可以被hash 2 class A:pass 3 # def __hash__(self): 4 # return 1 5 a = A() 6 b = A() 7 8 print(hash(a)) # object.__hash__() 9 print(hash(b)) # object.__hash__()
__format__
1 #_*_coding:utf-8_*_ 2 3 format_dict={ 4 ‘nat‘:‘{obj.name}-{obj.addr}-{obj.type}‘,#学校名-学校地址-学校类型 5 ‘tna‘:‘{obj.type}:{obj.name}:{obj.addr}‘,#学校类型:学校名:学校地址 6 ‘tan‘:‘{obj.type}/{obj.addr}/{obj.name}‘,#学校类型/学校地址/学校名 7 } 8 class School: 9 def __init__(self,name,addr,type): 10 self.name=name 11 self.addr=addr 12 self.type=type 13 14 def __format__(self, format_spec): 15 return format_spec.format(obj=self) 16 17 s1=School(‘oldboy1‘,‘北京‘,‘私立‘) 18 print(format(s1,format_dict[‘tna‘])) #私立:oldboy1:北京 19 print(format(s1,format_dict[‘nat‘])) #oldboy1-北京-私立 20 print(format(s1,format_dict[‘tan‘])) #私立/北京/oldboy1 21 print(format(s1,‘tna‘)) #tna 22 print(format(s1,‘tan‘)) #tan
面试题
1 # 有一个类,对应这个类产生了100个对象 2 # 每个对象有三个属性 : 姓名 年龄 性别 3 # 请对这一百个对象进行去重,如果姓名和性别相同,即便年龄不同也是相同的对象 4 # 问最简便的方法? 5 class Person: 6 def __init__(self,name,age,sex): 7 self.name = name 8 self.age = age 9 self.sex = sex 10 def __hash__(self): 11 return hash(‘%s%s‘%(self.name,self.sex)) 12 def __eq__(self, other): 13 if self.name == other.name and 14 self.sex == other.sex: 15 return True 16 17 p_lst = [] 18 for i in range(100): 19 p_lst.append(Person(‘egon‘,i,‘male‘)) 20 p_lst.append(Person(‘alex‘,i,‘male‘)) 21 p_lst.append(Person(‘yuan‘,i,‘male‘)) 22 print(p_lst) 23 print(set(p_lst)) # 报错不可hash 完成了__hash__ 24 ‘‘‘ 25 # hash是否相等 __hash__ 26 # 值是否相等 __eq__ 27 28 # 收获1 29 # 对于一些python当中已经存在的内置函数 内置数据类型 内置模块中的方法 30 # 都有可能依赖于类中的内置方法 31 # 收获2 32 # set方法依赖集合中元素对象的__hash__ __eq__ 33 ‘‘‘
1 from collections import namedtuple 2 card = namedtuple(‘card‘,[‘num‘,‘col‘]) 3 class A: 4 num = [str(n) for n in range(2,11) ]+ list(‘jqka‘) 5 col = [‘红心‘,‘方板‘,‘梅花‘,‘黑桃‘] 6 def __init__(self): 7 self._cards = [card(num,col) for num in A.num 8 for col in A.col] 9 def __len__(self): 10 return len(self._cards) 11 def __getitem__(self, item): 12 return self._cards[item] 13 def __setitem__(self, key, value): 14 self._cards[key] = value 15 deck = A() 16 print(‘**‘, deck[:]) #打印所有的纸牌 17 from random import choice 18 print(choice(deck)) #打印随机的纸牌 19 # deck对象对应的类中的getitem方法和len方法
以上是关于python之面向对象进阶的主要内容,如果未能解决你的问题,请参考以下文章