[Python-Dev] subclassing builtin data structures
Neil Girdhar
mistersheik at gmail.com
Sat Feb 14 00:03:35 CET 2015
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.belopolsky at gmail.com> wrote:
>
> On Fri, Feb 13, 2015 at 4:44 PM, Neil Girdhar <mistersheik at 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)
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20150213/1b0427d5/attachment.html>
More information about the Python-Dev
mailing list