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't think defaultdict is a good example -- I don'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'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 'A(%d)' % 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