[Python-bugs-list] [ python-Bugs-537450 ] Improper object initialization

noreply@sourceforge.net noreply@sourceforge.net
Mon, 01 Apr 2002 06:43:21 -0800


Bugs item #537450, was opened at 2002-03-31 12:23
You can respond by visiting: 
http://sourceforge.net/tracker/?func=detail&atid=105470&aid=537450&group_id=5470

Category: Type/class unification
Group: Python 2.3
Status: Open
Resolution: None
Priority: 5
Submitted By: Kevin Jacobs (jacobs99)
>Assigned to: Guido van Rossum (gvanrossum)
Summary: Improper object initialization

Initial Comment:
The descr tutorial specifies this rule:

  __new__ must return an object. There's nothing that
  requires that it return a new object that is an 
  instance of its class argument, although that is the 
  convention. If you return an existing object, the 
  constructor call will still call its __init__ 
  method. If you return an object of a different 
  class, its __init__ method will be called. 

I believe that this rule adds an unnecessary wart to 
the language, since it is not appropriate to call 
__init__, especially with the same arguments as 
__new__ on an 'unexpected' class returned by __new__.
It is simple enough to check that the resulting class 
is an instance of the expected class and to only then 
call __init__.  Otherwise, it should be assumed that 
__new__ is returning a fully constructed instance of 
another class.  In the rare and obscure case that one 
does wish to call __init__ on an object of a different 
class, then it may be done manually from within 
__new__.

So basically, my argument is for explicit versus
implicit semantics.  If __new__(cls) returns an 
instance where type(instance) is not cls, then
__init__ should not be called implicitly.  The
burden should be on the programmer to explicitly
ensure that the object is properly constructed.

Here is an example where the current rule results
in confusing and apparently random behavior
(if one doesn't have initimate knowledge of the
Python implementation, that is):

class Foo(object):
  def __new__(cls, x):
    if x == 0:
      return [1,2,3]
    if x == 1:
      return 1
    if x == 2:
      return (1,2,3)
    if x == 3:
      return '1'
    if x == 4:
      return {1:1,2:2,3:3}
    else:
      return super(cls, Foo).__new__(cls)

for i in range(6):
  try:
    print 'Foo(%d) =' % i,Foo(i)
  except:
    print 'Foo(%d) failed' % i

Which under Python 2.2 results in the following output:
  Foo(0) failed
  Foo(1) = 1
  Foo(2) = (1, 2, 3)
  Foo(3) = 1
  Foo(4) failed
  Foo(5) = <__main__.Foo object at 0x8147f54>

Under the proposed new rule, the output would be
much more sensible:
  Foo(0) = [1,2,3]
  Foo(1) = 1
  Foo(2) = (1, 2, 3)
  Foo(3) = 1
  Foo(4) = {1:1,2:2,3:3}
  Foo(5) = <__main__.Foo object at 0x8147f54>

If there is agreement on this issue, I will submit
a very simple patch to address this.


----------------------------------------------------------------------

>Comment By: Tim Peters (tim_one)
Date: 2002-04-01 09:43

Message:
Logged In: YES 
user_id=31435

Thanks, Kevin!  Assigned to Guido, under the theory that it 
lands on his plate sooner or later, and better sooner.

----------------------------------------------------------------------

Comment By: Kevin Jacobs (jacobs99)
Date: 2002-04-01 09:17

Message:
Logged In: YES 
user_id=459565

Patch attached.  Passes Python descr tests and our 
extremely comprehensive in-house test suite that
tortures new-style classes in fairly gruesome ways.

Note: The ugly test to avoid calling tp_init on
      type(x) calls was intentionally left in the code, 
      to handle the case of calling type(type).
      It is very likely that the test is now unnecessary 
      and can be removed since calling tp_init on type
      objects should be safe, because they do not implement 
      their own tp_init.  However, for the sake of
      simplicity, I'm going to leave this additional 
      cleanup to Guido, or others.


----------------------------------------------------------------------

You can respond by visiting: 
http://sourceforge.net/tracker/?func=detail&atid=105470&aid=537450&group_id=5470