On Mon, 03 Feb 2014 12:38:00 +1300, Gregory Ewing wrote: > Steven D'Aprano wrote: >> (In hindsight, it was probably a mistake for Python to define two >> create- an-object methods, although I expect it was deemed necessary >> for historical reasons. > > I'm not sure that all of the reasons are historical. Languages that have > a single creation/initialisation method also usually have a mechanism > for automatically calling a base version of the method if you don't do > that explicitly, and they typically do it by statically analysing the > source. That's not so easy in a dynamic language.
Just because statically-typed languages do it at compile-time doesn't mean Python couldn't do it at run-time. All the information is readily available, so Python could do something like this: # --- Untested --- # Automatically call each __new__ constructor method, starting from # the most fundamental (object) and ending with the current class. stack = [] for c in cls.__mro__: if hasattr(c, '__new__'): stack.append(c.__new__) while stack: stack.pop()(*args) Note that this design is sub-optimal: the constructor methods don't receive the newly-created instance as an argument, which makes it hard to do initialisation, and makes the whole exercise rather pointless. But with a slight change of semantics, we can make this work rather sensibly. Change the signature of __new__ to: def __new__(cls, self=None, *args, **kwargs) and the last two lines to: instance = None while stack: instance = stack.pop()(instance, *args) Is this a good design? Possibly not. But it's possible, and not terribly hard. Dynamism is no barrier to automatically calling constructors. What I meant by backwards compatibility is that prior to the introduction of new-style classes, you couldn't override __new__, only __init__. So if you had a classic class, you'd have to receive the instance: class Classic: def __init__(self, *args): ... but for new-style classes, you'd receive the class: class Newstyle(object): def __init__(cls, *args): ... which is confusing and awkward, and would make it annoying to migrate from classic classes to new-style classes. So from the backwards- compatibility perspective, __init__ has to receive the instance (self) as first argument. So the simplest way to satisfy that requirement, and still allow the class to define a constructor method that receives the class and constructs the instance, is to define a second special method. Which is what was done. > If Python only had __new__, everyone who overrode it would have to start > with an explicit call to the base class's __new__, adding a lot of > boilerplate and forcing people to learn how to make base method calls > much sooner than they would otherwise need to. There is that as well. -- Steven -- https://mail.python.org/mailman/listinfo/python-list