不会很常用,在ORM这种复杂结构中会遇到,同时在看一些框架源代码的过程中可能会遇到很多元类的实例,看起来很晦涩。推荐Stack overflow 一些专业解答,也可以参考下这篇博客的深刻理解,很详细。
- str是用来创建字符串对象的类
- int是用来创建整数对象的类
- type就是创建类对象的类
通过type函数动态创建类
# type的语法
type(class_name, class_parents, class_attr_dict)
"""
class_name: 类名
class_parents: 父类的元组(针对集成的情况,可为空)
class_attr_dict: 包函属性的字典
"""
eg:
class MyClass(object):
pass
MyClass = type('MyClass', (), {'foo':True})
元类:就是能够创建python中类这种对象的东西,如type就是Python的内建元类
MyClass = MetaClass() # 元类的创建
my_class = MyClass() # 类的实例
实际上Myclass就是通过type()来创建出的MyClass类,它是type()类的一个实例。
同时,MyClass本身也是累,也可以创建自己的实例my_class。
- metaclass
可以再写一个类的时候为其添加__metaclass__属性,这样就定义了这个类的元类。__metaclass__实际上可以被任意调用,它并不需要是一个正式的类。
# py2
class Foo(object):
__metaclass__ = something
# py3
class Foo(metaclass=something):
__metaclass__ = something
- 自定义元类
元类的主要目的为了当创建类时能够自动改变类,通常,你会为API做这样的事情,你希望可以创建符合当前上下文的类。
- 可以使用函数当做元类
# 元类通常会将你传给type的参数作为自己的参数传入
def upper_attr(future_class_name, future_class_parents, future_class_attr):
"""返回一个类对象,将属性都转为大写形式"""
# 选择所有不以'__'开头的属性
attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
# 将他们转化为大写形式
uppercase_attr = dict{(name.upper(), value) for name, value in attrs}
# 通过type来做类对象的创建
return type(future_class_name, future_class_parents, uppercase_attr) # 返回一个对象,这个对象是个类
class Foo(metaclass=upper_attr):
_metaclass__ = upper_attr
bar = 'bip'
print(hasattr(Foo, 'bar')) # False
print(hasattr(Foo, 'BAR')) # True
f = Foo()
print(f.BAR) # 'bip'
- 可以使用class来当做元类
class UpperAttrMetaClass(type):
def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr):
attrs = ((name, value) for name, value in future_class_attr.items() if not name.starswith('__'))
uppercase_attr = dict((name.upper(), value) for name, value in attrs)
# 复用type.__new__方法,OOP编程。
# 由于type是元类也是类,本身也是通过__new__方法生成实例,只不过这个实例是一个类。
return tpye.__new__(upperattr_metaclass, future_classs_name, future_class_parents, uppercase_attr)
- 真实业务场景下的元类
class UpperAttrMetaClass(type):
def __new__(cls, name, bases, dct):
attrs = ((name, value) for name, value in dct.items() if not name.startswith('__'))
uppercase_attr = dict((name.upper(), value) for name, value in attrs)
return type.__new__(cls, name, bases, uppercase_attr)
# supper继承
class UpperAttrMetaClass(type):
def __new__(cls, name, bases, dct):
attrs = ((name, value) for name, value in dct.items() if not name.startswith('__'))
uppercase_attr = dict((name.upper(), value) for name, value in attrs)
return supper(UpperAttrMetaClass, cls).__new__(cls, name, bases, uppercase_attr)
- 使用元类创建ORM实例
熟悉Django框架的,应该知道ORM结构,元类创建API,使得调用简洁明了。
# -*- coding:utf-8 -*-
# 1.定义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)
class StringField(Field):
def __init__(self, name):
super().__init__(name, 'varchar(100)')
class IntegerField(Field):
def __init__(self, name):
super().__init__(name, 'bigint')
# 定义元类,控制Model对象的创建
class ModelMetaClass(type):
"""定义元类"""
def __new__(cls, name, bases, attrs):
if name == 'Model':
return type.__new__(cls, name, bases, attrs)
print('Found model: %s' % name)
# 排除掉对Model类的修改
mappings = dict()
for k, v in attrs.items():
# 保存类属性和列的映射关系到mappings字典
if isinstance(v, Field):
print('Found mapping: %s==>%s' % (k, v)
mappings[k] = v
for k in mappings.keys():
# 将类属性移除,是定义的类字段不污染User类属性,只在实例中可以访问这些key
attrs.pop(k)
# 假设表名为类名的小写,创建类时添加一个__table__类属性
attrs['__table__'] = name.lower()
# 保存属性和列的映射关系,创建类时添加一个__mappings__类属性
attrs['__mappings__'] = mappings
return type.__new__(cls, name, bases, attrs)
# 编写Model基类
class Model(dict, metaclass= ModelMetaClass):
"""只是简单实现了INSERT功能"""
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))
# 创建一个model,用户表User,定义数据字段就可实现数据表和字段的操作
class User(Model):
id = IntegerField('id') # 对应数据表的id字段
name = StringField('username') # 对应数据表的username字段
email = StringField('email') # 对应数据表的email字段
password = StringField('password') # 对应数据表的password字段
# 创建一个实例
user = User(id=123456, name='Michael', email='test@163.com', password='123456')
# 保存数据库
user.save()