(original) (raw)
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@gmail.com> wrote:
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 "", line 1, inTypeError: \_\_new\_\_() takes 2 positional arguments but 4 were given>>> Date2.fromordinal(1)Traceback (most recent call last):File "", line 1, inTypeError: \_\_new\_\_() takes 2 positional arguments but 4 were givenWhy is this acceptable, but we have to sacrifice the convenience of having Date + timedeltareturn Date to make it work with Date2:>>> Date2((1,1,1)) + timedelta(1)datetime.date(1, 1, 2)