博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
面向对象之元类
阅读量:5272 次
发布时间:2019-06-14

本文共 8483 字,大约阅读时间需要 28 分钟。

一、元类的介绍

  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}
View Code

 

  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
View Code

    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
View Code

 

二、自定义元类以控制类的创建行为

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)
View Code

 

三、自定义元类控制类的实例化

  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)
View Code

  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)
View Code

 

四、自定义元类控制类的实例化应用

  单例模式

  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
View Code

  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
View Code

 

转载于:https://www.cnblogs.com/schut/p/8657025.html

你可能感兴趣的文章
iOS8统一的系统提示控件——UIAlertController
查看>>
PAT甲级——1101 Quick Sort (快速排序)
查看>>
python创建进程的两种方式
查看>>
1.2 基础知识——关于猪皮(GP,Generic Practice)
查看>>
迭代器Iterator
查看>>
java易错题----静态方法的调用
查看>>
php建立MySQL数据表
查看>>
最简单的线程同步的例子
查看>>
旅途上看的电影和观后感
查看>>
Ztree异步树加载
查看>>
关于IE和火狐,谷歌,Safari对Html标签Object和Embed的支持问题
查看>>
poj3320 Jessica's Reading Problem(尺取思路+STL)
查看>>
分布式计算开源框架Hadoop介绍
查看>>
安卓平台接口剖析
查看>>
坏的事情不都会带来坏的结果
查看>>
RPC的基础:调研EOS插件http_plugin
查看>>
第二次团队冲刺第二天
查看>>
bzoj 2257 (JSOI 2009) 瓶子与燃料
查看>>
11)Java abstract class 和 interface
查看>>
使用xrdp或Xmanager 远程连接 CentOS6
查看>>