Python中的类与元类

2021-04-15  本文已影响0人  Breezes

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建立映射关系
上一篇 下一篇

猜你喜欢

热点阅读