https://www.cnblogs.com/ybjourney/p/14295872.html https://zhuanlan.zhihu.com/p/378294204 https://zhuanlan.zhihu.com/p/311160583 https://mp.weixin.qq.com/s/FsjFt7ZHG5AXhChghKn8qQ

对象是类的实例 类是type的实例 type() 接收三个参数:类的名称、父类(tuple形式传入)、绑定的方法或者属性

MetaClass

元类可以理解为是type的子类,继承type,重载call方法,目的是可以在创建类对象的时候作出一些修改 元类的作用过程:

  1. 拦截类的创建
  2. 拦截后,进行修改
  3. 修改完后,返回修改后的类

示例1:创建类时修改类的属性为大写

  1. class TestMetaClass(type):
  2. # def __init__(self, name, class_bases, class_dict):
  3. # logger("this is metaclass __init__ func")
  4. # logger(f"class name: {name}")
  5. # logger(f"class parents as a tuple: {class_bases}")
  6. # logger(f"包含类主体定义的命名空间并且会被复制到一个标准字典成为 __dict__ 属性:{class_dict}")
  7. # super().__init__(name, class_bases, class_dict)
  8. # # metaclass中__call__方法负责对象的创建,这就是为什么要重新定义的原因
  9. # def __call__(cls, *args, **kwargs):
  10. # logger("this is metaclass __call__ func")
  11. # self = super().__call__(*args, **kwargs)
  12. # return self
  13. def __new__(cls, class_name, class_parents, class_attr):
  14. logger("this meteclass __new__ func")
  15. # 将类中非__开头的属性修改为大写
  16. new_attr = {}
  17. for name, value in class_attr.items():
  18. logger(f"name={name}, value={value}")
  19. if not name.startswith("__"):
  20. new_attr[name.upper()] = value
  21. logger(f"new_attr:{new_attr}")
  22. # 调用超类的 __new__() 并返回
  23. return super(TestMetaClass, cls).__new__(cls, class_name, class_parents, new_attr)
  24. class B(metaclass=TestMetaClass):
  25. def __init__(self, *args, **kwargs):
  26. logger("this is class __init__ func")
  27. super().__init__()
  28. def __new__(cls, *args, **kwargs):
  29. logger("this is class __new__ func")
  30. self = super().__new__(cls)
  31. return self
  32. def func1(self):
  33. logger("this is class instance func")
  34. B()
  35. B().FUNC1()
  36. # [I 220520 18:03:01 debug:47] this meteclass __new__ func
  37. # [I 220520 18:03:01 debug:50] name=__module__, value=__main__
  38. # [I 220520 18:03:01 debug:50] name=__qualname__, value=B
  39. # [I 220520 18:03:01 debug:50] name=__init__, value=<function B.__init__ at 0x7f6107b77ae8>
  40. # [I 220520 18:03:01 debug:50] name=__new__, value=<function B.__new__ at 0x7f6107b77b70>
  41. # [I 220520 18:03:01 debug:50] name=func1, value=<function B.func1 at 0x7f6107b77bf8>
  42. # [I 220520 18:03:01 debug:50] name=__classcell__, value=<cell at 0x7f6108413198: empty>
  43. # [I 220520 18:03:01 debug:53] new_attr:{'FUNC1': <function B.func1 at 0x7f6107b77bf8>}
  44. # [I 220520 18:03:01 debug:72] this is class instance func

示例2: ORM框架设计

