看完必会元编程2

元编程

元编程的概念来自LISP和smalltalk。

用来生成代码的程序称为元程序metaprogram,编写这种程序就称为元编程metaprogramming。
python主要通过反射来实现元编程。

    Python中
    所有非object类都继承自Object类
    所有类的类型包括type类都是type
    type类继承自object类,object类的类型也是type类

type类
type构建类

class type(object):
    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
 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

构建

def __init__(self):
    self.x = 1000
    
def show(self):
    return self.__dict__

XClass = type('myclass', (object,), {'a':100, 'b': 'string', 'show':show, '__init__':__init__}) # 字典是类属性 print(XClass)

print(XClass)
print(XClass.__name__)
print(XClass.__dict__)
print(XClass.mro())
 
XClass().show()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

可以借助type构造任何类,用代码生成代码,这就是元编程。
构建元类

一个类可以继承自type类

class ModelMeta(type):
    def __new__(cls, *args):
        print(cls)
        print(*args)
        return super().__new__(cls, *args)

    1
    2
    3
    4
    5

继承自type,ModelMeta就是元类,它可以创建出其他类。

class ModelMeta(type):  # 继承自type
    def __new__(cls, name, bases, attrs: dict):
        print(cls)
        print(name)
        print(bases)
        print(attrs)
        print("--------")
        return super().__new__(cls, name, bases, attrs)


# 第一种 使用metaclass关键字参数指定元类
class A(metaclass=ModelMeta):
    id = 100

    def __init__(self):
        self.x = 2000


# 第二种 B继承自A后,依然是从ModelMeta的类型
class B(A):  # 继承
    pass


# 第三种 元类就可以使用下面的方式创建新的类
C = ModelMeta('Class', (), {'y': 200})

print(type(A))
print(type(B))
print(type(C))

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29

从运行结果还可以分析出__new__(cls, *args) 的参数结构
中间是一个元组 ('A', (), {'__init__': <function A.__init__ at 0x0000000000B6E598>, '__module__':'__main__', '__qualname__': 'A', 'id': 100})
对应 (name, bases, dict)

从运行结果可以看出,只要元类是ModelMeta,创建类对象时,就会调用ModelMeta的__new__方法
元类的应用

class Field:
    def __init__(self, fieldname=None, pk=False, nullable=False):
        self.fieldname = fieldname
        self.pk = pk
        self.nullable = nullable

    def __repr__(self):
        return "<Field {}>".format(self.fieldname)


class ModelMeta(type):  # 继承自type
    def __new__(cls, name, bases, attrs: dict):
        print(cls)
        print(name)
        print(bases)
        print(attrs, '-------------')
        #    使用元类动态注入表名
        tblname = '__tablename__'
        if tblname not in attrs.keys():
            attrs[tblname] = name

        primarykeys = []
        for k, v in attrs.items():
            if isinstance(v, Field):
                print(k)
                print(v)
                print(v.fieldname)
                if v.fieldname is None:
                    v.fieldname = k  # 没有名字则使用属性名
                if v.pk:
                    primarykeys.append(v)

        attrs['__primarykeys__'] = primarykeys

        return super().__new__(cls, name, bases, attrs)


class ModelBase(metaclass=ModelMeta):
    pass


class Student(ModelBase):
    id = Field(pk=True, nullable=False)
    name = Field('username', nullable=False)
    age = Field()


print('----------------')
print(Student.__dict__)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49

元编程的总结

元类是制造类的工厂,是生成类的类。
构造好元类,就可以在类定义时,使用关键字参数metaclass指定元类,可以使用最原始的metatype(name,
bases, dict)的方式构造一个类。
元类的 __new__()方法中,可以获取元类信息、当前类、基类、类属性字典。

元编程一般用于框架开发中。
---------------------
作者:vampires  blood
来源:CSDN
原文:https://blog.csdn.net/weixin_42216574/article/details/84072327
版权声明:本文为博主原创文章,转载请附上博文链接!

posted @ 2019-07-20 17:03  天涯海角路  阅读(88)  评论(0)    收藏  举报