Трудность метаклассами Python | сказать вам прямо договоренности

типа сырой метакласса метакласса производного класса, Ан студентов класса объекта

Другими словами, это

 

Дорога на основе интерпретации метаклассом, естественно закончил

Мы почти не разговаривали на код, чтобы понять:

def fn1(self,name='world'):
    print('Hello,%s'%name)
def fn2(self,name='world'):
    print('Hi,%s'%name)

Hello = type('Hello',(object,),dict(say_hi=fn1,hi='hello'))
Hi = type('Hello',(object,),dict(say_hi=fn2,hi='hi'))
# 生成Hello类的对象
hello1 = Hello()
hello1.say_hi()
print(hello1.hi)
print(hello1)

print('-'*50) # 华丽分割线
# 生成Hi类的对象 hello2 = Hi() print(hello2.hi) hello2.say_hi() print(hello2)

结果:

Hello,world
hello
<__main__.Hello object at 0x0000022EBA06EBA8>
--------------------------------------------------
hi
Hi,world
<__main__.Hello object at 0x0000022EBA06EC50>

type()可以产生类,那么结果就证明了,他可以定制类的名称属性方法等。可以用于创造万物。

django中的ORM,大致思路如下:

class Field(object):
    def __init__(self, column_type, primary_key, default):
        self.column_type = column_type
        self.primary_key = primary_key
        self.default = default


class StringField(Field):
    def __init__(self, column_type='varchar(32)', primary_key=False, default=None):
        super().__init__(column_type, primary_key, default)


class IntegerField(Field):
    def __init__(self,column_type='int', primary_key=False, default=0):
        super().__init__(column_type, primary_key, default)


class MyMetaClass(type):
    def __new__(cls, class_name,class_bases,class_attrs):
        if class_name == 'Models':
            return type.__new__(cls,class_name,class_bases,class_attrs)
        table_name = class_attrs.get('table_name',class_name)
        primary_key = None
        mappings = {}

        for k,v in class_attrs.items():
            if isinstance(v,Field):
                mappings[k]=v
                if v.primary_key:
                    if primary_key:
                        raise TypeError('一张表只能有一个主键')
                    primary_key = k

        print(class_attrs)

        for k in mappings.keys():
            class_attrs.pop(k)
        if not primary_key:
            raise TypeError('一张表必须有主键')
        class_attrs['table_name'] = table_name
        class_attrs['primary_key'] = primary_key
        class_attrs['mappings'] = mappings

        print(class_attrs)

        return type.__new__(cls, class_name,class_bases,class_attrs)

class Models(dict,metaclass=MyMetaClass):

    def __init__(self,**kwargs):
        super().__init__(**kwargs)

    def __getattr__(self, item):
        return self.get(item,'没有该键')

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

    @classmethod
    def select(cls,**kwargs):
        pass

if __name__ == '__main__':
    class Teacher(Models):
        table_name = 'author'
        id = IntegerField(primary_key=True)
        name = StringField()

    a = Teacher(id=12,name='xxx')
    print(a)
    print(a.name)

结果:

{'__module__': '__main__', '__qualname__': 'Teacher', 'table_name': 'author', 'id': <__main__.IntegerField object at 0x0000021E7680ECF8>, 'name': <__main__.StringField object at 0x0000021E76814438>}
{'__module__': '__main__', '__qualname__': 'Teacher', 'table_name': 'author', 'primary_key': 'id', 'mappings': {'id': <__main__.IntegerField object at 0x0000021E7680ECF8>, 'name': <__main__.StringField object at 0x0000021E76814438>}}
{'id': 12, 'name': 'xxx'}
xxx

可以理解为:元类metaclass,是继承了type来控制其他类的产生的工具

然后用MyMetaClass来控制继承Model类的Teacher类,在生成类的实例的过程中,将类的同名属性id、name打包进mappings属性中,使得可以通过getattr来获取他自身字典中的值。可能还是不太明白那就继续看:

class Models(dict):

    def __init__(self,**kwargs):
        super().__init__(**kwargs)

    def __getattr__(self, item):
        return self.get(item,'没有该键')

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

    @classmethod
    def select(cls,**kwargs):
        pass

if __name__ == '__main__':
    class Teacher(Models):
        table_name = 'author'
        id = IntegerField(primary_key=True)
        name = StringField()

    a = Teacher(id=12,name='xxx')
    print(a)
    print(a.name)

结果:

{'id': 12, 'name': 'xxx'}
<__main__.StringField object at 0x000001BD9825EDD8>

此时没有元类MyMetaClass的控制,a.name,获取到的是Teacher类的属性,是一个StringField的对象,而不是他本身字典的键对应值,问题就是这里,元类的引入就是为了解决这种问题,因为a.name会首先找本类的属性,再找父类的属性,如果在这过程中找到了,就不会继续查询,也根本不会调用重写的__getattr__方法。所以在类的创建时,通过把原先的属性隐藏起来,可以让对象去触发getattr得到自身包含的值。

 

рекомендация

отwww.cnblogs.com/xufengfan/p/10951356.html