【Python基础知识库】Python中的元类metaclass

元类在Python中主要用于在创建类时自动改变类的行为,常见于ORM框架和复杂结构。type是Python的内建元类,可以用来动态创建类。通过定义`__metaclass__`属性可以自定义元类,元类主要应用于调整API创建,如在Django ORM中,元类使得API调用更为简洁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

不会很常用,在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()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值