__init__ is the initialiser

Steven D'Aprano steve+comp.lang.python at pearwood.info
Sat Feb 1 00:51:14 EST 2014


On Sat, 01 Feb 2014 15:35:17 +1100, Chris Angelico wrote:

> On Sat, Feb 1, 2014 at 2:42 PM, Steven D'Aprano
> <steve+comp.lang.python at pearwood.info> wrote:
>> I've met people who have difficulty with OOP principles, at least at
>> first. But once you understand the idea of objects, it isn't that hard
>> to understand the idea that:
>>
>> - first, the object has to be created, or constructed, or allocated
>>   if you will;
>>
>> - only then can it be initialised.
>>
>> Thus, two methods. __new__ constructs (creates, allocates) a new
>> object; __init__ initialises it after the event.
> 
> Yes, but if you think in terms of abstractions, they're both just steps
> in the conceptual process of "creating the object". If I ask GTK to
> create me a Button, I don't care how many steps it has to go through of
> allocating memory, allocating other resources, etc, etc, etc.

You deleted the part of my post where I suggested that it's only a 
historical accident that Python has two methods for constructing an 
object when most OOP languages get by with one.


> All I want is to be able to write:
> 
> foobar = Button("Foo Bar")
> 
> and, at the end of it, to have a Button that I can toss onto a window.
> That's the job of a constructor - to give me an object in a state that I
> can depend on.

You're assuming your conclusion. Why is it the job of the constructor, 
rather than the initialiser? When I buy a house, it is fully constructed, 
but it's not yet usable -- there's no bed, no fridge, no furniture of any 
sort, just a bare shell with a roof and some built-in cupboards and 
perhaps an oven. I have to initialise the house myself with whatever 
furniture I need.

Even if it's a "fully furnished house", I still have to initialise it 
before I can say it's truly usable, even if that is merely emptying my 
suitcase into the built-in robes.

The curse of the discontinuous mind: we look for hard dividing lines 
between black and white when what we really have is shades of grey. It's 
easy to tell when an int is constructed and ready to use, and sure enough 
it uses __new__ and has a do-nothing __init__. But with mutable objects, 
say a list, when is it constructed and ready to use? Suppose you want to 
create a list of items and extract the third smallest item. When is the 
list constructed and ready to use?

- Is it when the memory is allocated for the object? Obviously not, since 
we can't do anything with it yet.

- How about when the object fields are set up and made consistent? (Array 
is blanked, length set to the correct value, pointer to the class set, 
etc.) This makes a good candidate, since this is the earliest that the 
object is in a consistent state.

- Is it when the list items are placed into the array? This is also a 
good candidate, since this is the earliest that the list has the items we 
expect. Assuming we expect any -- since many lists are created as simply 
[], then populated later, this isn't exactly black and white either.

- Or when it is sorted? Probably not here, although this is the earliest 
that the user can *actually* use the list for what they wanted it for, 
namely to extract the third largest value.

When does a pile of computer parts become a computer? When the CPU is 
plugged in? When the mouse is attached? Somewhere in between? We have 
difficulty drawing dividing lines because our minds are discontinuous but 
reality is continuous.

[...]
> The difference between __new__ and __init__ is important when you write
> either method, but not when you use the class. It's like writing other
> dunder methods. You care about the distinction between __add__ and
> __radd__ when you write the methods, but in all other code, all that
> matters is that it does what you want:

Yes. And your point is? Speaking as an end user, "call the constructor" 
to refer to:

instance = MyClass(arg)

is exactly right, because the constructor is called regardless of whether 
__new__ is called alone, or __new__ and __init__.


[...]
> The two methods could have been done as a single method, __construct__,
> in which you get passed a cls instead of a self, and you call
> self=super().__construct__() and then initialize stuff. 

That would be called __new__ in Python. There's no *need* to use __init__ 
for anything (except old-style classic classes in Python 2).


-- 
Steven



More information about the Python-list mailing list