【python】超类简介__new__和__init__

本文介绍了如何通过元类Meta在类创建过程中添加功能,以AClass和AnotherClass为例,展示了__new__和__init__的区别,并创建了一个响应式Response类,用于简化接口返回和错误处理。

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

示例代码

class Meta(type):

    def __new__(mcs, name, bases, attrs):
        print(locals())
        return super(Meta, mcs).__new__(mcs, name, bases, attrs)

    def __init__(cls, *args, **kwargs):
    	# 获得类原来的__init__方法
        _init = _init = getattr(cls, "__init__", None)

        def cls_init(self, *args, **kwargs):
            if _init:  # 如果子类定义了__init__方法,执行它
                _init(self, *args, **kwargs)
            # 接下来做自己想做的操作
            print("inner init")
        print(locals())
        super(Meta, cls).__init__(*args, **kwargs)
        # 修改创建类的__init__方法
        setattr(cls, "__init__", cls_init)


class AClass(metaclass=Meta):
    status = 1

    def __init__(self, name):
        print(f"a init and name is {name}")


class AnotherClass(metaclass=Meta):
    status = 2

    def __init__(self, num):

        print(f"another init and num is {num}")


a = AClass("小红")
b = AClass("大红")
c = AnotherClass(1)
d = AnotherClass(100)

输出

{'mcs': <class '__main__.Meta'>, 'name': 'AClass', 'bases': (), 'attrs': {'__module__': '__main__', '__qualname__': 'AClass', 'status': 1, '__init__': <function AClass.__init__ at 0x10895b490>}, '__class__': <class '__main__.Meta'>}
{'cls': <class '__main__.AClass'>, 'args': ('AClass', (), {'__module__': '__main__', '__qualname__': 'AClass', 'status': 1, '__init__': <function AClass.__init__ at 0x10895b490>}), 'kwargs': {}, 'cls_init': <function Meta.__init__.<locals>.cls_init at 0x10895b520>, '_init': <function AClass.__init__ at 0x10895b490>, '__class__': <class '__main__.Meta'>}
{'mcs': <class '__main__.Meta'>, 'name': 'AnotherClass', 'bases': (), 'attrs': {'__module__': '__main__', '__qualname__': 'AnotherClass', 'status': 2, '__init__': <function AnotherClass.__init__ at 0x10895b5b0>}, '__class__': <class '__main__.Meta'>}
{'cls': <class '__main__.AnotherClass'>, 'args': ('AnotherClass', (), {'__module__': '__main__', '__qualname__': 'AnotherClass', 'status': 2, '__init__': <function AnotherClass.__init__ at 0x10895b5b0>}), 'kwargs': {}, 'cls_init': <function Meta.__init__.<locals>.cls_init at 0x10895b640>, '_init': <function AnotherClass.__init__ at 0x10895b5b0>, '__class__': <class '__main__.Meta'>}
a init and name is 小红
inner init
a init and name is 大红
inner init
another init and num is 1
inner init
another init and num is 100
inner init

超类写法

当一个类继承了单独type后,这个类就成了可以创建其他类对象的类
如:

class Meta(type):
	
    def __new__(mcs, name, bases, attrs):
        return super(Meta, mcs).__new__(mcs, name, bases, attrs)

    def __init__(cls, *args, **kwargs):
        super(Meta, cls).__init__(*args, **kwargs)

__new__方法

对于类来说,其创建也是会经过__new__和__init__的,和类实例一样。
元类就可以在其中就行某些操作。元类的__new__接收四个参数,都是不具名参,分别是mcs:本元类类对象,name:类的名字、bases:类的父类们、attrs:类的属性。我们可以在这对类的属性进行一些操作,下面有一个通过此方法设计response类的实例

__init__方法

init方法是在执行完new之后,已经把类对象创建出后对其执行某些操作。
此方法有也是四个参数,第一个参数是cls:__new__函数创建出的类,其余三个参数和__new__是相同的

为创建出的类的__init__添加功能

比如上边示例代码的元类的__init__方法

new和init的区别

类比类实例的创建过程,类的创建过程中的__new__函数的第一个参数实际上是元类(类实例的话是类),__init__函数的第一个参数是创建出的类本身(类实例的话是其本身)。

通过元类设计一个response类

import functools
import json


def gen_response_tuple(data=None, status_code=200, code=0, msg=""):
    """
    根据传入参数生成类似
    ({'data': {}, 'msg': 'invalid response', 'code': 10001}, 500)
    形式的元组用于接口返回。
    使用此方法以定义错误码、错误信息和http状态码
    """
    if data is None:
        data = {}
    return {"data": data, "code": code, "msg": msg, }, status_code


class ResponseMeta(type):
    """
    此元类的目的是构造
    class HttpResponse(ResponseMeta):
        __module_prefix__ = 1
        Success = 200, 0, "ok"
        Failed = 200, 1, "failed"
    此类中虽然类属性是元组,但是通过元类构造成了一个只需要传递data的偏函数
    通过此类创造的类构造的实例可以用于接口返回
    如: return HttpResponse.Success(data={})
        这样接口返回 {'data': {}, 'msg': 'ok', 'code': 10000}, 200
    当需要抛出错误时,可以使用raise HttpResponse.Success.Exception(data={})
    这样在中间件中就可以捕获到错误值是错误提示的错误,避免raise的非友好提示
    """
    prefix_codes = dict()

    def __new__(mcs, name, bases, attrs):
        module_prefix = attrs.get("__module_prefix__", None)
        # 保证在使用错误类之前定义了错误码前缀,否则项目无法启动
        assert module_prefix is not None, f"class <{name}> must define __module_prefix__"
        # 保证错误码前缀不重复,否则项目无法启动
        assert module_prefix not in mcs.prefix_codes, f"module_prefix of class <{mcs.prefix_codes[module_prefix]}> " \
                                                      f"and  class <{name}> is conflicted"
        mcs.prefix_codes[module_prefix] = name
        # 将类属性(格式不为'__a__'的)都转化为偏函数,这个函数固定了status_code和code和msg,只需要填入data
        for k in filter(lambda x: not (x.startswith("__") and x.endswith("__")), attrs.keys()):
            assert isinstance(attrs[k], tuple) and len(attrs[k]) == 3, f"attribution <{k}> of class " \
                                                                       f"<{name}> is not a tuple like (200, 1, 'ok')"

            msg = attrs[k][2]
            code = module_prefix * 10000 + attrs[k][1]
            status_code = attrs[k][0]
            attrs[k] = functools.partial(
                gen_response_tuple,
                status_code=status_code,
                code=code,
                msg=msg,
            )

            def gen_exception(data_in=None, msg_in=msg, code_in=code, status_code_in=status_code):
                return Exception(
                    json.dumps(dict(
                        msg=msg_in, code=code_in, status_code=status_code_in, data=data_in if data_in is not None else {}
                    ))
                )
            # 添加Exception属性使此属性能被raise
            setattr(attrs[k], 'Exception', functools.partial(
                gen_exception,
                status_code_in=status_code,
                code_in=code,
                msg_in=msg,
            ))
        return super(ResponseMeta, mcs).__new__(mcs, name, bases, attrs)


class BasicResponse(metaclass=ResponseMeta):
    __module_prefix__ = 1
    Success = 200, 0, 'success'
    NotFound = 200, 1, 'resource not found'
    UnknownError = 200, 9999, 'unknown error'

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值