关于廖雪峰提到的元类的应用实例的解释

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(attrs)
        print('Found model: %s' % name)
        mappings = dict()

        for k, v in attrs.items():        
            if isinstance(v, Field):    #这个有点难理解,为什么不是k,而是v
                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, **kw):
        super(Model, self).__init__(**kw)

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            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(params))
        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=12345, name='Michael', email='test@orm.org', password='my-pwd',sdfjojf='sdfe')
u.save()

当创建实例时,需要调用User类,首先会检查有没有__metaclass__属性,找到了,通过metalclass创建类(基于User类,传入的name为User,父类为Model,属性为User类的属性)。之后在实例化过程中,需要调用创建的新的User类中的方法,如果没有,需要到父类(metalclass创建新类会传承User类的父类)中查找,比如说之后会调用__init__方法,之后又调用save方法。

结果为:

Found model: User
Found mapping: email ==> <StringField:email>
Found mapping: password ==> <StringField:password>
Found mapping: id ==> <IntegerField:uid>
Found mapping: name ==> <StringField:username>
SQL: insert into User (password,email,username,id) values (?,?,?,?)
ARGS: ['my-pwd', 'test@orm.org', 'Michael', 12345]

另外:__metaclass__函数中传递的是在__dict__中可以查询到的特殊类属性。

程序来源:http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014319106919344c4ef8b1e04c48778bb45796e0335839000

所以,我们加几行代码:

 1 class Field(object):
 2 
 3     def __init__(self, name, column_type):
 4         self.name = name
 5         self.column_type = column_type
 6 
 7     def __str__(self):
 8         return '<%s:%s' % (self.__class__.__name__, self.name)
 9 
10 class StringField(Field):
11 
12     def __init__(self, name):
13         super(StringField, self).__init__(name, 'varchar(100)')
14 
15 class IntegerField(Field):
16 
17     def __init__(self, name):
18         super(IntegerField, self).__init__(name, 'bigint')
19 
20 class ModelMetaclass(type):
21 
22     def __new__(cls, name, bases, attrs):   #传入的是类的属性
23         if name=='Model':
24            return type.__new__(cls, name, bases, attrs)
25         print(attrs)    #后来加
26         print('Found model: %s' % name)
27         mappings = dict()
28 
29         for k, v in attrs.items():
30             if isinstance(v, Field):#这个有点难理解,为什么不是k,而是v
31                 print('Found mapping: %s ==> %s' % (k, v))   #这里是将k赋值为id,name,email,password,所以type(k)为str
32                 mappings[k] = v
33         for k in mappings.keys():
34             attrs.pop(k)    #删除一些属性
35         attrs['__mappings__'] = mappings # 保存属性和列的映射关系
36         attrs['__table__'] = name # 假设表名和类名一致
37         return type.__new__(cls, name, bases, attrs)
38 
39 class Model(dict, metaclass=ModelMetaclass):
40 
41     def __init__(self, **kw):
42         super(Model, self).__init__(**kw)
43 
44     def __getattr__(self, key):
45         try:
46             return self[key]
47         except KeyError:
48             raise AttributeError(r"'Model' object has no attribute '%s'" % key)
49 
50     def __setattr__(self, key, value):
51         self[key] = value
52 
53     def save(self):
54         fields = []
55         params = []
56         args = []
57         for k, v in self.__mappings__.items():
58             fields.append(v.name)
59             params.append('?')
60             args.append(getattr(self, k, None))
61         sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params))
62         print('SQL: %s' % sql)
63         print('ARGS: %s' % str(args))
64 
65 class User(Model):
66     # 定义类的属性到列的映射:
67     id = IntegerField('id')
68     name = StringField('username')
69     email = StringField('email')
70     password = StringField('password')
71 
72 
73 print('...')
74 for i, v in User.__dict__.items():   #后来加
75     print(i, v)
76 print('...')
77 
78 u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd',sdfjojf='sdfe')
79 u.save()

会得到下面的结果:

{'__module__': '__main__', '__qualname__': 'User', 'id': <__main__.IntegerField object at 0x0051FC50>, 'name': <__main__.StringField object at 0x0051FC70>, 'email': <__main__.StringField object at 0x0051FC90>, 'password': <__main__.StringField object at 0x0051FCB0>}
Found model: User
Found mapping: id ==> <IntegerField:id
Found mapping: name ==> <StringField:username
Found mapping: email ==> <StringField:email
Found mapping: password ==> <StringField:password
...
__module__ __main__
__mappings__ {'id': <__main__.IntegerField object at 0x0051FC50>, 'name': <__main__.StringField object at 0x0051FC70>, 'email': <__main__.StringField object at 0x0051FC90>, 'password': <__main__.StringField object at 0x0051FCB0>}
__table__ User
__doc__ None
...
SQL: insert into User (id,username,email,password) values (?,?,?,?)
ARGS: [12345, 'Michael', 'test@orm.org', 'my-pwd']

关于57行,类中有的属性(类中__dict__可以查到的属性),可以在定义的函数中使用可以通过self.属性  查询到!

比如:

class P():
    def qss(self):
        print(self.__module__)

print(dir(P))
print(P.__dict__)
p=P()
p.qss()

运行结果:

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'qss']
{'__module__': '__main__', 'qss': <function P.qss at 0x00783810>, '__dict__': <attribute '__dict__' of 'P' objects>, '__weakref__': <attribute '__weakref__' of 'P' objects>, '__doc__': None}
__main__

 在元类中选择重新定义 __new__() 方法还是 __init__() 方法取决于你想怎样使用结果类。__new__() 方法在类创建之前被调用,通常用于通过某种方式(比如通过改变类字典的内容)修改类的定义。而 __init__() 方法是在类被创建之后被调用,当你需要完整构建类对象的时候会很有用。如果要用 super() 函数来搜索之前的定义。它只能在类的实例被创建之后,并且相应的方法解析顺序也已经被设置好了。

posted on 2017-01-14 09:08  wzxds02  阅读(1151)  评论(0编辑  收藏  举报

导航