Hmm... super *is* a problem, because if we super, we can end up asking 
superclasses that we then won't know how to mimic. So what we really want is to 
move the superclasses we can mimic to the front of the MRO. If none of those 
can indirectly mimic the base class, then we try the other classes in the MRO 
to see if we can get a partial upgrade.

On 15-02-13, Neil Girdhar  wrote:
> I think it works as Isaac explained if __make_me__ is an instance method that 
> also accepts the calling class type.
> 
> On Fri, Feb 13, 2015 at 8:12 PM, Ethan Furman <Python-Dev@python.org 
> <et...@stoneleaf.us')" target="1">et...@stoneleaf.us> wrote:
> 
> > On 02/13/2015 02:31 PM, Serhiy Storchaka wrote:
> > > On 13.02.15 05:41, Ethan Furman wrote:
> > >> So there are basically two choices:
> > >>
> > >> 1) always use the type of the most-base class when creating new instances
> > >>
> > >> pros:
> > >> - easy
> > >> - speedy code
> > >> - no possible tracebacks on new object instantiation
> > >>
> > >> cons:
> > >> - a subclass that needs/wants to maintain itself must override all
> > >> methods that create new instances, even if the only change is to
> > >> the type of object returned
> > >>
> > >> 2) always use the type of self when creating new instances
> > >>
> > >> pros:
> > >> - subclasses automatically maintain type
> > >> - much less code in the simple cases [1]
> > >>
> > >> cons:
> > >> - if constructor signatures change, must override all methods which
> > >> create new objects
> > >
> > > And switching to (2) would break existing code which uses subclasses with 
> > > constructors with different signature (e.g.
> > > defaultdict).
> > 
> > I don&#39;t think defaultdict is a good example -- I don&#39;t see any 
> > methods on it that return a new dict, default or
> > otherwise. So if this change happened, defaultdict would have to have its 
> > own __add__ and not rely on dict&#39;s __add__.
> > 
> > 
> > > The third choice is to use different specially designed constructor.
> > >
> > > class A(int):
> > >
> > > --> class A(int):
> > > ... def __add__(self, other):
> > > ... return self.__make_me__(int(self) + int(other))
> > >
> > > ... def __repr__(self):
> > > ... return &#39;A(%d)&#39; % self
> > 
> > How would this help in the case of defaultdict? __make_me__ is a class 
> > method, but it needs instance info to properly
> > create a new dict with the same default factory.
> > 
> > --
> > ~Ethan~
> > 
> > 
> > _______________________________________________
> > Python-Dev mailing list
> > https://mail.python.org/mailman/listinfo/python-dev(javascript:main.compose('new',
> >  't=Python-Dev@python.org>
> > <a href=)
> > Unsubscribe: 
> > https://mail.python.org/mailman/options/python-dev/mistersheik%40gmail.com
> > 
> >
import inspect

class A:
    def __init__(self, bar):
        self.bar = bar
    def foo(self):
        return self.__class__.__make_me__(A, self.bar)
    @classmethod
    def __make_me__(cls, base, *args, **kwargs):
        if base is A:
            return A(*args, **kwargs)
        else:
            return super(A, cls).__make_me__(base, *args, **kwargs)

class B(A):
    def __init__(self, bar, baz):
        self.bar = bar
        self.baz = baz
    @classmethod
    def __make_me__(cls, base, *args, **kwargs):
        if base is B:
            return B(*args, **kwargs)
        elif base is A:
            bound = inspect.signature(A).bind(*args, **kwargs)
            return cls.__make_me__(B, bound.arguments['bar'], None)
        else:
            super(A, cls).__make_me__(base, *args, **kwargs)

class C(A):
    def __init__(self):
        pass
    @classmethod
    def __make_me__(cls, base, *args, **kwargs):
        if base is C:
            return C(*args, **kwargs)
        elif base is A:
            bound = inspect.signature(A).bind(*args, **kwargs)
            return cls.__make_me__(C)
        else:
            return super(C, cls).__make_me__(base, *args, **kwargs)

class D(C, B):
    def __init__(self, bar, baz, spam):
        self.bar = bar
        self.baz = baz
        self.spam = spam
    @classmethod
    def __make_me__(cls, base, *args, **kwargs):
        if base is D:
            return D(*args, **kwargs)
        elif base is B:
            bound = inspect.signature(B).bind(*args, **kwargs)
            return cls.__make_me__(D, bound.arguments['bar'],
                                   bound.arguments['baz'], 'hello')
        else:
            return super(D, cls).__make_me__(base, *args, **kwargs)

if __name__ == '__main__':
    assert D('a', 'b', 'c').foo().__class__ is D
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to