python 之 面向对象(元类、__call__、单例模式)
7.13 元类
元类:类的类就是元类,我们用class定义的类来产生我们自己的对象的,内置元类type是用来专门产生class定义的类
code=""" global x x=0 y=2 """ #字符串内声明的名称是全局,其他为局部名称 global_dic={'x':100000} local_dic={} # 运行字符串内代码 exec(code,global_dic,local_dic) # 把全局名称空间的名称放入global_dic,把局部的放入local_dic print(global_dic) #{'x': 0} print(local_dic) #{'y': 2}
7.131 用内置的元类type,来实例化得到我们的类
class_name='Chinese' class_bases=(object,) #基类 class_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 (<class 'object'>,) {'country':'China', '__init__': <function __init__ at ...>, 'speak': <function speak at....>} Chinese=type(class_name,class_bases,class_dic) #实例化一个类 print(Chinese) #<class '__main__.Chinese'> p=Chinese('egon',18,'male') #实例化对象p print(p.name,p.age,p.sex) # egon 18 male #说明和class定义的类功能相同
7.132 __call__
方法
在调用对象时自动触发__call__
的执行
class Foo: def __init__(self): pass def __call__(self, *args, **kwargs):# 调用对象,则会自动触发对象下的绑定方法__call__的执行, print('__call__',*args, **kwargs)# 然后将对象本身当作第一个参数传给self,将调用对象时括号内的值传给*args与**kwargs obj=Foo() obj(1,2,3,a=1,b=2,c=3) #对象调用
7.133 自定义元类来控制类的创建行为
class Mymeta(type): 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=Mymeta('Foo',(object,),class_dic) class Foo(object,metaclass=Mymeta): # metaclass=Mymeta创建自定义元类 """ 文档注释 """
7.134 自定义元类来控制类的调用
控制类Foo的调用过程,即控制实例化Foo的过程
class Mymeta(type): def __init__(self,class_name,class_bases,class_dic): #self=Foo print(class_name) print(class_bases) print(class_dic) def __call__(self, *args, **kwargs): #self=Foo,args=(1111,) 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) #<__main__.Foo object at 0x000002019EE1BB70> print(obj.y) # 1111 print(obj.f1) #<bound method Foo.f1 of <__main__.Foo object at 0x000002019EE1BB70>> print(obj.x) # 1
7.14 单例模式
对于对象通过相同的配置文件进行实例化,可以使几个对象使用同一个内存地址,节省内存
import settings 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.singleton() # obj4=MySQL(settings.IP,settings.PORT) obj5=MySQL.singleton() obj6=MySQL.singleton() print(obj4.ip,obj4.port) # 1.1.1.1 3306 print(obj4 is obj5 is obj6) # True