no return values for __init__ ??

Helge Hess helge at mdlink.de
Thu Jan 6 16:02:29 EST 2000


Gordon McMillan wrote:
> Helge Hess writes:
> 
> What happens when a derived class chains to the base class
> __init__ and the base class __init__ changes "self"?

Good question. Depends on what one tries to accomplish with different
return values, usually it would look like:

  def __init__(self...
     s = super.__init__(self...
     if (s is not None) & (s is not self): return s
     self.a = 5
     return self

Note that I don't want to make this feature common usage. It's useful in
a relativly small problem domain, like clusters where the additional
code as shown above is acceptable.

The one real 'inconsistency' with my approach is that None has the
special meaning of self in __init__. This is no technical requirement
but would break compatibility if done otherwise (any plain __init__
would be required to return self instead of None or the default return
value would need to be changed to 'self').

BTW: I also always wondered why Python has None as the default return
value. 'self' seems better to me as one could make compound method calls
without additional work while None has no benefit I can see (maybe
better RC behaviour ?).

> How about MI?

This is related to the above.
There is no conceptual difference between __init__ returning a value and
any other method returning a value. Eg if you have 

  class A(B,C)

you need to define order explicitly. Same as above:

  s = B.__init__(self..)
  if s is not self: return s
  s = C.__init__(self..)
  if s is not self: return s

This is exactly the same like with any other method and MI.

> Make it obvious: rename the factory function to "getC()" and
> rename "_C" to "C".

Didn't get my complaint with your func. I would like to have a
consistent & simple environment. Eg in the cluster example the developer
doesn't care and doesn't need to know about the fact that he get's
returned different instances.

Eg the user just says:

  s = String("sfhakasfhad", encoding='utf8')
  -> s instanceof Utf8String(String)
  s = String("adfhasfdj", encoding='utf16')
  -> s instanceof Utf16String(String)
  s = String("asfhjasd")
  -> s instanceof CString(String)
  s = String("symbol", intern=1)
  -> s instanceof InternedString(String)

he doesn't care about private subclasses of String and he doesn't care
about special factory functions. He just want's to create an object
compliant to the String class.

> If really you want to customize the class, you can assign to
> the instance's __class__ attribute.

Ok, this is getting much nearer to my goal although it is much less
convenient. Eg this would probably break abstraction since the state of
the object needs to be converted. Returning a new object seems much
easier and more consistent to me.

> > This is called a 'class-cluster' in Objective-C and has quite
> > some advantages. Another useful application for clusters are
> > string-objects (different classes for different char widths, eg
> > Py8bitString, PyUnicodeString, ..)
> 
> And Fred's pattern is called a "factory" in a wide variety of
> languages.

Goes in the right direction. A cluster is a special kind of factory
where the produced objects are subclasses of the factory therefore
making it look very convenient for the user, see the String example
above. The discussed feature has the advantage that the user isn't
required to know about the factory, that is, it is abstract.

> Hackishness is in the eye of the beholder.

Ok ;-)

> Having "self" be a complete object when __init__ runs  means
> the language doesn't have to come up with a bunch of arcane
> rules about default constructors, order in which base class
> constructors are called etc.

I don't understand what you are trying to say. We are talking about
return values. In every invocation of __init__ the object is as complete
as it can be.

> It's what makes MI useful in Python (vs a feature that is nearly
> impossible to use, as in some other languages).

My major point is that __init__ is a method like any other and should be
treated as such. The issues related to MI and return values is *exactly*
the same as for any other MI method.
There isn't even a difference between the state as it is now since no
__init__ methods are called explicitly, so the order needs to be defined
manually in any case.

best regards
  Helge




More information about the Python-list mailing list