美文网首页
Python中的类与元类

Python中的类与元类

作者: Breezes | 来源:发表于2021-04-15 20:30 被阅读0次

    Python的类

    在Python中类也是一个对象,可以使用type()内置函数动态创建类

    MyClass = type('MyClass', (object,), {})
    my_instance = MyClass()
    print(MyClass)
    print(my_instance)
    ⬇️
    <class '__main__.MyClass'>
    <__main__.MyClass object at 0x10ba00fa0>
    

    函数type()实际是一个元类,通过参数创建一个类对象。

    Python的元类

    Python中的元类和类的关系和java一样,实例对象是类对象的实例,而类对象是元类的实例,简单点来说就是元类是用来创建类的,而类是用来创建实例的

    class MyMetaclass(type):
        pass
    class MyClass(object, metaclass=MyMetaclass):
        pass
    my_instance = MyClass()
    

    实例 => 类 => 元类

    上面我们通过type()这个元类创建了MyClass这个类对象,下面自定义一个元类并为类对象添加一些方法和属性⬇️

    class ListMetaclass(type):
        def __new__(mcs, name, bases, attrs):
            attrs['add'] = lambda self, value: self.append(value)
            attrs['name'] = 'Bob Dylan'
            print(mcs, name, bases, attrs.items())
            return type.__new__(mcs, name, bases, attrs)
    
    class MyList(list, metaclass=ListMetaclass):
        pass
    

    这样就为MyList这个类添加了add方法和name属性

    l = MyList()
    l.add(10)
    l.add(20)
    print(l)
    
    ⬇️
    [10, 20]
    Bob Dylan
    

    MyList类的生成大约有几个步骤:

    1.MyListmetaclass属性吗?如果有,Python会在内存中通过__metaclass__创建一个名字为MyList类对象
    2.如果没有,则继续查找父类,并重复1的步骤
    3.如果父类中也没有,会在模块层次中查找,并重复1的步骤
    4.如果还是查找不到,Python会用内置的type()函数创建类对象

    使用元类实现ORM

    ORM是什么?
    1.定义Field类,负责保存数据库表的字段名和字段类型:

    class Field(object):
        def __init__(self, name, column_type):
            self.name = name
            self.column_type = column_type
    
        def __str__(self):
            return '<%s:%s>' % (self.__class__.__name__, self.name)
    
    class StringField(Field): 
        def __init__(self, name):
            super(StringField, self).__init__(name, '(varchar100)')
    
    class IntegerField(Field):
        def __init__(self, name):
            super(IntegerField, self).__init__(name, 'bigint')
    

    2.定义元类

    class ModelMetaclass(type):
        def __new__(mcs, name, bases, attrs):
            if name == "Model":
                return type.__new__(mcs, name, bases, attrs)
            mapping = dict()
    
            for k, v in attrs.items():
                if isinstance(v, Field):  
                    mapping[k] = v 
            for k in mapping.keys():
                attrs.pop(k)  # 将类属性移除,使定义的类字段不污染User类属性,只在实例中可以访问这些key
            attrs['__mapping__'] = mapping  # 保存映射关系
            attrs['__table__'] = name  # 假设表名和类名一致
            return type.__new__(mcs, name, bases, attrs)
    

    3.定义Model类

    class Model(dict, metaclass=ModelMetaclass):
        def __init__(self, **kw):
            super(Model, self).__init__(**kw)
    
        def __getattr__(self, item):  # 获取属性
            try:
                return self[item]
            except KeyError:
                raise AttributeError('Model object has no attribute %s ' % item)
    
        def __setattr__(self, key, value):  # 设置属性
            self[key] = value
    
        def save(self):
            fields = []
            params = []
            args = []
            for k, v in self.__mapping__.items():  # 查找映射关系
                fields.append(v.name)
                params.append('?')
                args.append(self[k])
            sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params))
            print('SQL: %s' % sql)
            print('ARGS: %s' % str(args))
    

    4.使用

    class User(Model):
        id = IntegerField('id')
        name = StringField('username')
        password = StringField('password')
        age = IntegerField('age')
    
    user = User(id=10086, name='ty', password='123456', age=18)
    user.save()
    

    输出⬇️

    SQL: insert into User (id,username,password,age) values (?,?,?,?)
    ARGS: [10086, 'ty', '123456', 18]
    

    映射关系如下⬇️:

    image.png
    通过Field类的namedictkey建立映射关系

    相关文章

      网友评论

          本文标题:Python中的类与元类

          本文链接:https://www.haomeiwen.com/subject/dnzclltx.html