python的元类

本文示例代码在python3.7下python

一.元类(metaclass)

1.python中一切皆对象.class也是一个对象.

class A:
    pass

a = A()
print(type(a))
print(type(A))

  

输出sql

<class '__main__.A'>
<class 'type'>

  

a是A类的实例,类A(是一个class)是type的实例(注意:类A是type的实例,是object的子类,全部新式类的根类都是object)app

2.A类是如何建立的?

(1).解释器检查是否有类A的元类属性,若是有则按指定元类来建立

(2).若是没有则默认使用type元类来建立

(3).对于建立类,解释器调用元类,须要使用三个参数

name:这将是须要建立的类的名称。对于咱们的状况,它将是字符串'A'。
bases:该类基类的元组。
attrs:它是一个字典,包含为该类定义的全部属性函数

所以动态建立上述A类能够写做:spa

A = type('A', (), {})

  

3.元类:

(1).type是建立类的默认元类,指示了类如何被建立.
(2).元类只是一个能够建立类的类,就像普通类具备建立该类实例的能力同样,元类也具备建立类的能力。建立的类是元类的一个实例
(3).类是元类的一个实例
(4).因为type是默认元类,所以若是咱们要编写元类,咱们必须从type继承。

二.实例

1.自定义元类:

class TestMetaClass(type):
    def __new__(cls, name, bases, attrs):
        return super().__new__(cls, name, bases, attrs)

  

(1).继承自元类type
(2).在元类中覆写了__new__
(3).解释器将使用三个参数调用咱们的元类,所以元类的__new__将接收四个参数。因此咱们要注意__new__元类须要四个参数
(4).在__new__中咱们使用超类中的__new__,若是TestMetaClass不是从type继承,实际的类建立将发生在type的__new__中
(5).任何类的__new__收到的第一个参数是类自己(上文代码中的cls)对象

若是咱们编写元类,必须从type继承,必须覆写__new__,而且调用超类的__new__来建立类blog

2.使用TestMetaClass

class B(metaclass=TestMetaClass):
    pass

b = B()
print(type(b))
print(type(B))

  

输出
<class '__main__.B'>
<class '__main__.TestMetaClass'>继承

b是类B的一个实例,类B是TestMetaClass的实例字符串

 

(1).解释器知道默认的元类类型不能用于建立B.而是必须使用TestMetaClass来建立B.

(2).当调用MyMeta时,调用MyMeta的__new__

(3).以上代码等同于:

B = TestMetaClass('B', (), {})
b = B()
print(type(b))
print(type(B))

(4).由于TestMetaClass继承自type,因此TestMetaClass的__new__也能够定义成

class TestMetaClass(type):
    def __new__(cls, name, bases, attrs):
        return type.__new__(cls, name, bases, attrs)

  

三.type

1.type(),是一个内置函数,能够检查类型

方法为:
type(some_object)get

2.type是一个内置函数,也能够动态建立类:

方法为:
type(cls类名, bases(继承的元组), attrs(属性字典))

3.type也是一个类,是建立类的默认元类

四.什么时候使用

1.元类使用的比较少,99%的状况下用不到
2.一个简单的例子,限制类的属性:

allowed_attributes = ['first', 'second']

class Meta(type):
    def __new__(cls, name, bases, attrs):
        attrs_list = list(attrs)
        for each_attr in attrs_list:
            if not each_attr.startswith('_') and each_attr not in allowed_attributes:
                del attrs[each_attr]
                print("Attributes after deleting non allowed attributes", attrs)
        return type.__new__(cls, name, bases, attrs)


class B(metaclass=Meta):
    first = 1
    second = 2
    third = 3

b = B()

  

注意:
上文代码中,您或许可能认为直接使用__new__就能够实现,由于__new__就是负责实例的建立.但类B中first,second等属性是静态属性,隶属于类,而不是实例,因此此处使用了元类.元类是负责类的建立.

咱们使用__new__来写一个限制实例属性的(不是很恰当)

class My:
    def __new__(cls, *args, **kwargs):
        print(kwargs)
        if not isinstance(kwargs, dict):
            raise RuntimeError('参数错误')
        if 'c' in kwargs:
            raise RuntimeError('不能包含key为c的参数')
        return super().__new__(cls)

    def __init__(self, **kwargs):
        self.args = kwargs


test = My(a=2, b=3, c=100)
print(test.args)

  

3.ORM的例子

class Field(object):
    def __init__(self, name, column_type):
        self.__name = name
        self.__column_type = column_type

    def __str__(self):
        return '<%s,%s>' % (self.__name, self.__column_type)

    def __getattr__(self, item):
        return {'name': self.__name, 'column': self.__column_type}[item]

class IntegerField(Field):
    def __init__(self, name):
        super(IntegerField, self).__init__(name, 'bigint')

class ModelMetaClass(type):
    def __new__(cls, name, bases, attrs):
        if name == 'Model':
            return type.__new__(cls, name, bases, attrs)

        mappings = dict()
        for k, v in attrs.items():
            if isinstance(v, Field):
                mappings[k] = v

        for k in mappings.keys():
            attrs.pop(k)

        attrs['__mappings__'] = mappings
        attrs['__table__'] = name
        return type.__new__(cls, name, bases, attrs)

class Model(dict, metaclass=ModelMetaClass):
    def __init__(self, **kwargs):
        super(Model, self).__init__(**kwargs)

    def __getattr__(self, key):
        try:
            return self[key]
        except BaseException:
            raise AttributeError(r"'Model' object has no attribute '%s'" % key)

    def __setattr__(self, key, value):
        self[key] = value


    def save(self):
        fields = []
        params = []
        args = []

        for k, v in self.__mappings__.items():
            fields.append(v.name)
            params.append('?')
            args.append(getattr(self, k, None))

        sql = 'insert into %s(%s) values(%s)' % \
              (self.__table__, ','.join(fields), \
               ','.join([str(x) for x in args]))
        print('SQL: %s' % sql)


class User(Model):
    id = IntegerField('id')

# create user instance
user = User(id=100)
user.save()
相关文章
相关标签/搜索