zoukankan      html  css  js  c++  java
  • Python中元类

    元类(metaclass)

    简单地说,元类就是一个能创建类的类,而类class 是由type创建的,class可以创建对象

    type与object的关系详见:python中type和object

    1.type动态创建类:

    def __init__(cls, what, bases=None, dict=None): 
          # known special case of type.__init__
            """
            type(object_or_name, bases, dict)
            type(object) -> the object's type
            type(name, bases, dict) -> a new type
            # (copied from class doc)
            """
            pass    
    

    从type源码可以看出,type接受3个参数,第一个是要创建的类名,第二个参数是接受一个tuple(这个类所继承的基类),第三个参数接受一个dict(这个类的属性)

    class BaseResource:
        def check_resource(self):
            return "base class"
    
    def paper_edit(self):
        return "edit paper..."
    
    if __name__=="__main__":
        Paper = type(
            "Paper",
            (BaseResource,),
            {
                "name":"paper_name",
                "paper_edit":paper_edit
            }
        )
        paper = Paper()
        print(paper.check_resource())
        print(paper.name)
        print(paper.paper_edit())
    

    result:

    base class
    paper_name
    edit paper...

    上例可以看到,使用type创建了Paper类,BaseResource是Paper的基类,paper有name属性和paper_edit方法

    2.metaclass控制类对象的生成

    对于python中类的实例化过程

      (1). 首先寻找类中的metaclass

      (2).如果找不到则找其父类的metaclass

      (3).如果父类也找不到metaclass,则找其模块中的   如抽象类  找abc模块的    抽象类详见:Python抽象类

      (4).在都找不到metaclass的情况下,使用type生成类

    class BaseMetaClass(type):
        def __new__(cls, name, bases, dict_agrs):
            upper_dict = dict(
                (arg_name.upper(), arg_val)
                for arg_name, arg_val in dict_agrs.items()
            )
            return super().__new__(cls, name, bases, upper_dict)
    
    
    class Paper(metaclass=BaseMetaClass):
        name = "aaa"
    
    
    print("hasattr(Paper, 'name'):{}".format(hasattr(Paper, 'name')))
    print("hasattr(Paper, 'NAME'):{}".format(hasattr(Paper, 'NAME')))
    

    BaseMetaClass的父类是type,实现了type的__new__方法,将type()方法的第三个参数(类的属性)做属性名大写转换, Paper类中定义了metaclass,在生成Paper类前会先去执行metaclass,即name="Paper"  bases=()  dict_agrs = {"name":"aaa"},  dict_agrs 执行大写转换后变成 {"NAME":"aaa"},即:Paper = type("Paper" ,() ,{"NAME":"aaa"})

     result

    hasattr(Paper, 'name'):False
    hasattr(Paper, 'NAME'):True
    

    3.使用元类实现单例模式

     1 class SingletonMetaClass(type):
     2     __instance = None
     3 
     4     def __call__(cls, *args, **kwargs):
     5         if cls.__instance is None:
     6             cls.__instance = super().__call__(*args, **kwargs)
     7         print(cls.__instance)
     8         return cls.__instance
     9 
    10 
    11 class Singleton(metaclass=SingletonMetaClass):
    12     pass
    13 
    14 singleton1 = Singleton()
    15 singleton2 = Singleton()
    16 print(id(singleton1))
    17 print(id(singleton2))

    Singleton类在生成时先调用SingletonMetaClass,Singleton作为SingletonMetaClass的一个实例,
    执行Singleton()时,会调用__call__方法(__call__让实例能像函数一样调用),__call__在Singleton类实例化(__new__和__init)之前调用,执行Singleton2时,直接返回之前存储在类属性cls._instance中的实例。

    result

    <__main__.Singleton object at 0x7fbd720fd978>
    <__main__.Singleton object at 0x7fbd720fd978>
    140451639187832
    140451639187832
  • 相关阅读:
    js遍历不要使用index 而是使用id(数据唯一表示)
    eureka
    Mybatis-plus自动填充字段的值(如createTime,UpdateTime)
    计算机网络入门
    操作系统入门
    计算机组成原理入门
    《事实》读书笔记
    推荐算法入门
    源码编译安装apache2.4脚本
    Mycat实现读写分离
  • 原文地址:https://www.cnblogs.com/FG123/p/9682968.html
Copyright © 2011-2022 走看看