Discuss / Python / 恍然大悟

恍然大悟

Topic source

学习到后面的实战后,回头来学习元类,突然恍然大悟,元类不管怎么使用,只是去修改类的一种手段,理解为元类创建类这个对象,思路就极其的清晰,贴上个人爬坑的代码:

#该类学习两个对象定制方法:__getattr__,__setattr__
class Model(object):
    #如果用点语法访问不存在的属性就会调用该方法,因为model继承dict没有定义属性,全是键值对,巧妙的通过点语法转换到获取字典的值
    def __getattr__(self, key):
        try:
            print('点语法访问了某个属性');
            return self[key]
        except KeyError:
            raise AttributeError(r"'Model' object has no attribute '%s'" % key)

    #用点语法给对象属性赋值都会走该方法
    #如果Model继承的不是dict,那么可以通过__dict__获取一个对象所有属性的一个字典
    def __setattr__(self, key, value):
        self[key] = value
print(type(Model))
model = Model()
print(model.__dict__)
print(type(model))

#次例子是学习type动态创建类
def fn(self,name='hehda'):
    print('hello %s' % (name,))
    print(self)

#type的第一个参数是类名,第二个参数是继承的父类为元组,第三个参数是对象方法和属性为字典
HeHe = type('HeHe', (object,), {'hifn':fn})
print(type(HeHe))
hehe = HeHe()
print(hehe)
hehe.hifn()



#次例子是学习元类来定制(创建)类
def add(self,value):
    self.append(value)
class MHMetaClass(type):
    #第一个参数是元类对象,第二个参数要创建的类名,第三个是要创建的类的父类,第四个参数很重要,是类的属性和方法(请记住不是对象的属性和方法,请自行查阅廖大之前教程以作区分)
    def __new__(cls,name,bases,attrs):
        print("通过元类来创建一个类:%s,%s,%s,%s" % (cls,name,bases,attrs))
        attrs['add'] = add
        return type.__new__(cls,name,bases,attrs)

class MHList(list,metaclass=MHMetaClass):
    pass
l = MHList()
l.append(1)
l.add(2)
print(l)

#次例子是为了验证super()的用法,以及__str__来定制对象
class F(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age
class C(F):
    def __init__(self,name,age,color):
        #廖大教程中的写法教老,新版本中可以省略super()里指定的类和对象,下面的语句就是super()获取父类,然后调用父类的__init__方法,但是我倾向于理解为super()是利用当前对象来调用父类的初始化方法
        super().__init__(name,age)
        self.color = color
    #该方法会改变print的输出
    def __str__(self):
        return "%s,%s,%s" % (self.name,self.age,self.color)
c = C("刘德华",78,'绿色')
print(c)





#次例子就是ORM的简单实现,重要部分已做注释
class Field(object):
    def __init__(self,name,type):
        self.name = name
        self.type = type
    def __str__(self):
        return '<%s:%s>' % (self.__class__.__name__,self.name)

class IntegerField(Field):
    def __init__(self,name,type='int(20)'):
        super().__init__(name,type)

class StringField(Field):
    def __init__(self,name,type='varchar(20)'):
        super().__init__(name,type)


class SchoolMetaClass(type):
    def __new__(cls,name,bases,attrs):
        mapping = dict()
        print('mapping:%s' % mapping)
        for key,value in attrs.items():
            if isinstance(value, Field):
                 print('类的属性和方法---%s:%s' % (key,value))
                 mapping[key] = value
        #移除类属性以免与对象属性发生冲突
        for key in mapping.keys():
            attrs.pop(key)
        attrs['__mapping__'] = mapping #类名和属性的映射
        attrs['__table__'] = name #表名
        print(attrs)
        return type.__new__(cls,name,bases,attrs)
class BaseSchool(dict,metaclass=SchoolMetaClass):
    def __init__(self,**keywords):
        print(keywords)
        #继承字典,对象调用该方法传关键字参数
        super().__init__(**keywords)
    def __getattr__(self,key):
        return self[key]
    def __setattr__(self,key,value):
        self[key] = value

    def save(self):
        #保存列名
        fields = []
        #sql语句的占位符是?,保存?
        parms = []
        #占位符对应的具体结果,就是值的集合
        args = []
        for key,value in self.__mapping__.items():
            fields.append(value.name)
            parms.append('?')
            args.append(getattr(self,key,None))
        sql = 'insert into %s (%s) value %s' % (self.__table__,','.join(fields),','.join(parms))
        print('sql:%s'% (sql))
        print(str(args))


class School(BaseSchool):
    name = StringField('name')
    id = IntegerField('id')
    email = StringField('email')
school = School(name='hehed',id='555',email='8064444')
school.save()
print(school.name)

  • 1

Reply