zoukankan      html  css  js  c++  java
  • 自定义元类和元类的用途

    # -*- 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()
  • 相关阅读:
    css 去除input框边框 鼠标禁用状态 背景颜色
    css 文字边框
    搭建简易的Vue项目
    那些年遇到的Bug
    vue 点击弹出下拉菜单 点击其他页面收回菜单
    css 控制文本显示
    css tips提示框 三角形 + 框
    vue 细节 规范(只要不断片,持续的更新.....)
    @click.self
    工欲善其事,必先利其器
  • 原文地址:https://www.cnblogs.com/zhoulixiansen/p/10068456.html
Copyright © 2011-2022 走看看