Harvard_Fly 阅读(21) 评论(0)

元类(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模块的    抽象类详见:

  (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