前言
本文以廖雪峰网页的元类示例为基础,进行一些补充注解,原文参见文末链接。
使用type()创建类
def fn(self, name="word"):
print("hello, %s" % name)
Hello = type('Hello', (object, ), dict(hello=fn))
type()依次接收3个参数
class名称
继承的父类的集合, 如果只有一个父类,注意tuple的单元素写法
class的方法名称与函数绑定
MetaClass
定义类的时候要显式指明metaclass=xxx
这样会指示python解释器在创建类时,调用xxxMetaclass.__new__()来创建
class ListMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs['add'] = lambda self, value: self.append(value)
return type.__new__(cls, name, bases, attrs)
__new__()接收
当前准备创建的类对象 cls
类名
类继承的父类集合
类的方法集合
ORM(Object Relational Mapping)
class Field(object):
def __init__(self, name, column_type):
self.name = name
self.column_type = column_type
def __str__(self):
return '' % (self.__class__.__name__, self.name)
class StringField(Field):
def __init__(self, name):
super(StringField, self).__init__(name, 'varchar(1000)')
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':
# 先在User中找Meta, 没有找到
# 然后到父类Model里找, 发现可以找到
# 就会使用Model的MetaClass先初始化User()
# 因为在本例中MetaClass不打算修改Model, 所以要在代码中排除掉Model
return type.__new__(cls, name, bases, attrs)
print('Found model: %s' % name)
mappings = dict()
'''
attr = {
'__module__': '__main__',
'__qualname__': 'User',
'id': <__main__.integerfieldobject at>,
'name': <__main__.stringfield object at>,
'email': <__main__.stringfield object at>,
'password': <__main__.stringfield object at>}
'''
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) # 此时只剩__module__ 和 __qualname__
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) # id, username, email, password
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')
u.save()
# out:
Found model: User
Found mapping: id ==>
Found mapping: name ==>
Found mapping: email ==>
Found mapping: password ==>
SQL: insert into User (id,username,email,password) values (?,?,?,?)
ARGS: [12345, 'Michael', 'test@orm.org', 'my-pwd']
引用