美文网首页
元类介绍

元类介绍

作者: HyRer | 来源:发表于2018-06-04 22:02 被阅读0次

    Python中的类

    记住一句话:在Python中万事万物皆对象
    python中的类也是对象,当一个对象具有创建对象的能力时,就称该对象为类。既然类也是对象,那他就有一下属性

    • 可以将它赋值给其他变量
    • 可以给他添加属性
    • 它可以作为函数的参数传递以及作为返回值返回
    class Person(object):
        def __init__(self,name):
            self.name = name
    
        def say(self):
            print('hello,{}'.format(self.name))
    
    
    # 赋值给其他变量
    xm = Person
    xiaomigng = xm('xiaoming')
    print(xiaomigng.name)
    xiaomigng.say()
    
    # 添加属性
    print(hasattr(Person, 'country'))
    Person.country = 'china'
    print(hasattr(Person, 'country'))
    
    
    # 作为函数的参数
    def exmp(person):
        print(person)
              
      
    exmp(Person)
    

    类的几个常用方法

    class Person(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age
            print(self)
            print('this is __init___')
    
        def __call__(self, *args, **kwargs):
            print('this is __call___')
    
        def __new__(cls, name, age):
            print(cls)
            print('this is __new___')
            return super(Person, cls).__new__(cls)
    
    
    person = Person('ctz', 22)
    person()
    '''
    <class '__main__.Person'>
    this is __new___
    <__main__.Person object at 0x00000286F4C70E80>
    this is __init___
    this is __call___
    '''
    
    • __ new __方法
      __ new __ 方法接受的参数和 __ init __ 一样,但 __ init __ 是在类实例创建之后调用,而 __ new __ 方法正是创建这个类实例的方法。 __ init __ 方法里面的self 实际就是 __ new __ 所创建的实例, __ new __ 返回值就是创建的实例,属于类级别的方法

    • __ init __ 方法
      .__ init __ 通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性, 做一些额外的操作,发生在类实例被创建完以后。它是实例级别的方法。无返回值

    • __ call __ 方法
      构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于
      __ call __ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

    使用type动态的创建类

    type是所有新式类的类,所有类都可以说是type创建的
    object是所有新式类的父类

    print(object.__class__)
    print(object.__bases__)
    print(object.__class__)
    print(type.__bases__)
    '''
    <class 'type'>   # object类是一个type元类所创建
    ()               # 说明 object类已经处于继承链条的顶端,是所有类的父类。
    <class 'type'>   #   type自身的类就是type,就是说type元类也就是由type自身创建的。
    (<class 'object'>,)   # type这一元类的父类是object。
    '''
    

    type动态创建类

    type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))

    def say(self):
      print('hello,{}' .format(self.name))
    
    
    def sayChinese(self):
      print('你好,{}'.format(self.name))
    
    
    address = input('input your country:').strip()
    name = input('your name:').strip()
    dic = {}
    dic['name'] = name
    if address == 'china':
      dic['country'] = '中国'
      dic['say'] = sayChinese
    else:
      dic['county'] = 'other'
      dic['say'] = say
    
    Person = type('Person', (object,), dic)
    print(Person)
    
    person = Person()
    print(person.name)
    person.say()
    

    也可以继承其他类

    class Animal(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def walk(self):
            print('{} is walking'.format(self.name))
    
    
    def eat(self):
        print('{} is eatting'.format(self.name))
    
    
    Dog = type('Dog', (Animal,), {'eat': eat})
    
    dog = Dog('aa', 2)
    print(dog.name)
    dog.eat()
    dog.walk()
    
    

    Python中的元类

    元类就是用来创建这些类(对象)的,元类就是类的类,我们上面用了type来创建类,因为type就是一个元类,我们可以看下面代码

    a = 5
    b = 'bb'
    c = True
    
    def fun():
        pass
    
    
    class Person(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    
    print(a.__class__.__class__)
    print(b.__class__.__class__)
    print(fun.__class__.__class__)
    print(Person.__class__)
    '''
    <class 'type'>
    <class 'type'>
    <class 'type'>
    <class 'type'>
    '''
    

    type就是Python在背后用来创建所有类的元类

    __ metaclass __ 属性

    class Foo(object):
        __metaclass__ = something…
    

    Python就会用元类来创建类Foo。首先我们写下class Foo(object),但是类对象Foo还没有在内存中创建。Python会在类的定义中寻找metaclass属性,如果找到了,Python就会用它来创建类Foo,如果没有找到,就会用内建的type来创建这个类

    class Foo(Bar):
        pass
    

    Python做了如下的操作:

    Foo中有 __ metaclass __ 这个属性吗?如果是,Python会在内存中通过__ metaclass __创建一个名字为Foo的类对象(我说的是类对象,请紧跟我的思路)。如果Python没有找到 __ metaclass __,它会继续在Bar(父类)中寻找 __ metaclass __属性,并尝试做和前面同样的操作。如果Python在任何父类中都找不到 __metaclass __,它就会在模块层次中去寻找 __metaclass __,并尝试做同样的操作。如果还是找不到 __ metaclass __,Python就会用内置的type来创建这个类对象。

    现在的问题就是,你可以在 __ metaclass __中放置些什么代码呢?答案就是:可以创建一个类的东西。那么什么可以用来创建一个类呢?type,或者任何使用到type或者子类化type的东东都可以。

    # 1.对象是类创建,创建对象时候类的__new__和__init__方法自动执行,对象()执行类的 __call__ 方法
    # 2.类是type创建,创建类时候type的__new__,__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法)
    
    
    # 第0步: 执行type的 __new__和__init__ 方法【类是type的对象】
    class Foo(object):
        def __init__(self):
            print('类的__init__')
            pass
    
        def __call__(self, *args, **kwargs):
            print('类的__call__')
            pass
    
    
    # 第1步: 执行type的 __call__ 方法
    #        1.1  调用 Foo类(是type的对象)的 __new__方法,用于创建对象。
    #        1.2  调用 Foo类(是type的对象)的 __init__方法,用于对对象初始化。
    obj = Foo()
    # 第2步:执行Foo类 __call__ 方法
    obj()
    
    

    示例一

    class MyType(type):
        def __init__(self, *args, **kwargs):
            print('MyType创建类__init__',self)
            super(MyType, self).__init__(*args, **kwargs)
    
        def __call__(self, *args, **kwargs):
            obj = super(MyType, self).__call__(*args, **kwargs)
            print('类创建对象__init__', self, obj)
            return obj
    
        def __new__(cls, *args, **kwargs):
            print('Mytype __new__', cls)
            return super(MyType, cls).__new__(cls, *args, **kwargs)
    
    
    class Foo(object,metaclass=MyType):
        user = 'ctz'
        age = 18
    
    
    obj = Foo()
    
    '''
    Mytype __new__ <class '__main__.MyType'>
    MyType创建类 <class '__main__.Foo'>
    类创建对象 <class '__main__.Foo'> <__main__.Foo object at 0x00000227D23BE630>
    '''
    

    示例二

    class MyType(type):
    
        def __init__(self, *args, **kwargs):
            print('MyType __init__', self, '----')
            super(MyType, self).__init__(*args, **kwargs)
    
        def __call__(cls, *args, **kwargs):
            v = dir(cls)
            obj = super(MyType, cls).__call__(*args, **kwargs)
            print('MyType __call__', cls, obj, '****')
            return obj
    
        def __new__(cls, *args, **kwargs):
            print('Mytype __new__',cls)
            return super(MyType,cls).__new__(cls, *args, **kwargs)
    
    
    class Foo(MyType('Bar', (object,), {})):
    
        user = 'ctz'
        age = 18
    
        def __init__(self, *args, **kwargs):
            super(Foo, self).__init__(*args, **kwargs)
    
    
    obj = Foo()
    print(Foo.__bases__)
    print(Foo.__class__)
    
    
    '''
    D:\Python36\python.exe D:/test/python高效编程技巧/元类介绍/元类示例2.py
    Mytype __new__ <class '__main__.MyType'>
    MyType __init__ <class '__main__.Bar'> ----
    Mytype __new__ <class '__main__.MyType'>
    MyType __init__ <class '__main__.Foo'> ----
    MyType __call__ <class '__main__.Foo'> <__main__.Foo object at 0x0000016BE87DEAC8> ****
    (<class '__main__.Bar'>,)
    <class '__main__.MyType'>
    '''
    

    上述相当于我们用MyType创建了一个类Bar,然后用Foo继承Bar,当创建Foo类的时候我们在Foo中找不到__ metaclass __ 属性,再去Bar里面找,Bar里面的 __ metaclass __指向MyType,所以MyType也是Foo的元类,用它来创建Foo

    示例三

    class MyType(type):
        def __init__(self, *args, **kwargs):
            print(self,'------')
            super(MyType, self).__init__(*args, **kwargs)
    
        def __call__(cls, *args, **kwargs):
            v = dir(cls)
            obj = super(MyType, cls).__call__(*args, **kwargs)
            print(cls,obj,'****')
            return obj
    
    
    def with_metaclass(arg,base):
        return MyType('MyType', (base,), {})
    
    
    class Foo(with_metaclass(MyType,object)):
        user = 'ctz'
        age = 18
    
    
    obj = Foo()
    
    '''
    <class '__main__.MyType'> ------
    <class '__main__.Foo'> ------
    <class '__main__.Foo'> <__main__.Foo object at 0x000001FBD9E63710> ****
    '''
    

    这种和上面第二种没啥区别,知识封装了一下,不过查看Flask,wtforms源码可知,实例化Form就是通过这种方法做的

    wtforms源码参考

    
    def with_metaclass(meta, base=object):
        return meta("NewBase", (base,), {})
    
    
    class Form(with_metaclass(FormMeta, BaseForm)):
        """
        Declarative Form base class. Extends BaseForm's core behaviour allowing
        fields to be defined on Form subclasses as class attributes.
    
        In addition, form and instance input data are taken at construction time
        and passed to `process()`.
        """
        Meta = DefaultMeta
    
        def __init__(self, formdata=None, obj=None, prefix='', data=None, meta=None, **kwargs):
            """
            :param formdata:
                Used to pass data coming from the enduser, usually `request.POST` or
                equivalent. formdata should be some sort of request-data wrapper which
                can get multiple parameters from the form input, and values are unicode
                strings, e.g. a Werkzeug/Django/WebOb MultiDict
            :param obj:
                If `formdata` is empty or not provided, this object is checked for
                attributes matching form field names, which will be used for field
                values.
            :param prefix:
                If provided, all fields will have their name prefixed with the
                value.
            :param data:
                Accept a dictionary of data. This is only used if `formdata` and
                `obj` are not present.
            :param meta:
                If provided, this is a dictionary of values to override attributes
                on this form's meta instance.
            :param `**kwargs`:
                If `formdata` is empty or not provided and `obj` does not contain
                an attribute named the same as a field, form will assign the value
                of a matching keyword argument to the field, if one exists.
            """
            meta_obj = self._wtforms_meta()
            if meta is not None and isinstance(meta, dict):
                meta_obj.update_values(meta)
            super(Form, self).__init__(self._unbound_fields, meta=meta_obj, prefix=prefix)
    
    

    元类实现单例模式

    import threading
    
    
    class Singleton(type):
        _instance_lock = threading.Lock()  # 为了实现支持多线程的单例模式
    
        def __call__(cls, *args, **kwargs):
            with cls._instance_lock:
                if not hasattr(cls,'_instance'):
                    cls._instance=super(Singleton, cls).__call__(*args, **kwargs)
            return cls._instance
    
    
    class Foo(metaclass=Singleton):
        def __init__(self, name):
            self.name = name
    
    
    obj1 = Foo('ctz')
    obj2 = Foo('ztc')
    print(obj1, obj2)
    
    '''
    <__main__.Foo object at 0x000002155BBDE940> <__main__.Foo object at 0x000002155BBDE940>
    '''
    

    自定义元类

    示例1

    class UpperTest(type):
        def __new__(cls, myclass, parentclass, myattrs):
            attrs = ((name, value) for name, value in myattrs.items() if not name.startswith('__'))
            attrs_dic = dict((k.upper(), v) for k, v in attrs)
            return type(myclass, parentclass, attrs_dic)
    
    
    class MyTest(object, metaclass=UpperTest):
        name = 'ctz'
        age = 22
    
    
    print(hasattr(MyTest, 'name'))
    print(hasattr(MyTest, 'age'))
    print(hasattr(MyTest, 'NAME'))
    print(hasattr(MyTest, 'AGE'))
    
    
    '''
    D:\Python36\python.exe D:/test/python高效编程技巧/元类介绍/自定义元类1.py
    False
    False
    True
    True
    '''
    

    示例2

    class MetaList(type):
        def __new__(cls, myclassname, myparentname,attrs):
            attrs['add'] = lambda self, value: self.append(value)
            return type.__new__(cls, myclassname, myparentname, attrs)
    
    
    class MyList(list, metaclass=MetaList):
        pass
    
    
    l = MyList()
    l.add(1)
    l.add(2)
    print(l)
    

    应用Django-----ORM

    创建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)
      
    

    创建StringField和IntergerField

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

    继承Field,示例化是调用Field的初始化方法、

    创建Model元类

    class ModelMetaclass(type):
     
        def __new__(cls, name, bases, attrs):
            if name=='Model':
                return type.__new__(cls, name, bases, attrs)
            print('Found model: %s' % name)
            mappings = dict()
            for k, v in attrs.items():
                if isinstance(v, Field):
                    print('Found mapping: %s ==> %s' % (k, v))
                    mappings[k] = v
            for k in mappings.keys():
                attrs.pop(k)
            attrs['__mappings__'] = mappings # 保存属性和列的映射关系
            attrs['__table__'] = name # 假设表名和类名一致
            return type.__new__(cls, name, bases, attrs)
    

    它做了以下几件事

    • 创建一个新的字典mapping
    • 将每一个类的属性,通过.items()遍历其键值对。如果值是Field类,则打印键值,并将这一对键值绑定到mapping字典上。
    • 将刚刚传入值为Field类的属性删除。
    • 创建一个专门的mappings属性,保存字典mapping。
    • 创建一个专门的table属性,保存传入的类的名称。

    创建Model类

    class Model(dict, metaclass=ModelMetaclass):
    
        def __init__(self, **kwarg):
            super(Model, self).__init__(**kwarg)
    
        def __getattr__(self, key):
            try:
                return self[key]
            except KeyError:
                raise AttributeError("'Model' object has no attribute '%s'" % key)
    
        def __setattr__(self, key, value):
            self[key] = value
    
        # 模拟建表操作
        def save(self):
            fields = []
            args = []
            for k, v in self.__mappings__.items():
                fields.append(v.name)
                args.append(getattr(self, k, None))
            sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join([str(i) for i in args]))
            print('SQL: %s' % sql)
            print('ARGS: %s' % str(args))
    

    创建Model的子类User

    class User(Model):
        # 定义类的属性到列的映射:
        id = IntegerField('id')
        name = StringField('username')
        email = StringField('email')
        password = StringField('password')
    

    思路:

    当执行 id = IntegerField('id')时首先会调用元类的 __ new __ 方法,由于IntegerField是Field的子类,所以会将其存入 __ mapping __中,
    mapping['id']=IntegerField('id')并从attrs中删除这个键值对,然后调用
    Model. __ setattr __(self, ‘id’, IntegerField(‘id’))

    初始化实例

    u = User(id=1, name='ctz', email='ctz@qq.com', password='123')
    u.save()
    
    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, 'varchar(100)')
    
    
    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)
            print('Found model: %s' % name)
            mappings = dict()
            for k, v in attrs.items():
                if isinstance(v, Field):
                    print('Found mapping: %s ==> %s' % (k, v))
                    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, **kwarg):
            super(Model, self).__init__(**kwarg)
    
        def __getattr__(self, key):
            try:
                return self[key]
            except KeyError:
                raise AttributeError("'Model' object has no attribute '%s'" % key)
    
        def __setattr__(self, key, value):
            self[key] = value
    
        # 模拟建表操作
        def save(self):
            fields = []
            args = []
            for k, v in self.__mappings__.items():
                fields.append(v.name)  # v就表示Filed或者其子类
                args.append(getattr(self, k, None))
            sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join([str(i) for i in args]))
            print('SQL: %s' % sql)
            print('ARGS: %s' % str(args))
    
    
    
    class User(Model):
        # 定义类的属性到列的映射:
        id = IntegerField('id')
        name = StringField('username')
        email = StringField('email')
        password = StringField('password')
    
    
    u = User(id=1, name='ctz', email='ctz@qq.com', password='123')
    u.save()
    
    '''
    Found model: User
    Found mapping: id ==> <IntegerField:id>
    Found mapping: name ==> <StringField:username>
    Found mapping: email ==> <StringField:email>
    Found mapping: password ==> <StringField:password>
    SQL: insert into User (id,username,email,password) values (1,ctz,ctz@qq.com,123)
    ARGS: [1, 'ctz', 'ctz@qq.com', '123']
    '''
    
    """
    1.创建User实例时,调用元类的__new__,如果是Filed字段,将其价值对存放在mapping中类似于:
       mapping['id] = IntegerField('id'),然后将其键值对从attrs中删除,然后将mapping赋值给attrs['__mapping__']
    2. 调用Model.__setattr__(self, ‘id’, IntegerField(‘id’))进行赋值
    """
    

    相关文章

      网友评论

          本文标题:元类介绍

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