python类重写__new__,返回其他类的实例

发布于 2022-09-30 23:08:59 字数 1181 浏览 18 评论 0

上代码:
class A:

"""通过__new__返回其他的类"""

def __init__(self, data=None, **kwargs):
    self.data = data

def __new__(cls, *args, **kwargs):
    if kwargs.pop("another", False):
        # 返回B类的实例
        instance = B(*args, **kwargs)
        return instance
    return super().__new__(cls)

class B(A):

created_num = 0     #计数总共创建了多少实例
instance_list = []
def __init__(self, name=None, **kwargs):
    # 将实例保存在instance_list中
    self.__class__.instance_list.append(self)
    # 对实例赋值id
    self.instance_id = self.created_num
    # 每创建一个实例,实例数 + 1
    self.__class__.created_num += 1
    self.name = name
    super().__init__(**kwargs)

@property
def self_cls(self):
    return self.instance_id, self.__class__.created_num

if name == "__main__":

b = A(data=0, name='ty', another=True)
print()

如上,我通过传递参数another=True,使A返回一个B类的实例,在print()处打断点,期望的结果是b.self_cls == (0, 1), b.instance_list中只有一个实例对象。
可是事与愿违:
image.png
结果表明创建了两个实例,且当前实例是第二个(b.self_cls == (1, 2),但instance_list中的两个实例对象却又是同一个(内存地址相同),百思不得其解,希望能有大神帮忙解答,在此谢过。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

倾城泪 2022-10-07 23:08:59

把断点打在B.__init__
第一次调用栈是

B.__init__
A.__new__
main

第二次是

B.__init__
main

也就是说在A.__new__ return后, B.__init__又被调用了一次,
而正常的python对象创建的流程就是先new在init, 很合理.

如果想调用一次的话,改成下面这样就行了

    def __new__(cls, *args, **kwargs):
        if kwargs.pop("another", False):
            # 返回B类的实例
            -- instance = B(*args, **kwargs)
               -- return instance
            ++ return super().__new__(B)
        return super().__new__(cls)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文