<div dir="ltr">Oops, I meant to call super if necessary:<div><br></div><div><div>    @classmethod</div><div>    def __make_me_cls__(cls, arg_cls, *args, **kwargs):</div><div>        if arg_cls is C:</div><div>            pass</div><div>        elif arg_cls is D:</div><div>            args, kwargs = modified_args_for_D(args, kwargs)</div><div>        elif arg_cls is E:</div><div>            args, kwargs = modified_args_for_D(args, kwargs)</div><div>        else:</div><div>            return super().__make_me_cls__(arg_cls, args, kwargs)</div><div><br></div><div>        if cls is C:</div><div>            return C(*args, **kwargs)</div><div>        return cls.__make_me_cls__(C, *args, **kwargs)</div></div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Sat, Feb 14, 2015 at 3:15 PM, Neil Girdhar <span dir="ltr"><<a href="mailto:mistersheik@gmail.com" target="_blank">mistersheik@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">I think the __make_me__ pattern discussed earlier is still the most generic cooperative solution.  Here it is with a classmethod version too:<div><br></div><div><div>class C(D, E):</div><div>    def some_method(self):</div><div>        return __make_me__(self, C)</div><div><br></div><div>    def __make_me__(self, arg_cls, *args, **kwargs):</div><div>        if arg_cls is C:</div><div>            pass</div><div>        elif issubclass(D, arg_cls):</div><div>            args, kwargs = modified_args_for_D(args, kwargs)</div><div>        elif issubclass(E, arg_cls):</div><div>            args, kwargs = modified_args_for_D(args, kwargs)</div><div>        else:</div><div>            raise ValueError</div><div><br></div><div>        if self.__class__ == C:</div><div>            return C(*args, **kwargs)</div><div>        return self.__make_me__(C, *args, **kwargs)</div><div><br></div><div>    @classmethod</div><div>    def __make_me_cls__(cls, arg_cls, *args, **kwargs):</div><div>        if arg_cls is C:</div><div>            pass</div><div>        elif issubclass(D, arg_cls):</div><div>            args, kwargs = modified_args_for_D(args, kwargs)</div><div>        elif issubclass(E, arg_cls):</div><div>            args, kwargs = modified_args_for_D(args, kwargs)</div><div>        else:</div><div>            raise ValueError</div><div><br></div><div>        if cls == C:</div><div>            return C(*args, **kwargs)</div><div>        return cls.__make_me_cls__(C, *args, **kwargs)</div></div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote"><span class="">On Sat, Feb 14, 2015 at 7:23 AM, Steven D'Aprano <span dir="ltr"><<a href="mailto:steve@pearwood.info" target="_blank">steve@pearwood.info</a>></span> wrote:<br></span><div><div class="h5"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span>On Fri, Feb 13, 2015 at 06:03:35PM -0500, Neil Girdhar wrote:<br>
> I personally don't think this is a big enough issue to warrant any changes,<br>
> but I think Serhiy's solution would be the ideal best with one additional<br>
> parameter: the caller's type.  Something like<br>
><br>
> def __make_me__(self, cls, *args, **kwargs)<br>
><br>
> and the idea is that any time you want to construct a type, instead of<br>
><br>
> self.__class__(assumed arguments…)<br>
><br>
> where you are not sure that the derived class' constructor knows the right<br>
> argument types, you do<br>
><br>
> def SomeCls:<br>
>      def some_method(self, ...):<br>
>            return self.__make_me__(SomeCls, assumed arguments…)<br>
><br>
> Now the derived class knows who is asking for a copy.<br>
<br>
</span>What if you wish to return an instance from a classmethod? You don't<br>
have a `self` available.<br>
<br>
class SomeCls:<br>
    def __init__(self, x, y, z):<br>
        ...<br>
    @classmethod<br>
    def from_spam(cls, spam):<br>
        x, y, z = process(spam)<br>
        return cls.__make_me__(self, cls, x, y, z)  # oops, no self<br>
<br>
<br>
Even if you are calling from an instance method, and self is available,<br>
you cannot assume that the information needed for the subclass<br>
constructor is still available. Perhaps that information is used in the<br>
constructor and then discarded.<br>
<br>
The problem we wish to solve is that when subclassing, methods of some<br>
base class blindly return instances of itself, instead of self's type:<br>
<br>
<br>
py> class MyInt(int):<br>
...     pass<br>
...<br>
py> n = MyInt(23)<br>
py> assert isinstance(n, MyInt)<br>
py> assert isinstance(n+1, MyInt)<br>
<span>Traceback (most recent call last):<br>
</span>  File "<stdin>", line 1, in ?<br>
AssertionError<br>
<br>
<br>
The means that subclasses often have to override all the parent's<br>
methods, just to ensure the type is correct:<br>
<br>
class MyInt(int):<br>
    def __add__(self, other):<br>
        o = super().__add__(other)<br>
        if o is not NotImplemented:<br>
            o = type(self)(o)<br>
        return o<br>
<br>
<br>
Something like that, repeated for all the int methods, should work:<br>
<br>
py> n = MyInt(23)<br>
py> type(n+1)<br>
<class '__main__.MyInt'><br>
<br>
<br>
This is tedious and error prone, but at least once it is done,<br>
subclasses of MyInt will Just Work:<br>
<br>
<br>
py> class MyOtherInt(MyInt):<br>
...     pass<br>
...<br>
py> a = MyOtherInt(42)<br>
py> type(a + 1000)<br>
<class '__main__.MyOtherInt'><br>
<br>
<br>
(At least, *in general* they will work. See below.)<br>
<br>
So, why not have int's methods use type(self) instead of hard coding<br>
int? The answer is that *some* subclasses might override the<br>
constructor, which would cause the __add__ method to fail:<br>
<br>
    # this will fail if the constructor has a different signature<br>
    o = type(self)(o)<br>
<br>
<br>
Okay, but changing the constructor signature is quite unusual. Mostly,<br>
people subclass to add new methods or attributes, or to override a<br>
specific method. The dict/defaultdict situation is relatively uncommon.<br>
<br>
Instead of requiring *every* subclass to override all the methods,<br>
couldn't we require the base classes (like int) to assume that the<br>
signature is unchanged and call type(self), and leave it up to the<br>
subclass to override all the methods *only* if the signature has<br>
changed? (Which they probably would have to do anyway.)<br>
<br>
As the MyInt example above shows, or datetime in the standard library,<br>
this actually works fine in practice:<br>
<br>
py> from datetime import datetime<br>
py> class MySpecialDateTime(datetime):<br>
...     pass<br>
...<br>
py> t = MySpecialDateTime.today()<br>
py> type(t)<br>
<class '__main__.MySpecialDateTime'><br>
<br>
<br>
Why can't int, str, list, tuple etc. be more like datetime?<br>
<span><font color="#888888"><br>
<br>
<br>
--<br>
Steve<br>
</font></span><div><div>_______________________________________________<br>
Python-Dev mailing list<br>
<a href="mailto:Python-Dev@python.org" target="_blank">Python-Dev@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-dev" target="_blank">https://mail.python.org/mailman/listinfo/python-dev</a><br>
Unsubscribe: <a href="https://mail.python.org/mailman/options/python-dev/mistersheik%40gmail.com" target="_blank">https://mail.python.org/mailman/options/python-dev/mistersheik%40gmail.com</a><br>
</div></div></blockquote></div></div></div><br></div>
</blockquote></div><br></div>