想要实现如下通过将关系数据库的一行映射为一个对象的操作,如下:

  1. class Field(object):
  2. """定义Field类,它负责保存数据库表的字段名和字段类型"""
  3. def __init__(self, name, column_type):
  4. self.name = name
  5. self.column_type = column_type
  6. def __str__(self):
  7. return "<%s: %s>" % (self.__class__.__name__, self.name)
  8. class IntegerField(Field):
  9. def __init__(self, name):
  10. super(IntegerField, self).__init__(name, "bigint")
  11. class StringField(Field):
  12. def __init__(self, name):
  13. super(StringField, self).__init__(name, "varchar(100)")
  14. class ModelMetaClass(type):
  15. """orm模型元类"""
  16. def __new__(cls, name, bases, attrs):
  17. if name == "Model":
  18. return type.__new__(cls, name, bases, attrs)
  19. logger(f"Found model: {name}")
  20. logger(f"attrs:{attrs}")
  21. mappings = {}
  22. for k, v in attrs.items():
  23. # 如果找到一个Field属性,就把它保存到一个__mappings__的dict中,同时从类属性中删除该Field属性(避免实例的属性遮盖类的同名属性)
  24. if isinstance(v, Field):
  25. logger(f"Found mappings : {k} ==> {v}")
  26. mappings[k] = v
  27. for k in mappings.keys():
  28. attrs.pop(k)
  29. attrs["__mappings__"] = mappings # 保存属性和列的映射关系
  30. attrs.setdefault('__table__', name) # 当未定义__table__属性时,表名直接使用类名
  31. return type.__new__(cls, name, bases, attrs)
  32. class Model(dict, metaclass=ModelMetaClass):
  33. """Model 模型"""
  34. def __init__(self, **kw):
  35. """一个基类如果有 __init__() 方法,则其所派生的类如果也有 __init__() 方法,
  36. 就必须显式地调用它以确保实例基类部分的正确初始化;例如: super().__init__([args...])."""
  37. super(Model, self).__init__(**kw)
  38. def __getattr__(self, key):
  39. """当对象的属性不存在时调用"""
  40. try:
  41. logger(f"{key}, call __getattr__ func")
  42. return self[key]
  43. except KeyError:
  44. return AttributeError(f"'Model' object has no attribute {key}")
  45. def __setattr__(self, key, value):
  46. """属性被赋值时调用"""
  47. logger(f"{key}={value}, call __setattr__ func")
  48. self[key] = value
  49. def save(self):
  50. fields = []
  51. params = []
  52. args = []
  53. for k, v in self.__mappings__.items():
  54. fields.append(v.name)
  55. params.append("?")
  56. args.append(getattr(self, k, None))
  57. sql = f"insert into {self.__table__} ({','.join(fields)}) values ({','.join(params)})"
  58. logger(f"sql={sql}")
  59. logger(f"args={args}")
  60. logger(f"params={params}")
  61. class User(Model):
  62. # 定义类的属性到列的映射
  63. id = IntegerField("id")
  64. name = StringField('username')
  65. # 创建一个实例
  66. user = User(id=123456, name="zaygee")
  67. # 保存到数据库
  68. user.save()
  69. # [I 220520 18:57:05 debug:123] Found model: User
  70. # [I 220520 18:57:05 debug:124] attrs:{'__module__': '__main__', '__qualname__': 'User', 'id': <__main__.IntegerField object at 0x7fb6fc19c7f0>, 'name': <__main__.StringField object at 0x7fb6fc19c828>}
  71. # [I 220520 18:57:05 debug:130] Found mappings : id ==> <IntegerField: id>
  72. # [I 220520 18:57:05 debug:130] Found mappings : name ==> <StringField: username>
  73. # [I 220520 18:57:05 debug:151] id, call __getattr__ func
  74. # [I 220520 18:57:05 debug:151] name, call __getattr__ func
  75. # [I 220520 18:57:05 debug:172] sql=insert into User (id,username) values (?,?)
  76. # [I 220520 18:57:05 debug:173] args=[123456, 'zaygee']
  77. # [I 220520 18:57:05 debug:174] params=['?', '?']

使用init_subclass 替换元类

1、当所在类派生子类时此方法就会被调用。cls 将指向新的子类。如果定义为一个普通实例方法,此方法将被隐式地转换为类方法 2、 传入一个新类的关键字参数会被传给父类的 init_subclass。为了与其他使用 init_subclass 的类兼容,应当根据需要去掉部分关键字参数再将其余的传给基类 3、 这个方法隐式地被 @classmethod 装饰

  1. class Validator:
  2. """校验器基类: 统一注册所有校验器类"""
  3. _validators = {}
  4. def __init_subclass__(cls, **kwargs):
  5. print('{} 注册额外参数: {}'.format(cls.__name__, kwargs))
  6. Validator._validators[cls.__name__] = cls
  7. # 派生子类
  8. class StringValidator(Validator, foo='bar'):
  9. name = 'string'
  10. # StringValidator 注册额外参数: {'foo': 'bar'}
  11. # {'StringValidator': <class '__main__.StringValidator'>}
  12. print(Validator._validators)
  13. # {'StringValidator': <class '__main__.StringValidator'>}
  14. print(StringValidator()._validators)
  15. class Philosopher:
  16. """当有子类继承了 Philosopher ,那么 __init_subclass__ 就会调用"""
  17. def __init_subclass__(cls, default_name, **kwargs):
  18. print("call __init_subclass__ func, default_name is", default_name)
  19. for k, v in kwargs.items():
  20. type.__setattr__(cls, k, v)
  21. class AustralianPhilosopher(Philosopher, default_name="Bruce", name="zaygee"):
  22. pass
  23. # call __init_subclass__ func, default_name is Bruce
  24. # <class '__main__.Philosopher'>
  25. print(Philosopher)
  26. print(AustralianPhilosopher.name) # zaygee