python type与__metaclass__的使用
1. 通过__metaclass__实现自定义列表add方法:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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方法:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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)