Override __new__ doubts
Asked Answered
T

1

3

I will try to simplify the case here, when overriding __new__ as below I don't know the correct way of calling super __new__ to do the job, am I doing it ok or is there other way of doing this? super().__new__(cls) is not producing correct results as I expected

I'm a python beginner, please be patient, I'm C++ fluent

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))
Tussle answered 11/5, 2012 at 13:38 Comment(7)
What are you trying to do? Also, subclassing the built in classes is usually more tricky and less useful than people tend to think. :-)Gigue
Not to bother you guys with tons of code i tryed to reduce the problem to that (my real code has some more complicated classes than those A and B) and its true i tend to derive from base classes when possible because i dont have to cast and wrap... but i'm still learnning. The doubt when having multiple super classes who should create the object? should not it be the "object" and latter decorated by init (risk of missing some specific operations done by other super "new"), or is there a way of calling several "new" of all the supers to not skip code?Tussle
You didn't answer the question: What are you trying to do? What is the purpose of your code?Gigue
The reason we're asking about your purpose is that there's almost certainly a simpler way to do it. It's pretty rare to need multiple inheritance, weak references or overriding __new__ in Python.Halcomb
Its a scope to support several types of objects, it was going good until i start messing with polymorphic objects. the above example was just an attempt to isolate the case and understand python's object composition and who calls whoTussle
"scope"? What does that mean?Gigue
I'm pretty sure that you are trying to think in C++ while programming in Python. That's not a good idea. It really would be more useful for you, if you explained what you are trying to do, and we can tell you how to do it in Python. It is highly unlikely that this way is the correct way. I can't see any reason to use super() in __new__ at all. Sure, it works, but why?Gigue
G
5

I suspect (but I'm not sure) that you are trying to call __new__ on both your super classes, ie A and B. The best way to do that depends on a lot of things.

The purpose of P.__new__ is to return an instance of P. So that's what you should create. This is indeed what super().__new__(cls,a) will do, so that should work fine, however, you could also just call str.__new__(cls, a) directly.

Usually you actually call object.__new__, but since you subclass from str you can't do that, it will tell you that it's unsafe in this case.

If you do want to use super() (and there are cases when this is a good idea) you should typically use it consistently in all of the classes, so it should be used in A and B as well, and not only in __new__ but also in __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)

However, that becomes problematic here as you don't have the same function profile, since P takes two parameters. This can be take as an indication that your solution may not be the best one. Especially since P is a string that takes two strings as parameters, that doesn't make much sense. In your previous question, you talked about polymorphism, and this is a pattern that break that polymorphism somewhat, as P doesn't have the same API as A and B, and hence can't be used interchangeably.

The result is that I suspect that subclassing is the wrong solution here. Also, I'm guessing you are trying to cache the objects so that creating new objects with the same parameters will actually return the same object. I suggest you instead use a factory method for that, instead of overriding __new__.

Gigue answered 11/5, 2012 at 17:28 Comment(7)
just discovered that o=super().__new__(cls,"...") will call both A and B newTussle
@neu-rah: Nope. It will call one of them. However, if that one also calls super, that one will call the other. This is why you generally should use super() in all methods, or none. However, as noted, if you have different parameters, which you do, using super() mainly stops making sense.Gigue
hmm not parallel but a chain... i have to peek on MRO to understand it better thenTussle
@neu-rah: It is unfortunate that you don't want to say what you are trying to achieve so we can tell you how to do that in Python instead of what you are trying to do now.Gigue
I was trying to code a vars scope. I'm learning python... and i use to "hammer" some cases that i don't understand well (and this is one), most of the time i build a small code to delineate the case (my anvil) and hammer on it till I understand it. This was the case of python object composition and who calls who. its not a code case its a language introspection. The above discussion plus some "traces" on code shed enough light over the case, thanks, and you are right that double str derivation makes absolute no sense and now i can see why.Tussle
@neu-rah: Yeah, you said it was a "scope". That doesn't answer what you are trying to do, or achieve, though. If the aim only was to learn more, then all is well.Gigue
@Tussle I think you should have upvoted the answer of Lennart. You only accepted it. (The only upvote until now is from me, just done)Hopefully

© 2022 - 2024 — McMap. All rights reserved.