【问题标题】:Override __new__ doubts覆盖 __new__ 疑虑
【发布时间】:2012-05-11 13:38:39
【问题描述】:

我会尽量简化这里的情况,当覆盖__new__ 时,如下所示,我不知道调用 super __new__ 来完成这项工作的正确方法,是我做得好还是有其他方法这个? super().__new__(cls) 没有像我预期的那样产生正确的结果

我是python初学者,请耐心等待,我C++流利

import weakref

class A(str):
    def __init__(self,s):self.a=s
class B(str):
    def __init__(self,s):self.b=s

class P(A,B):
    manifest=weakref.WeakValueDictionary()
    def __new__(cls,a,b):
        o=P.manifest.get(a+b)
        if not o:
            print(a,b,super(P,cls))
            #i thought this first should be used because __init__ puts the values in
            #and we index the manifest with parameters [a+b]
            #o=super().__new__(cls)#produces unique results for all requests?!?
            #so i called like this and it works (either with a or b)
            o=super().__new__(cls,a)#why favoring a over b?
            #o=super().__new__(cls,b)#why favoring b over a?
            #o=super().__new__(cls,a,b)#its an error (of coz)
            P.manifest[a+b]=o
        print("using",id(o))
        return o
    def __init__(self,a,b):
        A.__init__(self,a)
        B.__init__(self,b)

p=P("a","b")
q=P("a","b")
r=P("a","x")
print(id(p),id(q),id(r))

【问题讨论】:

  • 你想做什么?此外,对内置类进行子类化通常比人们想象的更棘手,也更没用。 :-)
  • 不想用大量代码打扰你们,我试图将问题简化为(我的真实代码有一些比 A 和 B 更复杂的类),而且我倾向于从基类派生在可能的情况下,因为我不必投射和包装......但我仍在学习。有多个超类应该创建对象时的疑问?不应该是“对象”,后者由 init 装饰(可能会丢失其他超级“new”完成的一些特定操作),还是有办法调用几个“new”的所有超级不跳过代码?
  • 你没有回答这个问题:你想做什么?您的代码的目的是什么?
  • 我们询问您的目的的原因是几乎可以肯定有一种更简单的方法可以做到这一点。在 Python 中很少需要多重继承、弱引用或覆盖 __new__。
  • 它是一个支持多种类型对象的范围,在我开始弄乱多态对象之前它一直很好。上面的例子只是尝试隔离案例,了解python的对象组成和谁调用谁

标签: python python-3.x


【解决方案1】:

我怀疑(但我不确定)你试图在你的两个超级类上调用__new__,即A 和B。做到这一点的最佳方式取决于很多事情。

P.__new__ 的目的是返回一个P 的实例。所以这就是你应该创造的。这确实是super().__new__(cls,a) 会做的事情,所以应该可以正常工作,但是,您也可以直接调用str.__new__(cls, a)。

通常你实际上调用object.__new__,但由于你从str 继承你不能这样做,它会告诉你在这种情况下它是不安全的。

如果您确实想使用super()(在某些情况下这是个好主意),您通常应该在所有类中一致地使用它,所以它应该在A 和B 中使用好吧,不仅在__new__,而且在__init__

class A(str):
    def __init__(self, s):
        super().__init__(s)
        self.a = s

    def __new__(cls, s):
        return super().__new__(cls, s)

class B(str):
    def __init__(self, s):
        super().__init__(s)
        self.b = s

    def __new__(cls, s):
        return super().__new__(cls, s)

但是,这里会出现问题,因为您没有相同的函数配置文件,因为 P 有两个参数。这可能表明您的解决方案可能不是最好的。特别是因为 P 是一个以两个字符串作为参数的字符串,所以这没有多大意义。在您之前的问题中,您谈到了多态性,这是一种在一定程度上打破了多态性的模式,因为 P 与 A 和 B 没有相同的 API,因此不能互换使用。

结果是我怀疑子类化是错误的解决方案。另外,我猜您正在尝试缓存对象,以便创建具有相同参数的新对象实际上会返回相同的对象。我建议您改为使用工厂方法,而不是覆盖 __new__。

【讨论】:

  • 刚刚发现 o=super().__new__(cls,"...") 会同时调用 A 和 B new
  • @neu-rah:不。它会调用其中一个。但是,如果那个 also 调用 super,那么那个将调用另一个。这就是为什么您通常应该在所有方法中使用 super() 或不使用的原因。但是,如前所述,如果您有不同的参数,那么使用 super() 主要是没有意义的。
  • hmm 不是平行的,而是一条链……我必须先看看 MRO 才能更好地理解它
  • 我试图编写一个 vars 范围。我正在学习 python ......我习惯于“锤击”一些我不太了解的案例(这是一个),大多数时候我构建一个小代码来描述案例(我的铁砧)和锤子直到我明白为止。这就是 python 对象组合和谁调用谁的情况。它不是代码案例,而是语言自省。上面的讨论加上代码上的一些“痕迹”足以说明这个案例,谢谢,你是对的,双 str 推导绝对没有意义,现在我明白为什么了。
  • @neu-rah 我认为您应该支持 Lennart 的答案。你只接受了。 (到目前为止,唯一的赞成票来自我,刚刚完成)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-04
  • 2016-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多