isinstance(obj,cls) 检查obj是不是cls的实例python
issubclass(obj,cls) 检查obj是不是cls的继承类程序员
经过字符串的形式操做对象的相关的属性。app
主要是指程序能够访问、检测和修改它自己状态或行为的一种能力(自省)this
hasattr(obj,name) 检查obj下是否有叫name属性,name必须字符串 getattr(obj,name,default=None) 查询obj下的属性,有返回name对应的参数,没有返回default setattr(obj,x,y) 给obj设置属性,x必须字符串 delattr(obj,x) 删除obj下的属性,x必须字符串
示例:code
class BlackMedium: feature='Ugly' def __init__(self,name,addr): self.name=name self.addr=addr def sell_house(self): print('%s 黑中介卖房子啦,傻逼才买呢,可是谁能证实本身不傻逼' %self.name) def rent_house(self): print('%s 黑中介租房子啦,傻逼才租呢' %self.name) b1=BlackMedium('万成置地','回龙观天露园') #检测是否含有某属性 print(hasattr(b1,'name')) print(hasattr(b1,'sell_house')) #获取属性 n=getattr(b1,'name') print(n) func=getattr(b1,'rent_house') func() # getattr(b1,'aaaaaaaa') #报错 print(getattr(b1,'aaaaaaaa','不存在啊')) #设置属性 setattr(b1,'sb',True) setattr(b1,'show_name',lambda self:self.name+'sb') print(b1.__dict__) print(b1.show_name(b1)) #删除属性 delattr(b1,'addr') delattr(b1,'show_name') delattr(b1,'show_name111')#不存在,则报错 print(b1.__dict__)
好处一:实现可插拔机制orm
有俩程序员,一个lili,一个是egon,lili在写程序的时候须要用到egon所写的类, 可是egon去跟女友度蜜月去了,尚未完成他写的类,lili想到了反射,使用了反射机制lili能够继续完成本身的代码, 等egon度蜜月回来后再继续完成类的定义而且去实现lili想要的功能。 总之反射的好处就是,能够事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用, 这实际上是一种‘后期绑定’,什么意思?即你能够事先把主要的逻辑写好(只定义接口),而后后期再去实现接口的功能
好处二:动态导入模块(基于反射当前模块成员)对象
在模块中导入本身: this_modul=sys.modules[__name__] 使用字符串导入模块: 一、__import__("time") 二、import importlib importlib.import_module("time") 推荐使用第二种
设置属性的时候会触发。实质是操做类.__dict__
删除类的属性时会触发,实质是操做类.__dict__
调用类中不存在的属性时会触发。
三者的用法演示:继承
class Foo: x=1 def __init__(self,y): self.y=y def __getattr__(self, item): print('----> from getattr:你找的属性不存在') def __setattr__(self, key, value): print('----> from setattr') # self.key=value #这就无限递归了,你好好想一想 # self.__dict__[key]=value #应该使用它 def __delattr__(self, item): print('----> from delattr') # del self.item #无限递归了 self.__dict__.pop(item) #__setattr__添加/修改属性会触发它的执行 f1=Foo(10) print(f1.__dict__) # 由于你重写了__setattr__,凡是赋值操做都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操做属性字典,不然永远没法赋值 f1.z=3 print(f1.__dict__) #__delattr__删除属性的时候会触发 f1.__dict__['a']=3#咱们能够直接修改属性字典,来完成添加/修改属性的操做 del f1.a print(f1.__dict__) #__getattr__只有在使用点调用属性且属性不存在的时候才会触发 f1.xxxxxx
做用同上。只不过是调用的时候__setattr__那中方法是用 . 去调用。而这种是用["值"]的方式去调用。递归
class Foo: x = 1 def __init__(self, y): self.y = y def __getitem__(self, item): #执行对象[属性],找不到属性的时候会执行这个代码。 print('----> from getattr:你找的属性不存在') def __setitem__(self, key, value): #执行对象[属性]=值,的时候会执行这个代码 self.__dict__[key]=value def __delitem__(self, item): #执行 del 对象[属性] 的时候会执行这个代码。 self.__dict__.pop(item) f1 = Foo(10) #初始化触发init print(f1.__dict__) f1["z"]=3 #赋值触发setitem print(f1.__dict__) f1["a"] #查找不存在的属性,触发getitem f1.__dict__['a'] = 3 del f1["a"] #删除触发delitem print(f1.__dict__)
class List(list): #继承list全部的属性,也能够派生出本身新的,好比append和mid def append(self, p_object): if not isinstance(p_object,int): #' 派生本身的append:加上类型检查' raise TypeError('must be int') super().append(p_object) @property def mid(self): '新增本身的属性' index=len(self)//2 return self[index] l=List([1,2,3,4]) print(l) l.append(5) print(l) # l.append('1111111') #报错,必须为int类型 print(l.mid) #其他的方法都继承list的 l.insert(0,-123) print(l) l.clear() print(l)
import time class FileHandle: def __init__(self,filename,mode='r',encoding='utf-8'): self.file=open(filename,mode,encoding=encoding) def write(self,line): t=time.strftime('%Y-%m-%d %T') self.file.write('%s %s' %(t,line)) def __getattr__(self, item): return getattr(self.file,item) f1=FileHandle('b.txt','w+') f1.write('你好啊') f1.seek(0) print(f1.read()) f1.close() #重写list class List: def __init__(self,seq): self.seq=seq def append(self, p_object): ' 派生本身的append加上类型检查,覆盖原有的append' if not isinstance(p_object,int): raise TypeError('must be int') self.seq.append(p_object) def clear(self): if not self.permission: raise PermissionError('not allow the operation') self.seq.clear() @property def mid(self): '新增本身的方法' index=len(self.seq)//2 return self.seq[index] def __getattr__(self, item): return getattr(self.seq,item) def __str__(self): return str(self.seq) l=List([1,2,3]) print(l) l.append(4) print(l) # l.append('3333333') #报错,必须为int类型 print(l.mid) #基于受权,得到insert方法 l.insert(0,-123) print(l)
date_dic={ 'ymd':'{0.year}:{0.month}:{0.day}', 'dmy':'{0.day}/{0.month}/{0.year}', 'mdy':'{0.month}-{0.day}-{0.year}', } class Date: def __init__(self,year,month,day): self.year=year self.month=month self.day=day def __format__(self, format_spec): if not format_spec or format_spec not in date_dic: 若是输入的为空或者输入的格式不在规定的字典中,赋予默认格式 format_spec='ymd' fmt=date_dic[format_spec] return fmt.format(self) d1=Date(2016,12,29) print(format(d1)) #默认输出模式 print('{:mdy1}'.format(d1)) #没有mdy1这个模式。因此默认ymd模式输出 print('{:mdy}'.format(d1)) #mdy输出模式 print(format(d1,"dmy")) #dmy输出模式 print("{:dmy}".format(d1)) #dmy输出模式,同上
from collections import Iterable(可迭代对象),Iterator(迭代器) class Foo: def __init__(self,start=0,stop=0): self.start=start self.stop=stop self.con=0 def __iter__(self): return self def __next__(self): if self.con >= self.start and self.start >=self.stop : raise StopIteration if self.stop==0: if self.con < self.start: n = self.con self.con += 1 return n else: self.con=self.stop n=self.start self.start+=1 return n f=Foo(1,6) print(isinstance(f,Iterator)) #判断f是不是迭代器 for i in Foo(1,6): print(i) for i in Foo(6): print(i)
class Foo: '我是描述信息' pass print(Foo.__doc__) 输出:'我是描述信息'
这个属性没法被继承接口
class Open: def __init__(self,name,mode="w"): self.x=open(name,mode=mode) self.name=name self.mode=mode def __enter__(self): #出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量 return self def __exit__(self, exc_type, exc_val, exc_tb): #with中代码块执行完毕后执行 print("exc_type",exc_type) #捕获异常。获取异常的各个信息。 print("exc_val",exc_val) print("exc_tb",exc_tb) return True def write(self,value): self.x.write(value) def __getattr__(self, item): return getattr(self.x,item) # a=Open("a.txt","r") # print(a.read()) # a.seek(0) # print(a.read()) with Open("a.txt","r") as f: print(f.read()) raise TypeError("error!") print("-------------------------")
对象后面加括号,触发执行。
注:构造方法的执行是由建立对象触发的,即:对象 = 类名() ;而对于 call 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print('__call__') obj = Foo() # 执行 __init__ obj() # 执行 __call__
元类是类的类,是类的模板
元类是用来控制如何建立类的,正如类是建立对象的模板同样
type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象
方式一:
1 class Foo: 2 def func(self): 3 print('from func')
方式二:
1 def func(self): 2 print('from func') 3 x=1 4 Foo=type('Foo',(object,),{'func':func,'x':1})
class B(type): def __init__(self,name,bases=None,dict=None): print("init B") self.name=name def __call__(self, *args, **kwargs): print("call") obj=self.__new__(self) self.__init__(obj,*args,**kwargs) return obj class A(object,metaclass=B): def __init__(self,name): print("init A") self.name=name def __new__(cls, *args, **kwargs): print("new A") return super().__new__(cls) a=A("name1") print(a.__dict__)
class Mytype(type): def __init__(self,what,bases=None,dict=None): print(what,bases,dict) def __call__(self, *args, **kwargs): print('--->') obj=object.__new__(self) self.__init__(obj,*args,**kwargs) return obj class Room(metaclass=Mytype): def __init__(self,name): self.name=name r1=Room('alex') print(r1.__dict__)
class Mymeta(type): def __init__(self,name,bases,dic): print('===>Mymeta.__init__') def __new__(cls, *args, **kwargs): print('===>Mymeta.__new__') return type.__new__(cls,*args,**kwargs) def __call__(self, *args, **kwargs): print('aaa') obj=self.__new__(self) self.__init__(self,*args,**kwargs) return obj class Foo(object,metaclass=Mymeta): def __init__(self,name): self.name=name def __new__(cls, *args, **kwargs): return object.__new__(cls) ''' 须要记住一点:名字加括号的本质(即,任何name()的形式),都是先找到name的爹,而后执行:爹.__call__ 而爹.__call__通常作两件事: 1.调用name.__new__方法并返回一个对象 2.进而调用name.__init__方法对儿子name进行初始化 ''' ''' class 定义Foo,并指定元类为Mymeta,这就至关于要用Mymeta建立一个新的对象Foo,因而至关于执行 Foo=Mymeta('foo',(...),{...}) 所以咱们能够看到,只定义class就会有以下执行效果 ===>Mymeta.__new__ ===>Mymeta.__init__ 实际上class Foo(metaclass=Mymeta)是触发了Foo=Mymeta('Foo',(...),{...})操做, 遇到了名字加括号的形式,即Mymeta(...),因而就去找Mymeta的爹type,而后执行type.__call__(...)方法 因而触发Mymeta.__new__方法获得一个具体的对象,而后触发Mymeta.__init__方法对对象进行初始化 ''' ''' obj=Foo('egon') 的原理同上 ''' ''' 总结:元类的难点在于执行顺序很绕,其实咱们只须要记住两点就能够了 1.谁后面跟括号,就从谁的爹中找__call__方法执行 type->Mymeta->Foo->obj Mymeta()触发type.__call__ Foo()触发Mymeta.__call__ obj()触发Foo.__call__ 2.__call__内按前后顺序依次调用儿子的__new__和__init__方法 '''