python3全栈开发-内置函数补充,反射,元类,__str__,__del__,exec,type,__call__方法
一、内置函数补充
1、isinstance(obj,cls)检查是否obj是否是类 cls 的对象
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面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数:
hasattr、getattr、setattr、delattr
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
# 1、hasattr # print(hasattr(People,'country')) #True # print('country' in People.__dict__) #不知道hasattr方法时,用的方法 # print(hasattr(obj,'name')) #True # print(hasattr(obj,'country')) #True # print(hasattr(obj,'tell')) #True # 2、getattr # x=getattr(People,'country1',None) #查找指定属性,没有此属性(提前预防报错写None)显示None,有就返回值 # print(x) # f=getattr(obj,'tell',None)#obj.tell # print(f == obj.tell) #True # f() #正常的调用函数 # obj.tell() # 3、setattr # People.x=111 # setattr(People,'x',111) #添加x属性,值为111 # print(People.x) # obj.age=18 # setattr(obj,"age",18) # 添加age属性,值为18 # print(obj.__dict__) # 4、delattr # del People.country #原始的方法 # delattr(People,"country") # print(People.__dict__) # del obj.name # delattr(obj,"name") # print(obj.__dict__)
三、__str__
class People: def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def __str__(self): # print('========>') return '<名字:%s 年龄:%s 性别:%s>' %(self.name,self.age,self.sex) obj=People('duoduo',18,'male') print(obj) #print(obj.__str__()) 在print时触发__str__
四、__del__
当对象在内存中被释放时,自动触发执行。
注:如果产生的对象仅仅只是python程序级别的(用户级),那么无需定义__del__,如果产生的对象的同时还会向操作系统发起系统调用,即一个对象有用户级与内核级两种资源
import time class People: def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def __del__(self): # 在对象被删除的条件下,自动执行 print('__del__') obj=People('duoduo',18,'male') #del obj #obj.__del__() #先删除的情况下,直接执行__del__ time.sleep(5) #可以更形象的看出在资源回收前执行__del__
典型的应用场景:
创建数据库类,用该类实例化出数据库链接对象,对象本身是存放于用户空间内存中,而链接则是由操作系统管理的,存放于内核空间内存中
当程序结束时,python只会回收自己的内存空间,即用户态内存,而操作系统的资源则没有被回收,这就需要我们定制__del__,在对象被删除前向操作系统发起关闭数据库链接的系统调用,回收资源
这与文件处理是一个道理:
f=open('a.txt') #做了两件事,在用户空间拿到一个f变量,在操作系统内核空间打开一个文件 del f #只回收用户空间的f,操作系统的文件还处于打开状态 #所以我们应该在del f之前保证f.close()执行,即便是没有del,程序执行完毕也会自动del清理资源,于是文件操作的正确用法应该是 f=open('a.txt') 读写... f.close() #很多情况下大家都容易忽略f.close,这就用到了with上下文管理 class MyOpen: #自己写个打开读文件类,封装内置的open def __init__(self,filepath,mode="r",encoding="utf-8"): self.filepath=filepath self.mode=mode self.encoding=encoding self.fobj=open(filepath,mode=mode,encoding=encoding) #申请系统内存 def __str__(self): msg=""" filepath:%s mode:%s encoding:%s """ %(self.filepath,self.mode,self.encoding) return msg def __del__(self): self.fobj.close() f=MyOpen('aaa.py',mode='r',encoding='utf-8') # print(f.filepath,f.mode,f.encoding) # print(f) # print(f.fobj) res=f.fobj.read() #一样可以读 print(res)
五、exec
#例子 一 code=""" #global x #shsh声明x为全局变量 x=0 y=2 """ global_dic={'x':100000} local_dic={} #字符串中声明全局就是全局,不声明就是局部 exec(code,global_dic,local_dic) # # print(global_dic) # print(local_dic) #例子 二 # code=""" # x=1 # y=2 # def f1(self,a,b): # pass # """ # local_dic={} # exec(code,{},local_dic) # print(local_dic)
六、元类
1、什么是元类:
类的类就是元类
#我们用class定义的类使用来产生我们自己的对象的
#内置元类type是用来专门产生class定义的类的
#一切皆为对象: # Chinese=type(...) class Chinese: country="China" def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def speak(self): print('%s speak Chinese' %self.name) # print(Chinese) # p=Chinese('duoduo',18,'male') # print(type(p)) #最上层的类 type # print(type(Chinese))
2、用内置的元类type,来实例化得到我们的类
#2、用内置的元类type,来实例化得到我们的类 class_name='Chinese' class_bases=(object,) lass_body=""" country="China" def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def speak(self): print('%s speak Chinese' %self.name) """ class_dic={} exec(class_body,{},class_dic) #类的三大要素 # print(class_name,class_bases,class_dic) Chinese=type(class_name,class_bases,class_dic) # print(Chinese) p=Chinese('duoduo',18,'male') # print(p.name,p.age,p.sex)
3、 __call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo: def __init__(self): pass def __str__(self): return '' def __del__(self): pass # 调用对象,则会自动触发对象下的绑定方法__call__的执行, # 然后将对象本身当作第一个参数传给self,将调用对象时括号内的值 #传给*args与**kwargs def __call__(self, *args, **kwargs): print('__call__',args,kwargs) obj=Foo() # print(obj) obj(1,2,3,a=1,b=2,c=3) #
4、自定义元类
class Mymeta(type): # 来控制类Foo的创建 def __init__(self,class_name,class_bases,class_dic): #self=Foo # print(class_name) # print(class_bases) # print(class_dic) if not class_name.istitle(): #加上判断 raise TypeError('类名的首字母必须大写') if not class_dic.get('__doc__'): raise TypeError('类中必须写好文档注释') super(Mymeta,self).__init__(class_name,class_bases,class_dic) # 控制类Foo的调用过程,即控制实例化Foo的过程 def __call__(self, *args, **kwargs): #self=Foo,args=(1111,) kwargs={} # print(self) # print(args) # print(kwargs) #1 造一个空对象obj obj=object.__new__(self) #2、调用Foo.__init__,将obj连同调用Foo括号内的参数一同传给__init__ self.__init__(obj,*args,**kwargs) return obj #Foo=Mymeta('Foo',(object,),class_dic) class Foo(object,metaclass=Mymeta): """ 文档注释 """ x=1 def __init__(self,y): self.Y=y def f1(self): print('from f1') obj=Foo(1111) #Foo.__call__() # print(obj) # print(obj.y) # print(obj.f1) # print(obj.x)
5、单例模式
import settings #调用配置文件的IP,PORT class MySQL: __instance=None def __init__(self,ip,port): self.ip=ip self.port=port @classmethod #绑定方法 def singleton(cls): if not cls.__instance: obj=cls(settings.IP, settings.PORT) cls.__instance=obj return cls.__instance obj1=MySQL('1.1.1.2',3306) obj2=MySQL('1.1.1.3',3307) obj3=MySQL('1.1.1.4',3308) # obj4=MySQL(settings.IP,settings.PORT) # print(obj4.ip,obj4.port) obj4=MySQL.singleton() obj5=MySQL.singleton() obj6=MySQL.singleton() print(obj4 is obj5 is obj6) #Ture