FreezeJ' Blog

python元类metaclass

2021-11-29

参考文档:
https://zhuanlan.zhihu.com/p/149126959
https://www.cnblogs.com/tkqasn/p/6524879.html
https://blog.csdn.net/a2011480169/article/details/87891753

什么是元类

type是Python的一个内建元类,用来直接控制生成类,在python当中任何class定义的类其实都是type类实例化的结果。
只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类,自定义元类可以控制类的产生过程,类的产生过程其实就是元类的调用过程。元类的主要目的是为了控制类的创建行为。

type、class和object的关系

type、class和object的关系
在Python面向对象当中,所有的类的根本来源就是type。也就是说Python当中的每一个类都是type的实例。

使用type动态创建类

一个类由三大组成部分,分别是:

  1. 类名class_name
  2. 继承关系class_bases
  3. 类的名称空间class_dict

type的帮助信息:

type除了可以查看一个对象的类型,还可以用来创建类:
type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))

构建类
#构建目标代码
class Foo(object):
    bar = True

#使用type构建
Foo = type('Foo', (), {'bar':True})
继承类
# 构建目标代码:
class FooChild(Foo):
    pass

# 使用type构建
FooChild = type('FooChild', (Foo,),{})
绑定方法
# 构建目标代码:
class FooChild(Foo):
    def echo_bar(self):
        print(self.bar)

# 使用type构建
def echo_bar(self):
    print(self.bar)

FooChild = type('FooChild', (Foo, ), {'echo_bar': echo_bar})
绑定静态方法、类方法
# 构建目标代码:
class TestClass():
    @classmethod
    def test_classmethod(cls):
        print('classmethod')

    def test(self):
        print('test')

    @staticmethod
    def test_staticmethod():
        print('staticmethod')

# 使用type构建
@classmethod
def test_classmethod(cls):
    print('classmethod')

def test(self):
    print('test')

@staticmethod
def test_staticmethod():
    print('staticmethod')

TT = type('TestClass', (), {'test_staticmethod': test_staticmethod, 'test':test, 'test_classmethod': test_classmethod})

自定义元类

class Foo(object):   # py2
    __metaclass__ = something…


class Foo(metaclass=something):   # py3
    __metaclass__ = something…
class Mymeta(type):
    def __init__(self, name, bases, dic):
        super().__init__(name, bases, dic)
        print('===>Mymeta.__init__')
        print(name)  # 类名
        print(bases)  # 父类的元组(针对继承的情况,可以为空)
        print(dic)  # 包含属性的字典(名称和值)
        print(self.yaml_tag)  # 打印特定属性

    def __new__(cls, *args, **kwargs):
        print('===>Mymeta.__new__')
        print(cls.__name__)
        return type.__new__(cls, *args, **kwargs)

    def __call__(cls, *args, **kwargs):
        print('===>Mymeta.__call__')
        obj = cls.__new__(cls)
        cls.__init__(cls, *args, **kwargs)
        return obj


class Foo(metaclass=Mymeta):
    yaml_tag = '!Foo'

    def __init__(self, name):
        print('Foo.__init__')
        self.name = name

    def __new__(cls, *args, **kwargs):
        print('Foo.__new__')
        return object.__new__(cls)

    def __call__(cls, *args, **kwargs):
        print('FOO.__call__')

    def test(text):
        print(text)

# Foo = Mymeta('Foo', (), {'yaml_tag ': '!Foo', '__init__': __init__, '__new__': __new__, '__call__': __call__, 'test': test})

print('------------实例化--------------')
foo = Foo('foo')
foo()

输出结果:

===>Mymeta.__new__
Mymeta
===>Mymeta.__init__
Foo
()
{'__module__': '__main__', '__qualname__': 'Foo', 'yaml_tag': '!Foo', '__init__': <function Foo.__init__ at 0x7fd0383c78c8>, '__new__': <function Foo.__new__ at 0x7fd0383c7c80>, '__call__': <function Foo.__call__ at 0x7fd0383c79d8>, 'test': <function Foo.test at 0x7fd0383c7bf8>}
!Foo
------------实例化--------------
===>Mymeta.__call__
Foo.__new__
Foo.__init__
FOO.__call__

使用元类实现单例

import threading
import time


# 普通类
class Foo():
    def __init__(self):
        print('init!!')
        self.log_time = time.time()

# 单例元类
class SingletonType(type):
    _instance_lock = threading.Lock()
    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            with SingletonType._instance_lock:
                if not hasattr(cls, "_instance"):
                    cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)
        return cls._instance

# 使用单例元类
class FooSingleton(metaclass=SingletonType):
    def __init__(self):
        print('init!!')
        self.log_time = time.time()

# 普通任务
def task(arg):
    obj = Foo()
    print(obj.log_time)

print('普通类实例化')
for i in range(5):
    t = threading.Thread(target=task,args=[i,])
    t.start()

# 单例任务
def task_single(arg):
    obj = FooSingleton()
    print(obj.log_time)

print('单例')
for i in range(5):
    t = threading.Thread(target=task_single,args=[i,])
    t.start()

输出结果:

普通类实例化
init!!
1638345526.2971504
init!!
1638345526.29774
init!!
1638345526.2979605
init!!
1638345526.2982018
init!!
1638345526.2983775
单例
init!!
1638345526.2985206
1638345526.2985206
1638345526.2985206
1638345526.2985206
1638345526.2985206