赞
踩
Python的type函数能够返回对象的类型,先看下面一段代码
class Model(object):
pass
a = Model()
print(type(a))
#
输出的结果是a的类型:“Model”,这个是在意料之中的
不过,Python中的类也是一个对象,来看一下它的类型:
print(type(Model))
#
Model返回的类型是Type;可以这样理解,因为Model是类,也就是一种类型(type),所以创建一个类就是是创建了一种类型(即type的实例)
上面说的有点绕,简单了说就是:创建一个类就是创建了一个type的实例
所以很自然的一个疑问是,如果类是type的一个对象,那么这个类是如何与type关联起来的?
在定义类的时候,可以给它指定一个元类(metaclass)
class Model(object, metaclass=type):
pass
print(type(Model))
#
这里把Model的metaclass设置成了type,输出类型仍是‘type’,似乎没什么作用,接着:
class ModelMeta(type):
pass
class Model(object, metaclass=ModelMeta):
pass
print(type(Model))
#
现在先定义一个ModelMeta类,然后将Model的元类设置成ModelMeta,再打印Model的类型,结果变成了‘ModelMeta’类型
到这里可以初步认为,类作为一个对象,是由它的元类所创建,而默认的元类就是type,下面来进一步确认
class ModelMeta(type):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
print("init a", self)
print("init a", self.__class__.__name__)
class Model(object, metaclass=ModelMeta):
pass
# init a
# init a ModelMeta
上面的代码除了定义类Model和它的元类ModelMeta,其他任何代码都没有,但是还是打印了两句话:init a
init a ModelMeta
对照代码可以知道这是ModelMeta类的__init__执行的结果,也就是说有一个ModelMeta实例被创建了
因为在程序运行之后,python解释器会将所有的类、函数等都创建好,所以上面通过追踪ModelMeta类的init过程,证明了Model类确实是由它的metaclass,也就是ModelMeta这个类所创建的对象
在搞清楚这个原理后,就可以干很多事情了,例如,在原来的代码上,加上句打印:
m = Model()
print(m)
# <__main__.model object at>
上面创建一个Model对象,打印一切正常,再看看下面的代码:
class ModelMeta(type):
def __call__(self, *args, **kwargs):
print("hello")
class Model(object, metaclass=ModelMeta):
pass
m = Model()
print(m)
# hello
# None
可以看到,这一次没有创建成功Model对象,而是返回了一个None
关键在于ModelMeta的魔法方法__call__,因为Model是ModelMeta的一个对象,所以执行
Model()
实际上是就执行了ModelMeta的__call__方法,而该方法里面并没有执行创建对象的步骤,只是打印了一句hello,所以就返回了一个None
现在再修改一下:
def __call__(self, *args, **kwargs):
print("hello")
return super().__call__(*args, **kwargs)
...
m = Model()
print(m)
# hello
# <__main__.model object at>
这一次正常创建了Model对象,所以,当有时候有某种需要不希望一个类能够创建对象(比如只希望这个类提供一系列静态方法)时,可以使用这种方法:
class ModelMeta(type):
def __call__(self, *args, **kwargs):
raise TypeError("NO")
class Model(object, metaclass=ModelMeta):
@staticmethod
def func():
print("fun")
再比如说单例模式的实现:
class Singleton(type):
def __init__(self, *args, **kwargs):
self.__instance = None
super().__init__(*args, **kwargs)
def __call__(self, *args, **kwargs):
if self.__instance is None:
self.__instance = super().__call__(*args, **kwargs)
return self.__instance
else:
return self.__instance
class Model(metaclass=Singleton):
pass
a = Model()
print(a)
b = Model()
print(b)
# <__main__.model object at>
# <__main__.model object at>
可以看到a和b是同一个对象,还有一些设计模式,例如工厂模式等等也可以通过元类轻松实现
然后是通过重载元类的__new__方法,来对类进行动态改造:
class ModelMetaclass(type):
def __new__(cls, name, bases, attrs):
print('name:', name)
print('bases:', bases)
for k, v in attrs.items(): print('{}:{}'.format(k, v))
class Model(object, metaclass=ModelMetaclass):
class_attribute_1 = 1
class_attribute_2 = 'a'
def __init__(self):
self.obj_attribute_1 = 5
def func(self):
pass
# name: Model
# bases: (,)
# __module__: __main__
# __qualname__: Model
# class_attribute_1: 1
# class_attribute_2: a
# __init__:
# func:
在创建Model类的时候,因为它的元类是ModelMetaclass,所以会创建一个ModelMetaclass的实例,自然而然的会调用到它的__new__方法,从输出中可以看到,参数name是要创建的类的名称,bases是这个类的基类,而attrs是个字典,包括所有这个类的属性(是类的属性,不是对象的属性)
这里的参数和内置的type函数的参数是一致的,如果使用type函数动态创建类型的话也是使用这三个参数:
new_type = type('Hello', (object,), {'say': lambda self: print('hello')})
print(type(new_type))
t = new_type()
t.say()
#
# hello
上面,使用type动态创建了一个类型(也就是类),并且给了它一个say方法;可以看到,成功创建了一个类,并且调用了这个方法
铺垫都讨论完了,最后贴一段抄来的代码做纪念:
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(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('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)
class Model(dict, metaclass=ModelMetaclass):
def __init__(self, **kw):
super(Model, self).__init__(**kw)
def __getattr__(self, key):
'''重载__getattr__, __setattr__方法使子类可以像正常的类使用'''
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')
# # 保存到数据库:
u.save()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。