I personally don't think this is a big enough issue to warrant any changes, but I think Serhiy's solution would be the ideal best with one additional parameter: the caller's type. Something like
def __make_me__(self, cls, *args, **kwargs) and the idea is that any time you want to construct a type, instead of self.__class__(assumed arguments…) where you are not sure that the derived class' constructor knows the right argument types, you do def SomeCls: def some_method(self, ...): return self.__make_me__(SomeCls, assumed arguments…) Now the derived class knows who is asking for a copy. In the case of defaultdict, for example, he can implement __make_me__ as follows: def __make_me__(self, cls, *args, **kwargs): if cls is dict: return default_dict(self.default_factory, *args, **kwargs) return default_dict(*args, **kwargs) essentially the caller is identifying himself so that the receiver knows how to interpret the arguments. Best, Neil On Fri, Feb 13, 2015 at 5:55 PM, Alexander Belopolsky < alexander.belopol...@gmail.com> wrote: > > On Fri, Feb 13, 2015 at 4:44 PM, Neil Girdhar <mistersh...@gmail.com> > wrote: > >> Interesting: >> http://stackoverflow.com/questions/5490824/should-constructors-comply-with-the-liskov-substitution-principle >> > > Let me humbly conjecture that the people who wrote the top answers have > background in less capable languages than Python. > > Not every language allows you to call self.__class__(). In the languages > that don't you can get away with incompatible constructor signatures. > > However, let me try to focus the discussion on a specific issue before we > go deep into OOP theory. > > With python's standard datetime.date we have: > > >>> from datetime import * > >>> class Date(date): > ... pass > ... > >>> Date.today() > Date(2015, 2, 13) > >>> Date.fromordinal(1) > Date(1, 1, 1) > > Both .today() and .fromordinal(1) will break in a subclass that redefines > __new__ as follows: > > >>> class Date2(date): > ... def __new__(cls, ymd): > ... return date.__new__(cls, *ymd) > ... > >>> Date2.today() > Traceback (most recent call last): > File "<stdin>", line 1, in <module> > TypeError: __new__() takes 2 positional arguments but 4 were given > >>> Date2.fromordinal(1) > Traceback (most recent call last): > File "<stdin>", line 1, in <module> > TypeError: __new__() takes 2 positional arguments but 4 were given > > Why is this acceptable, but we have to sacrifice the convenience of having > Date + timedelta > return Date to make it work with Date2: > > >>> Date2((1,1,1)) + timedelta(1) > datetime.date(1, 1, 2) > > >
_______________________________________________ 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