python type与__metaclass__的使用
1. 通过__metaclass__实现自定义列表add方法:
1 class ListMetaclass(type): 2 """ 3 通过__metaclass__动态生成类,为新生成的类添加add方法 4 """ 5 6 def __new__(cls, *args, **kwargs): 7 """ 8 :param args: args包含了三个参数具体如下: 9 args[0]: 调用ListMetaclass的类名,这边为"MyList" 10 args[1]: 为MyList所继承的父类,这边为"(<type 'list'>,)" 11 args[2]: 为MyList类所包含的属性与方法, {'__module__': '__main__', '__metaclass__': <class '__main__.ListMetaclass'>} 12 :param kwargs: 13 :return: 返回后必须将这三个参数全部返回 14 """ 15 args[2]["add"] = lambda List, value: List.append(value) 16 return type.__new__(cls, *args) 17 18 class MyList(list): 19 __metaclass__ = ListMetaclass 20 21 c = MyList() 22 c.add(10) 23 print c
打印结果如下:

2. 通过__metaclass__实现ORM的save方法:
1 class Field(object): 2 def __init__(self, name, column_type): 3 self.name = name 4 self.column_type = column_type 5 6 def __str__(self): 7 return '<%s:%s>' % (self.__class__.__name__, self.name) 8 9 class StringField(Field): 10 def __init__(self, name): 11 super(StringField, self).__init__(name, 'varchar(100)') 12 13 class IntegerField(Field): 14 def __init__(self, name): 15 super(IntegerField, self).__init__(name, 'bigint') 16 17 class ModelMetaclass(type): 18 19 def __new__(cls, name, bases, attrs): 20 """ 21 :param name: 22 :param bases: 23 :param attrs: 这边attrs为User类中的数据属性,也就是每个变量对应一个文件类型的对象,具体如下: 24 { 25 'email': <__main__.StringField object at 0x0000000002827550>, 26 '__module__': '__main__', 27 'password': <__main__.StringField object at 0x0000000002827588>, 28 'id': <__main__.IntegerField object at 0x00000000028274E0>, 29 'name': <__main__.StringField object at 0x0000000002827518> 30 } 31 :param 在逻辑处理完成后, __mappings__数据为: 32 { 33 'password': <__main__.StringField object at 0x00000000028C75F8>, 34 'email': <__main__.StringField object at 0x00000000028C75C0>, 35 'name': <__main__.StringField object at 0x00000000028C7588>, 36 'id': <__main__.IntegerField object at 0x00000000028C7550> 37 } 38 :return: 39 这边的__metaclass__主要就是实现了对User类中文件对象的数据进行筛选,因为只有文件对象的数据才需要来拼接sql语句 40 """ 41 if name =='Model': 42 return type.__new__(cls, name, bases, attrs) 43 print('Found model: %s' % name) 44 mappings = dict() 45 for k, v in attrs.iteritems(): 46 #判断attrs中key对应的value是否为文件对象, 如果是则将对象赋值到mappings字典中 47 if isinstance(v, Field): 48 print('Found mapping: %s ==> %s' % (k, v)) 49 mappings[k] = v 50 51 # 先删除attr原先中文件对象,然后添加__mappings__方法,Model类中的save可以通过__mappings__中存放的文件对象来 52 # 实现数据的获取 53 for k in mappings.iterkeys(): 54 attrs.pop(k) 55 attrs['__mappings__'] = mappings # 保存属性和列的映射关系 56 attrs['__table__'] = name # 假设表名和类名一致 57 return type.__new__(cls, name, bases, attrs) 58 59 60 class Model(dict): 61 __metaclass__ = ModelMetaclass 62 63 def __init__(self, **kw): 64 super(Model, self).__init__(**kw) 65 66 def __getattr__(self, key): 67 try: 68 return self[key] 69 except KeyError: 70 raise AttributeError(r"'Model' object has no attribute '%s'" % key) 71 72 # def __setattr__(self, key, value): 73 # self[key] = value 74 75 def save(self): 76 fields = [] 77 params = [] 78 for k, v in self.__mappings__.iteritems(): 79 fields.append(v.name) 80 params.append(str(getattr(self, k, None))) 81 args = " (" 82 for i in params: 83 args += "'{}',".format(i) 84 sql = 'insert into %s (%s) values' % (self.__table__, ','.join(fields)) + args + ")" 85 print('SQL: %s' % sql) 86 87 class BoolObj(object): 88 pass 89 90 91 class User(Model): 92 id = IntegerField('uid') 93 name = StringField('username') 94 email = StringField('email') 95 password = StringField('password') 96 97 #这边User()实列化,由于User类继承了dict类,实际上就相当于dict(id=12345, name='Michael', email='test@orm.org', password='my-pwd') 98 #所有此时打印出来的u就是字典显示 {'email': 'test@orm.org', 'password': 'my-pwd', 'id': 12345, 'name': 'Michael'} 99 u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd') 100 u.save()
打印结果如下:

3. python3__metaclass__实现
"""
@Version: 1.0
@Project: FluentyPython
@Author: Raymond
@Data: 2018/4/10 下午3:34
@File: MetaClass.py
@License: MIT
"""
import logging
from functools import wraps
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
ENUM = (int, dict, list, tuple, str, set, type)
def log(func):
@wraps(func)
def wrap(*args, **kwargs):
if isinstance(func, staticmethod):
if len(args) > 0:
args = args[1::] if not isinstance(args[0], ENUM) else args
func_name = func.__func__.__name__
result = func.__func__(*args, **kwargs)
elif isinstance(func, classmethod):
_args = [func.__class__]
if len(args) > 0:
args = args[1::] if not isinstance(args[0], ENUM) else args
_args.extend(list(args))
func_name = func.__func__.__name__
result = func.__func__(*_args, **kwargs)
else:
func_name = func.__name__
result = func(*args, **kwargs)
logger.info("[ Func {} Called ]".format(func_name))
logger.info("[ Func Paramter ]: Args: {}, Kwargs: {}".format(args, kwargs))
logger.info("[ Func Result ]: {}({}, {})".format(func_name, args, kwargs))
return result
return wrap
class LoggerMeta(type):
def __new__(mcs, name, bases, properties):
wrap_properties = {}
for key, value in properties.items():
if isinstance(value, classmethod):
wrap_properties[key] = classmethod(log(value.__func__))
elif isinstance(value, staticmethod):
wrap_properties[key] = staticmethod(log(value.__func__))
elif key.startswith('__') or isinstance(value, property):
wrap_properties[key] = value
else:
wrap_properties[key] = log(value)
properties.update({"logger": logger})
properties.update(**wrap_properties)
return type.__new__(mcs, name, bases, properties)
class TestMetaLogger(metaclass=LoggerMeta):
def __init__(self):
self.index = 1
self.end = 10
@staticmethod
def test_func_log(a, b):
return a, b
def test_aaa_log(self, a, b):
return a, b
@classmethod
def test_bbb_log(cls, a, b):
return a, b
@staticmethod
def test_ccc_log():
return 111
@classmethod
def test_ddd_log(cls):
return 222
@property
def test_property(self):
return self.end
if __name__ == '__main__':
instance = TestMetaLogger()
TestMetaLogger.test_func_log(7, 8)
TestMetaLogger.test_bbb_log(9, 10)
instance.test_aaa_log(1, 2)
instance.test_func_log(3, 4)
instance.test_bbb_log(5, 6)
TestMetaLogger.test_ccc_log()
instance.test_ccc_log()
TestMetaLogger.test_ddd_log()
instance.test_ddd_log()
print(instance.test_property)

浙公网安备 33010602011771号