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.pyt...@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 -- https://mail.python.org/mailman/listinfo/python-list