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
View Code

打印结果如下:

 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()
View Code

打印结果如下:

 

 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)

  

posted @ 2018-11-07 17:41  啊行啊  阅读(718)  评论(0编辑  收藏  举报