首页 > 编程语言 > 详细

Python之难点元类|一句话给你安排的明明白白

时间:2019-05-30 18:59:50      阅读:155      评论:0      收藏:0      [点我收藏+]

type生元类,元类生类,类生对象

换句话就是

技术分享图片

 

道系元类解读,生就完了

话不多说上代码来理解:

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得到自身包含的值。

 

Python之难点元类|一句话给你安排的明明白白

原文:https://www.cnblogs.com/xufengfan/p/10951356.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!