python元编程3

前言

元编程概念来自LISP和smalltalk。

举个简单的栗子:
我们写程序是直接写代码,是否能够用代码来生成未来我们需要的代码呢?这就是元编程, ‘类’的’类’,也就是比类更高级的东西。

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

    python中,所有非object对象都继承自object类
    所有类的类型包括type类,都是type
    type类继承自object类, object类的类型也是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

查看type文档很清楚的可以看到:

type(object) => the object’s type

type(name, bases, dict) => a new type 返回一个新的类型

xclass = type("a", (object,), {"a":1})  # 这里xclass只是标识符, 生成的类的真正的名字是'a'

print(xclass.__name__) #查看类的__name__
print(xclass.a)  # 1 查看类属性'a'
print(xclass().a)  # 1 查看实例属性'a'
print(xclass.__bases__)  # object, 查看继承的类
print(xclass.mro())  # 查看mro(方法解析顺序)
print(xclass.__dict__) # 查看类的__dict__

    1
    2
    3
    4
    5
    6
    7
    8
    9

构建元类

一个类可以继承自tyoe类, 注意不是继承自object类了。

class Meta(type):
    def __new__(cls, name, bases, attrs:dict):
        print(cls)
        print(name)
        print(bases)
        print(attrs)
        return super().__new__(cls, name, bases, attrs)

    1
    2
    3
    4
    5
    6
    7
    8

参数     含义
cls     通过元类创建的类或者继承自通过元类创建的类
name     通过元类创建的类的__name__
bases     通过元类创建的类所继承的类
attrs     通过元类创建的类的__dict__

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

分析下面通过不同方式创建类的区别:

class Metaclass(type):
    def __new__(cls, name, bases, attrs:dict):
        print(cls)
        print(name)
        print(attrs)
        return super().__new__(cls, name, bases, attrs)


class A(metaclass=Metaclass): # 类型是元类,但是还是继承自Object
    pass


class B(A):  # 类型还是元类,但是继承自A类,A类继承自object类
    pass


C = type("C", (), {}) # 这就是元类

D = Metaclass("D", (), {}) # 这就是元类


class E: # 创建的普通类
    pass


class F(Metaclass): # 继承自Metaclass类
    pass


print("A", type(A), A.__bases__)

print("B", type(B), B.__bases__)

print("C", type(C), C.__bases__)

print("D", type(D), D.__bases__)

print("E", type(E), E.__bases__)

print("F", type(F), F.__bases__)

-----------------------------------------------
<class '__main__.Metaclass'>
A
{'__module__': '__main__', '__qualname__': 'A'}
<class '__main__.Metaclass'>
B
{'__module__': '__main__', '__qualname__': 'B'}
<class '__main__.Metaclass'>
D
{}
A <class '__main__.Metaclass'> (<class 'object'>,)
B <class '__main__.Metaclass'> (<class '__main__.A'>,)
C <class 'type'> (<class 'object'>,)
D <class '__main__.Metaclass'> (<class 'object'>,)
E <class 'type'> (<class 'object'>,)
F <class 'type'> (<class '__main__.Metaclass'>,)

    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
    50
    51
    52
    53
    54
    55
    56
    57

从运行结果可以看出, 只要通过一个元类创建类对象时, 就是调用元类中的__new__方法。
元类的应用

ORM编程中使用的框架sqlalchemy中就广泛使用了元编程,下面尝试使用元编程来实现sqlalchemy框架中元编程涉及到的部分功能。

class Column:
    def __init__(self, filedname= None, primary_key=False, nullable=False):
        self.filedname = filedname
        self.primary_key = primary_key
        self.nullable = nullable


class Metaclass(type): # 创建一个元类
    def __new__(cls, name, bases, attrs:dict):
        if "__tablename__" not in attrs:
            attrs["__tablenam__"] = name.lower() # 添加表名

        primarykey = []
        for k,v in attrs.items():
            if isinstance(v, Column):
                if v.filedname is None or v.filedname.strip() == "": # 如果创建的mapping类没有添加字段名,
                    v.filedname = k
                if v.primary_key:
                    primarykey.append(v)
        attrs["primary_key"] = primarykey

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


class Base(metaclass=Metaclass): # 创建一个元类,
    pass


class Student(Base):
    __tablename__ = "student"
    id = Column(primary_key=True, nullable=False) # 使用默认filename=None构造Column类
    name = Column("ben", nullable=False) #
    age = Column()


# 本来构造Column实体对象的时候,参数没有填写完整,想利用元类的__new__方法,构造完整
print(Student.__dict__)
print(Student().age.filedname)

    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

元编程总结

元类是制造类的工厂,是用来构造类的类。
构造好元类,就可以在类的定义时,使用关键字参数metaclass指定一个元类,可以使用最原始的metatype(name, bases, dict)的方式构造一个类。

元类的__new__方法中,可以获取元类信息、当前类、基类、类属性字典。

元编程一般广泛用于开发框架中。例如Django、SQLALchemy等
---------------------
作者:ammmao
来源:CSDN
原文:https://blog.csdn.net/ammmao/article/details/94157263
版权声明:本文为博主原创文章,转载请附上博文链接!

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