使用 type() 查看一个类或者变量的类型
>>> class Hello(object):
... def hello(self, name='world'):
... print('Hello, %s.' % name)
...
>>> h = Hello()
>>> h.hello()
Hello, world.
>>> print(type(Hello)) #查看类的类型
<class 'type'>
>>> print(type(h)) #查看变量的类型
<class '__main__.Hello'>
复制代码
class 的定义是运行时动态创建的,而创建class 的方法就是使用 type() 函数 type() 函数既可以返回一个对象的类型,又可以创建出新的类型。
通过type() 动态创建 Hello类:
>>> def fn(self, name='world'): #定义函数
... print('Hello, %s.' % name)
...
>>> Hello = type('Hello', (object,), dict(hello = fn)) #创建 Hello 类
>>> h = Hello()
>>> h.hello()
Hello, world.
>>> print(type(Hello))
<class 'type'>
>>> print(type(h))
<class '__main__.Hello'>
复制代码
通过 type() 函数创建类,需要传入的3个参数: 1、class 的名称 2、继承父类集合,注意 Python 支持多重继承,别忘了 tuple 的单元素写法 3、class 的方法名称与函数绑定,上面我们是通过 fn 绑定到 hello 上
通过 metaclass 可以给我们自定义的 MyList 增加一个 add 方法:
>>> class ListMetaclass(type): #metaclass 是类的模板,所以必须从 ‘type’ 类型派生
... def __new__(cls, name, bases, attrs):
... attrs['add'] = lambda self, value: self.append(value)
... return type.__new__(cls, name, bases, attrs)
...
复制代码
使用 ListMetaclass 来定制类,传入关键字参数 metaclass:
>>> class MyList(list, metaclass=ListMetaclass):
... pass
...
>>> L = MyList() #测试 MyList 是否可以调用 add() 方法
>>> L.add(1)
>>> L
[1]
>>> L2 = list() # 测试普通的 list 是否有add() 方法
>>> L2.add(1)
Traceback (most recent call last): #报错了,说明没有add 方法
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'add'
复制代码
定义 Field 类,它负责保存数据库表的字段名和字段类型:
>>> 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)
...
复制代码
进一步定义各种类型的 Field, 比如 StringField, IntegerField 等等:
>>> 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')
...
复制代码
编写复杂的 ModelMetaclass :
>>> class ModelMetaclass(type):
... def __new__(cls, name, bases, attrs):
... if name == 'Model':
... return type.__new__(cls, name, bases, attrs)
... print('Found model:%s' % name)
... mappings = dict()
... for k, v in attrs.items():
... if isinstance(v, Field):
... 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)
...
复制代码
编写基类 Model:
>>> 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')
...
Found model:User
Found mapping: id ==> <IntegerField: id>
Found mapping: name ==> <StringField: username>
Found mapping: email ==> <StringField: email>
Found mapping: password ==> <StringField: password>
>>> u = User(id = 12345, name='Michael', email='test@orm.org', password='my-pwd')
>>> u.save()
SQL: insert into User (id,username,email,password) values(?,?,?,?)
ARGS: [12345, 'Michael', 'test@orm.org', 'my-pwd']
复制代码
以上我们通过 metaclass实现了一个精简的 ORM 框架,是不是很简单呢。
总结:
metaclass 是 Python 中非常具有魔术性的对象,它可以改变类创建时的行为。不过使用起来务必小心。
复制代码