自定义元类和元类的用途

# -*- coding:UTF-8 -*-
__autor__ = 'zhouli'
__date__ = '2018/12/3 23:13'


def create_class(name):
    if name == "user":
        class User:
            def __str__(self):
                return "user"

        return User  # 这一步很关键一定要把类给return回去
    elif name == "company":
        class Company:
            def __str__(self):
                return "company"

        return Company


if __name__ == "__main__":
    MyClass = create_class("user")
    my_obj = MyClass()
    print(my_obj)

结果是user,这个就是动态的创建出来的类。

不过在此做一个补充说明:很多人不明白为什么使用

if __name__ == "__main__":

因为这样会保证这个脚本被调用时候不会被自动执行

但这样动态的创建类也不是太灵活,那就可以采用type类了

type一般用来获取某一个对象的类型的,第二点就是type可以用来创建类的

如何动态的创建类呢?

# -*- coding:UTF-8 -*-
__autor__ = 'zhouli'
__date__ = '2018/12/3 23:25'
# type动态创建类
#  User = type("User", (), {})
# 第一个参数传递的是类的名称,第二个参数是继承的基类,不继承直接写个空元祖,第三个参数是传入属性,不写传一个空字典


if __name__=="__main__":
    User = type("User", (), {})
    my_obj = User()
    print(my_obj)
"""
<__main__.User object at 0x025A4A50>
"""

为User添加属性

if __name__=="__main__":
    User = type("User", (), {"name":"user"})
    my_obj = User()
    print(my_obj.name)
"""
user
"""

这个就和

# -*- coding:UTF-8 -*-
__autor__ = 'zhouli'
__date__ = '2018/12/3 23:13'


def create_class(name):
    if name == "user":
        class User:
            name = "user"

            def __str__(self):
                return "user"

        return User  # 这一步很关键一定要把类给return回去
    elif name == "company":
        class Company:
            def __str__(self): 
                return "company"

        return Company


if __name__ == "__main__":
    MyClass = create_class("user")
    my_obj = MyClass()
    print(my_obj.name)

是一样的了

但是我们创建类的时候不仅仅有类的属性,实际还有类的方法,那如何定义呢?

很简单:定义一个函数,记住参数一定要是self:

def say(self):
    return "i am user"
    # return self.name

然后在属性中加入{"say": say}

完整如下:

def say(self):
    # return "i am user"
    return self.name + 'test'


if __name__ == "__main__":
    User = type("User", (), {"name": "user", "say": say})  # 是函数的名称,不是调用,不要加()
    my_obj = User()
    print(my_obj.say())
"""
usertest
"""

那如果User需要继承一个基类呢?

class BaseClass:
    def answer(self):
        return '****'


if __name__ == "__main__":
    User = type("User", (BaseClass,), {"name": "user", "say": say})  # 是函数的名称,不是调用,不要加()
    my_obj = User()
    print(my_obj.answer())
"""
****
"""

别忘了元祖后的一个逗号

那什么才是元类?

元类是创建类的类

编码时很少会采用type创建类,一般使用MetaClass(type)类名可以自定义,但继承type了他就是元类了

class MetaClass(type):
    def __new__(cls, *args, **kwargs):
        return super().__new__(cls, *args, **kwargs)


from collections.abc import *


# 什么是元类, 元类是创建类的类 对象<-class(对象)<-type
class User(metaclass=MetaClass):  # 指定控制实例化过程的元类
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return "user"


# python中类的实例化过程,会首先寻找metaclass,通过metaclass去创建user类
# 去创建类对象,实例

类什么也不继承的时候,type会去创建类对象,实例。

那么元类到底有什么作用呢?

例:自定义ORM(自我仿制乞丐版Django的ORM)

# 需求
import numbers


class Field:
    pass


class IntField(Field):
    # 数据描述符
    def __init__(self, db_column, min_value=None, max_value=None):
        self._value = None  # 这里采用_单下划线模式,指明这是一个内部的变量,不希望采用self._value方式访问
        self.min_value = min_value
        self.max_value = max_value
        self.db_column = db_column
        if min_value is not None:
            if not isinstance(min_value, numbers.Integral):
                raise ValueError("min_value must be int")
            elif min_value < 0:
                raise ValueError("min_value must be positive int")
        if max_value is not None:
            if not isinstance(max_value, numbers.Integral):
                raise ValueError("max_value must be int")
            elif max_value < 0:
                raise ValueError("max_value must be positive int")
        if min_value is not None and max_value is not None:
            if min_value > max_value:
                raise ValueError("min_value must be smaller than max_value")

    def __get__(self, instance, owner):
        return self._value

    def __set__(self, instance, value):
        if not isinstance(value, numbers.Integral):
            raise ValueError("int value need")
        if value < self.min_value or value > self.max_value:
            raise ValueError("value must between min_value and max_value")
        self._value = value


class CharField(Field):
    def __init__(self, db_column, max_length=None):
        self._value = None
        self.db_column = db_column
        if max_length is None:
            raise ValueError("you must spcify max_lenth for charfiled")
        self.max_length = max_length

    def __get__(self, instance, owner):
        return self._value

    def __set__(self, instance, value):
        if not isinstance(value, str):
            raise ValueError("string value need")
        if len(value) > self.max_length:
            raise ValueError("value len excess len of max_length")
        self._value = value


class ModelMetaClass(type):
    def __new__(cls, name, bases, attrs, **kwargs):  # 在这里就和用type生成类是一样的用法,attr是{}是类的方法,bases是(),name是类名
        if name == "BaseModel":
            return super().__new__(cls, name, bases, attrs, **kwargs)
        fields = {}
        for key, value in attrs.items():
            if isinstance(value, Field):
                fields[key] = value
        attrs_meta = attrs.get("Meta", None)
        _meta = {}  #
        db_table = name.lower()
        if attrs_meta is not None:
            table = getattr(attrs_meta, "db_table", None)  # 利用反射,找不到置为None
            if table is not None:
                db_table = table
        _meta["db_table"] = db_table
        attrs["_meta"] = _meta
        attrs["fields"] = fields
        del attrs["Meta"]
        return super().__new__(cls, name, bases, attrs, **kwargs)


class BaseModel(metaclass=ModelMetaClass):
    def __init__(self, *args, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)
        return super().__init__()

    def save(self):  # 拼凑save的字符串
        fields = []
        values = []
        for key, value in self.fields.items():
            db_column = value.db_column
            if db_column is None:
                db_column = key.lower()
            fields.append(db_column)
            value = getattr(self, key)
            values.append(str(value))

        sql = "insert {db_table}({fields}) value({values})".format(db_table=self._meta["db_table"],
                                                                   fields=",".join(fields), values=",".join(values))
        pass


class User(BaseModel):  # 因为本身没有metaclass,他会首先查找父类的metaclass
    name = CharField(db_column="name", max_length=10)
    age = IntField(db_column="age", min_value=1, max_value=100)

    class Meta:
        db_table = "user"


if __name__ == "__main__":
    user = User(name="bobby", age=28)  # 这样是先走BaseModel的,将值变为下面注释的样子
    # user.name = "bobby"  # 这样是先走User的
    # user.age = 28  # 这样是先走User的
    user.save()
原文地址:https://www.cnblogs.com/zhoulixiansen/p/10068456.html