1. 程式人生 > >python 64式: 第11式、元類

python 64式: 第11式、元類

#!/usr/bin/env python
# -*- coding: utf-8 -*-

'''
關鍵:
1 元類
含義:建立類的東西,用來建立這些類,是類的類
作用:1) 修改類,返回修改後的類
    2) 物件關係對映,將定義的簡單類轉變成對資料庫的操作
目的: 當建立類時能夠自動改變類,希望可以建立符合當前上下文的類
類的型別是type,type可以動態建立類,
可以接收類的描述符作為引數,然後返回一個類
class ListMetaClass(type):
    # __new__(當前準備建立的類的物件,類的名字,類繼承的父類集合,類的方法集合)
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda self, value: self.append(value)
        return type.__new__(cls, name, bases, attrs)

class MyList(list):
    # 指示使用元類L來定義類的建立
    __metaclass__ = ListMetaClass

2 type可以接收一個字典為類定義屬性
type():
含義:是內建函式,可以動態建立類,接收類名作為引數,返回類
本質:是建立所有類的元類。
用法: type(類名,父類的元組【針對繼承的情況,可以為空】,包含屬性或方法的字典) 
def fn(self, name=''):
    return name
Student = type('Student', (object,), {'getName': fn, 'age': 25})
print Student.age
student = Student()
name = student.getName('chen')

總結:
元類本質上是類的類,即類是元類的例項。由於元類可以定製化類的特性,會被用於
物件關係對映,新增自定義類方法等。效果等同於type(name, base, attrs)建立的類。

參考:
[1] http://blog.jobbole.com/21351/
[2] https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386820064557c69858840b4c48d2b8411bc2ea9099ba000
[3] http://python.jobbole.com/88795/
'''

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):
    # __new__(當前準備建立的類的物件,類的名字,類繼承的父類集合,類的方法集合)
    def __new__(cls, name, bases, attrs):
        if 'Model' == name:
            return type.__new__(cls, name, bases, attrs)
        mappings = dict()
        for k, v in attrs.iteritems():
            if isinstance(v, Field):
                mappings[k] = v
        # 將原來屬性字典中已經有Field的鍵值對刪除,否則執行錯誤
        for k in mappings.iterkeys():
            attrs.pop(k)
        # 假設表名和類名一致
        attrs['__table__'] = name
        # 儲存屬性和值的對映關係
        attrs['__mappings__'] = mappings
        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):
        return self[key]

    def save(self):
        fields = []
        values = []
        # 遍歷屬性和值的對映
        for k, v in self.__mappings__.iteritems():
            fields.append(v.name)
            values.append(str(getattr(self, k, None)))
        sql = 'insert into %s (%s) values (%s)' % (self.__table__,
                                                   ','.join(fields),
                                                   ','.join(values))
        print "sql: %s" % (sql)


class User(Model):
    # 定義類的屬性到列的對映
    id = IntegerField('id')
    name = StringField('username')

def userMetaClassORM():
    u = User(id=12345, name='Chen')
    # 儲存到資料庫,由metaclass完成
    u.save()


def process():
    userMetaClassORM()


if __name__ == "__main__":
    process()