__init__ is the initialiser
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Sun Feb 2 19:33:10 EST 2014
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
More information about the Python-list
mailing list