[Tutor] : unexpected behavior with assignment in __init__

Kent Johnson kent37 at tds.net
Wed Jan 25 12:07:46 CET 2006


Orri Ganel wrote:
> Hello all,
>     I was just messing around with a suggestion w chun (wescpy at gmail 
> dot com) gave (to make a class that handles time, ie:
> 
>> >> import myTime
>> >> c = myTime.myTime(10,30)
>> >> print c
> 10:30
>> >> d = myTime.myTime(8,45)
>> >> print c + d
> 19:15
> 
> etc), and I was trying to make it like the str class in that, by 
> default, when you str() a string, it returns the same object.  I tried 
> to do this with the following (irrelevant code removed), but it didn't 
> work, despite original indications to the contrary, and I'm not sure I 
> understand why:
> 
>  >>> class stime:
>     def __init__(self, minutes, seconds=None):
>         if seconds is None:
>             if minutes.__class__ is stime:
>                 print minutes, type(minutes), minutes.__class__, id(minutes)
>                 self = minutes
>                 print self, type(self), self.__class__, id(self)
>     def __repr__(self):
>         return str(self)
>     def __str__(self):
>         return "%02d:%02d" % (self.minutes, self.seconds)

Assigning to self in __init__() just changes the value of the local 
variable, it has no effect outside the method; inside a method, self is 
just a method parameter, nothing more. There is some magic that gives 
self its value for the call.

When __init__() is called the new instance has already been created, you 
are just initializing its state, not creating the object. You can do 
what you want by defining stime.__new__(). __new__() is responsible for 
actually creating a new object. You still have to check for an stime 
instance in __init__() because __init__() will be called even when 
__new__() returns an existing instance.

Here is a simplified example:

  >>> class stime(object):
  ...   def __new__(cls, value):
  ...     if isinstance(value, cls):
  ...       return value
  ...     return object.__new__(cls, value)
  ...   def __init__(self, value):
  ...     print 'stime.__init__', value
  ...     if isinstance(value, stime):
  ...       return
  ...     self.value = value
  ...
  >>> a=stime(3)
stime.__init__ 3
  >>> a
<__main__.stime object at 0x00A32E90>
  >>> b=stime(a)
stime.__init__ <__main__.stime object at 0x00A32E90>
  >>> b
<__main__.stime object at 0x00A32E90>
  >>> a.value
3
  >>> b.value
3
  >>> a is b
True

Kent
> 
>  >>> a = stime(10,3)
>  >>> b = stime(a)
> 10:03 <type 'instance'> __main__.stime 12858832
> 10:03 <type 'instance'> __main__.stime 12858832
>  >>> # so, it appears to work, because it prints the same id both times. 
> however,
> # . . .
>  >>> id(a)
> 12858832
>  >>> id(b)
> 12858792
>  >>> # they're not the same anymore! and that's not all:
>  >>> a
> 10:03
>  >>> b
> 
> Traceback (most recent call last):
>   File "<pyshell#163>", line 1, in -toplevel-
>     b
>   File "C:/Documents and Settings/Cookie/Desktop/stime.py", line 20, in 
> __repr__
>     return str(self)
>   File "C:/Documents and Settings/Cookie/Desktop/stime.py", line 22, in 
> __str__
>     return "%02d:%02d" % (self.minutes, self.seconds)
> AttributeError: stime instance has no attribute 'minutes'
> 
> So, not only do the two variables not refer to the same object after 
> exiting __init__, but b is now a broken stime instance.  Anyone know 
> what's going on?
> 
> Thanks in advance,
> Orri
> 
> -- 
> Email: singingxduck AT gmail DOT com
> AIM: singingxduck
> Programming Python for the fun of it.
> 
> 
> ------------------------------------------------------------------------
> 
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> http://mail.python.org/mailman/listinfo/tutor




More information about the Tutor mailing list