一、元类的介绍
1、知识储备--了解exec
# exec''' 参数一:字符串形式的命令 参数二:全局作用域(字典形式),如果不指定默认就使用globals() 参数三:局部作用域(字典形式),如果不指定默认就使用locals()'''
1.1、示例:
g = { 'a':6, 'b':8}l = {}exec('''global a,ia = 66i = 99y = 100''',g,l)print(g)# {'a': 66, 'b': 8, '__builtins__': {'__name__': 'builtins', '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", '__package__': '', '__loader__':, '__spec__': ModuleSpec(name='builtins', loader= ), '__build_class__': , '__import__': , 'abs': , 'all': , 'any': , 'ascii': , 'bin': , 'callable': , 'chr': , 'compile': , 'delattr': , 'dir': , 'divmod': , 'eval': , 'exec': , 'format': , 'getattr': , 'globals': , 'hasattr': , 'hash': , 'hex': , 'id': , 'input': , 'isinstance': , 'issubclass': , 'iter': , 'len': , 'locals': , 'max': , 'min': , 'next': , 'oct': , 'ord': , 'pow': , 'print': , 'repr': , 'round': , 'setattr': , 'sorted': , 'sum': , 'vars': , 'None': None, 'Ellipsis': Ellipsis, 'NotImplemented': NotImplemented, 'False': False, 'True': True, 'bool': , 'memoryview': , 'bytearray': , 'bytes': , 'classmethod': , 'complex': , 'dict': , 'enumerate': , 'filter': , 'float': , 'frozenset': , 'property': , 'int': , 'list': , 'map': , 'object': , 'range': , 'reversed': , 'set': , 'slice': , 'staticmethod': , 'str': , 'super': , 'tuple': , 'type': , 'zip': , '__debug__': True, 'BaseException': , 'Exception': , 'TypeError': , 'StopAsyncIteration': , 'StopIteration': , 'GeneratorExit': , 'SystemExit': , 'KeyboardInterrupt': , 'ImportError': , 'ModuleNotFoundError': , 'OSError': , 'EnvironmentError': , 'IOError': , 'WindowsError': , 'EOFError': , 'RuntimeError': , 'RecursionError': , 'NotImplementedError': , 'NameError': , 'UnboundLocalError': , 'AttributeError': , 'SyntaxError': , 'IndentationError': , 'TabError': , 'LookupError': , 'IndexError': , 'KeyError': , 'ValueError': , 'UnicodeError': , 'UnicodeEncodeError': , 'UnicodeDecodeError': , 'UnicodeTranslateError': , 'AssertionError': , 'ArithmeticError': , 'FloatingPointError': , 'OverflowError': , 'ZeroDivisionError': , 'SystemError': , 'ReferenceError': , 'BufferError': , 'MemoryError': , 'Warning': , 'UserWarning': , 'DeprecationWarning': , 'PendingDeprecationWarning': , 'SyntaxWarning': , 'RuntimeWarning': , 'FutureWarning': , 'ImportWarning': , 'UnicodeWarning': , 'BytesWarning': , 'ResourceWarning': , 'ConnectionError': , 'BlockingIOError': , 'BrokenPipeError': , 'ChildProcessError': , 'ConnectionAbortedError': , 'ConnectionRefusedError': , 'ConnectionResetError': , 'FileExistsError': , 'FileNotFoundError': , 'IsADirectoryError': , 'NotADirectoryError': , 'InterruptedError': , 'PermissionError': , 'ProcessLookupError': , 'TimeoutError': , 'open': , 'quit': Use quit() or Ctrl-Z plus Return to exit, 'exit': Use exit() or Ctrl-Z plus Return to exit, 'copyright': Copyright (c) 2001-2017 Python Software Foundation.print(l) # {'y': 100}
2、Python中一切皆对象,对象有哪些用法?
1、都可以被引用 2、都可以当作函数的参数传入 3、都可以当作函数的返回值 4、都可以当作容器类的元素(所谓容器就是可以盛放一连串元素的类型,如列表字典元组集合等)
3、类也是对象,产生类的类称之为元类,默认所有用class定义的类,他们的元类是type
class Func: passobj = Func()print(type(obj)) #print(type(Func)) # class Bar: passprint(type(Bar)) #
4、定义类的两种方式
4.1 方式一:class关键字
示例:
class Chinese1: country = 'China' def __init__(self,name,age): self.name = name self.age = age def chat(self): print('%s is chating now'%self.name)print(Chinese1) #obj1 = Chinese1('cc',21)print(obj1,obj1.name,obj1.age) # <__main__.Chinese1 object at 0x00000240924237B8> cc 21
4.2 方式二:type
定义类的三要素:类名,类的基类,类的名称空间
示例:
class_name = 'Chinese2'class_bases = (object,)class_body='''country='China'def __init__(self,name,age): self.name = name self.age = agedef chat(self): print('%s is chating now'%self.name)'''class_dic = {}exec(class_body,globals(),class_dic)print(class_dic)# {'country': 'China', '__init__':, 'chat': }Chinese2 = type(class_name,class_bases,class_dic)print(Chinese2)obj2 = Chinese2('cc',21)print(obj2,obj2.name,obj2.age) # <__main__.Chinese2 object at 0x0000024092423320> cc 21
二、自定义元类以控制类的创建行为
class Mymeta(type): def __init__(self,class_name,class_bases,class_dic): # print(class_name) # Chinese # print(class_bases) # (,) # print(class_dic) if not class_name.istitle(): raise TypeError('类名首字母应大写!') if not '__doc__' or not class_dic['__doc__'].strip(): raise TypeError('必须加注释') super(Mymeta,self).__init__(class_name,class_bases,class_dic) # 重用父类中的方法class Chinese(object,metaclass=Mymeta): # metaclass= 表示指定元类 ''' 由元类Mymeta控制类的创建行为 ''' country = 'China' def __init__(self,name,age): self.name = name self.age = age def chat(self): print('%s is chating now'%self.name)#Chinese = Mymeta(class_name,class_bases,class_dic)
三、自定义元类控制类的实例化
1、前情提要
# __call__方法class Func: def __call__(self, *args, **kwargs): print(self) print(args) # (1, 2, 3, 4) print(kwargs) # {'a': 3}obj = Func()obj(1,2,3,4,a=3) # 调用对象,会触发__call__方法,把对象本身和参数传入__call__方法中存成元祖和字典# 元类内部也应该有一个__call__方法,会在调用Func时触发执行# 如 Func(1,2,a=5) --> Func.__call__(Func,1,2,a=5)
2、示例:
#!/usr/bin/env python3#-*- coding:utf-8 -*-# write by congcongclass Mymeta(type): def __init__(self,class_name,class_bases,class_dic): # print(class_name) # Chinese # print(class_bases) # (,) # print(class_dic) if not class_name.istitle(): raise TypeError('类名首字母应大写!') if not '__doc__' or not class_dic['__doc__'].strip(): raise TypeError('必须加注释') super(Mymeta,self).__init__(class_name,class_bases,class_dic) # 重用父类中的方法 def __call__(self, *args, **kwargs): ''' # print(self) # # print(args) # ('cc',) # print(kwargs) # {'age': 21}''' # 第一件事:先造一个空对象 obj = object.__new__(self) # 第二件事:初始化对象 self.__init__(obj,*args,**kwargs) # 第三件事:返回对象 return objclass Chinese(object,metaclass=Mymeta): # metaclass= 表示指定元类 ''' 由元类Mymeta控制类的实例化行为 ''' country = 'China' def __init__(self,name,age): self.name = name self.age = age def chat(self): print('%s is chating now'%self.name)
四、自定义元类控制类的实例化应用
单例模式
1、实现方式一
#!/usr/bin/env python3#-*- coding:utf-8 -*-# write by congcongclass Mysql: __instance = None def __init__(self): self.host = '127.0.0.1' self.port = 3306 @classmethod def singleton(cls): if not cls.__instance: obj = cls() cls.__instance = obj return cls.__instance# obj1 = Mysql()# obj2 = Mysql()# obj3 = Mysql()# print(obj1) # <__main__.Mysql object at 0x0000029CEF267EB8># print(obj2) # <__main__.Mysql object at 0x0000029CEF273080># print(obj3) # <__main__.Mysql object at 0x0000029CEF273128># 这种实例化方式十分浪费内存,下列方式仅占用一份内存obj1 = Mysql.singleton()obj2 = Mysql.singleton()obj3 = Mysql.singleton()print(obj1) # <__main__.Mysql object at 0x00000243FC8B7EB8>print(obj2) # Noneprint(obj3) # None
2、实现方式二(元类的方式)
#!/usr/bin/env python3#-*- coding:utf-8 -*-class Mymeta(type): def __init__(self,class_name,class_bases,class_dic): # print(class_name) # Chinese # print(class_bases) # (,) # print(class_dic) if not class_name.istitle(): raise TypeError('类名首字母应大写!') if not '__doc__' or not class_dic['__doc__'].strip(): raise TypeError('必须加注释') super(Mymeta,self).__init__(class_name,class_bases,class_dic) # 重用父类中的方法 self.__instance = None def __call__(self, *args, **kwargs): if not self.__instance: obj = object.__new__(self) # 造一个空对象 self.__init__(obj) # 实例化 self.__instance = obj # 赋值,更改属性 return self.__instance # 返回class Mysql(object,metaclass=Mymeta): ''' 自定义元类控制类的实例化 ''' __instance = None def __init__(self): self.host = '127.0.0.1' self.port = 3306obj1 = Mysql()obj2= Mysql()obj3 = Mysql()print(obj1==obj2==obj3) # True