1、isinstance和issubclass
1)、isinstance(obj,cls)检查是否obj是否是类 cls 的对象
print(obj.__dict__) #由于报错无法执行 class Foo(object): pass obj = Foo() print(isinstance(obj, Foo)) #True
2)、issubclass(sub, super)检查sub类是否是 super 类的派生类
class Foo(object): pass class Bar(Foo): pass print(issubclass(Bar, Foo)) #True
一、反射
1、什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
2、面向对象中的反射的定义
通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
3、实现反射的4个内置函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
#内置函数:hasattr/getattr/setattr/delattr class Foo: f = '类的静态变量' def __init__(self,name,age): self.name=name self.age=age def say_hi(self): print('hi,%s'%self.name) obj=Foo('egon',73) #1、hasattr 检测是否含有某属性 print(hasattr(obj,'name')) #True print(hasattr(obj,'say_hi')) #True #2、getattr 获取属性 n=getattr(obj,'name') print(n) #egon func=getattr(obj,'say_hi') func() #hi,egon print(getattr(obj,'aaaaaaaa','不存在啊')) #不存在啊 #3、setattr 设置属性 setattr(obj,'sb',True) setattr(obj,'show_name',lambda self:self.name+'sb') print(obj.__dict__) #{'name': 'egon', 'age': 73, 'sb': True, 'show_name': <function <lambda> at 0x0000026061C8AAE8>} print(obj.show_name(obj)) #egonsb #4、delattr 删除属性 delattr(obj,'age') delattr(obj,'show_name') delattr(obj,'show_name111')#不存在,则报错 #报错信息:delattr(obj,'show_name111')#不存在,则报错
class Foo(object): staticField = "old boy" def __init__(self): self.name = 'wupeiqi' def func(self): return 'func' @staticmethod def bar(): return 'bar' print(getattr(Foo, 'staticField')) #old boy print(getattr(Foo, 'func')) #<function Foo.func at 0x00000250E23EAC80> print(getattr(Foo, 'bar')) #<function Foo.bar at 0x00000250E23EAD08>
#!/usr/bin/env python # -*- coding:utf-8 -*- import sys def s1(): print('s1') def s2(): print('s2') #获取当前模块的名字 this_module = sys.modules[__name__] print(hasattr(this_module, 's1')) #True print(getattr(this_module, 's2')) #<function s2 at 0x0000023BABB4AB70>
导入其他模块,利用反射查找该模块是否存在某个方法
#!/usr/bin/env python # -*- coding:utf-8 -*- def test(): print('from the test')
#!/usr/bin/env python # -*- coding:utf-8 -*- """ 程序目录: module_test.py index.py 当前文件: index.py """ import module_test as obj #obj.test() # 判断test是否属于obj的属性或方法 print(hasattr(obj,'test')) #True getattr(obj,'test')() #直接执行test()方法 #结果:from the test
反射总结
# hasattr 判断某一个 变量 是否能够.调用一个名字,返回True或者False # getattr 直接获取一个变量中的名字的值 # setattr 为一个变量增加或者修改一个属性 # delattr 删除一个变量中的属性或者方法 # 反射类中的名字 # getattr(类名,'静态属性') # getattr(类名,'类方法')() # getattr(类名,'静态方法')() # 反射对象中的名字 # getattr(对象名,'对象属性') # getattr(对象名,'方法名')() # 反射模块中的名字 # import 模块名 # getattr(模块名,'模块中的变量') # getattr(模块名,'模块中的函数')() # getattr(模块名,'模块中的类名') # 反射当前模块中的名字 # import sys # getattr(sys.modules[__name__],'变量') # getattr(sys.modules[__name__],'函数')() # getattr(sys.modules[__name__],'类名')
二、特殊的内置方法函数
1、__str__和__repr__
改变对象的字符串显示__str__,__repr__
自定制格式化字符串__format__
#_*_coding:utf-8_*_ format_dict={ 'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型 'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址 'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名 } class School: def __init__(self,name,addr,type): self.name=name self.addr=addr self.type=type def __repr__(self): return 'School(%s,%s)' %(self.name,self.addr) def __str__(self): return '(%s,%s)' %(self.name,self.addr) def __format__(self, format_spec): # if format_spec if not format_spec or format_spec not in format_dict: format_spec='nat' fmt=format_dict[format_spec] return fmt.format(obj=self) s1=School('oldboy1','北京','私立') print('from repr: ',repr(s1)) #from repr: School(oldboy1,北京) print('from str: ',str(s1)) #from str: (oldboy1,北京) print(s1) #(oldboy1,北京) ''' str函数或者print函数--->obj.__str__() repr或者交互式解释器--->obj.__repr__() 如果__str__没有被定义,那么就会使用__repr__来代替输出 注意:这俩方法的返回值必须是字符串,否则抛出异常 ''' print(format(s1,'nat')) #oldboy1-北京-私立 print(format(s1,'tna')) #私立:oldboy1:北京 print(format(s1,'tan')) #私立/北京/oldboy1 print(format(s1,'asfdasdffd')) #oldboy1-北京-私立
class B: def __str__(self): return 'str : class B' def __repr__(self): return 'repr : class B' b=B() print('%s'%b) #str : class B print('%r'%b) #repr : class B
2、__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
# 构造方法 创建一个对象的初始化方法 __init__ 给已经创建出来的对象添加属性 # 析构方法 删除一个对象的时候调用的方法 class A: #初始化方法 def __init__(self): pass #析构方法 def __del__(self): print('删除一个对象是调用我') a = A() del a #输出结果: 删除一个对象是调用我
import time class A: #初始化方法 def __init__(self): pass #析构方法 def __del__(self): '''在删除一个对象之前做一些收尾工作''' print('删除一个对象的时候调用我') a = A() time.sleep(1) #输出结果: 删除一个对象是调用我 # 删除一个对象的时候,如果内部存在__del__方法, # 那么在删除一个对象之前先执行__del__方法中的代码
3、item系列
__getitem__/__setitem__/__delitem__
#__xxxitem__:使用 [''] 的方式操作属性时被调用 class Foo: #初始化方法 def __init__(self,name): self.name=name #当访问不存在的属性时会调用该方法 def __getitem__(self, item): print(self.__dict__[item]) #:每当属性被赋值的时候都会调用该方法,因此不能再该方法内赋值 self.name = value 会死循环 def __setitem__(self, key, value): self.__dict__[key]=value #当删除属性时调用该方法 def __delitem__(self, key): print('del obj[key]时,我执行') self.__dict__.pop(key) #删除指定对象的指定名称的属性 def __delattr__(self, item): print('del obj.key时,我执行') self.__dict__.pop(item) #实例化对象 f1=Foo('sb') f1['age']=18 f1['age1']=19 print(f1.__dict__) #{'name': 'sb', 'age': 18, 'age1': 19} del f1.age1 #del obj.key时,我执行 del f1['age'] #del obj[key]时,我执行 f1['name']='alex' print(f1.__dict__) #{'name': 'alex'}
4、__new__
构造方法,当实例化对象时,会优先自动执行该方法
# new一个对象 # object.__new__() class A: def __init__(self): print('执行init方法') def __new__(cls): print('执行new方法') #创造对象 将对象返回 return object.__new__(cls) a = A() #输出结果: # 执行new方法 # 执行init方法 print(type(a)) #<class '__main__.A'> print(type(A)) #<class 'type'> # 先执行__new__方法 创造出一个对象 # 然后把创造出来的对象传递给__init__方法 # 会把self自动的返回,被a接收 # 元类 # 有一个元类 在创建类 # type() 所有直接用class创建出来的类的元类都是type # class 类名(B,classMeta = 元类名) # class 类名(B,classMeta = type) # 默认 # 元类 创造 类 所以所有的类的type都是它的元类,默认是type # 类 创造 对象 具体创造对象的方法 __new__方法,所有的对象的type都是它对应的类 # python中 一切皆对象 # 变量 都有它属于的数据类型
#单例模式 class Singleton: def __new__(cls, *args, **kw): if not hasattr(cls, '_instance'): cls._instance = object.__new__(cls, *args, **kw) return cls._instance #实例化对象 one = Singleton() two = Singleton() two.a = 3 print(one.a) # 3 # one和two完全相同,可以用id(), ==, is检测 print(id(one)) # 2363725443368 print(id(two)) # 2363725443368 print(one == two) # True print(one is two) # True
# 设计模式 # 单例模式 # 一个类 可以被多次实例化 但是同一时间在python的内存中,只能有一个实例 class A: _instance = None #静态变量 #初始化方法 def __init__(self, name): '''给娃娃穿衣服''' self.name = name #构造方法 def __new__(cls, *args, **kwargs): '''生娃的过程''' if not A._instance: A._instance = object.__new__(cls) return A._instance a1 = A('alex') #第一次实例化的时候创造一个实例 print(a1.name) #alex a2 = A('egon') print(a1.name, a2.name) #egon egon #第二种方法 class B: #初始化方法 def __init__(self,name): '''给娃穿衣服''' self.name = name #构造方法 def __new__(cls, *args, **kwargs): '''生娃的过程''' if not hasattr(B, '_instance'): B._instance = object.__new__(cls) return B._instance a1 = B('alex') # 第一次实例化的时候创造一个实例 print(a1.name) #alex a2 = B('egon') print(a1.name,a2.name) #egon egon
5、__call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo: #初始化方法 def __init__(self): print('执行__init__') #构造方法 def __call__(self, *args, **kwargs): print('执行__call__') #常规方法 def call(self): print('执行call') obj = Foo() # 执行__init__ obj() # 执行__call__ obj.call() # 执行call
6、__len__
class A: def __init__(self): self.a = 1 self.b = 2 def __len__(self): return len(self.__dict__) a = A() print(len(a)) #2
7、__hash__
class A: def __init__(self): self.a = 1 self.b = 2 def __hash__(self): return hash(str(self.a)+str(self.b)) a = A() print(hash(a)) #-8485950673113911502
8、__eq__
class A: def __init__(self): self.a = 1 self.b = 2 #是==的内置方法 def __eq__(self,obj): if self.a == obj.a and self.b == obj.b: return True a = A() b = A() print(a == b) #True
from collections import namedtuple Card = namedtuple('Card',['rank','suit']) class FranchDeck: ranks = [str(n) for n in range(2,11)] + list('JQKA') suits = ['红心','方板','梅花','黑桃'] #初始化方法 构造纸牌的列表 def __init__(self): self._cards = [Card(rank,suit) for rank in FranchDeck.ranks for suit in FranchDeck.suits] #计算纸牌的张数 def __len__(self): return len(self._cards) #返回纸牌列表的某张纸牌 def __getitem__(self, item): return self._cards[item] #纸牌实例化 deck = FranchDeck() print(deck[0]) #Card(rank='2', suit='红心') #随机抽牌 from random import choice print(choice(deck)) #Card(rank='A', suit='红心') print(choice(deck)) #Card(rank='K', suit='方板')
#可命名元组 from collections import namedtuple Card = namedtuple('Card',['rank','suit']) #纸牌类 class FranchDeck: ranks = [str(n) for n in range(2,11)] + list('JQKA') suits = ['红心','方板','梅花','黑桃'] #初始化方法 构造纸牌的列表 def __init__(self): self._cards = [Card(rank,suit) for rank in FranchDeck.ranks for suit in FranchDeck.suits] #计算纸牌的张数 def __len__(self): return len(self._cards) #返回纸牌列表的某张纸牌 def __getitem__(self, item): return self._cards[item] #增加或修改纸牌 def __setitem__(self, key, value): self._cards[key] = value #实例化纸牌对象 deck = FranchDeck() print(deck[0]) #Card(rank='2', suit='红心') #随机抽牌 from random import choice print(choice(deck)) #Card(rank='7', suit='梅花') print(choice(deck)) #Card(rank='Q', suit='梅花') #随机洗牌 from random import shuffle shuffle(deck) print(deck[:5]) #输出结果 #[Card(rank='2', suit='红心'), Card(rank='8', suit='梅花'), Card(rank='6', suit='黑桃'), # Card(rank='5', suit='方板'), Card(rank='5', suit='梅花')]