Why does __init__ not get called?

R

Rob Conner

I'm still working on my DateTime class from last week...
Why does __init__ not get called?

The docs at
http://www.python.org/dev/doc/devel/ref/customization.html
read "If __new__() returns an instance of cls, then the new instance's
__init__() method will be invoked" and as far as I can tell cls is very
much an instance of DateTime

************
import datetime
_datetime = datetime.datetime

class DateTime(_datetime):
"""
Identical to builtin datetime.datetime, except it accepts
invalid dates and times as input.
"""
_valid = True
__dict__ = _datetime.__dict__

def __init__(self, year, month, day, *args, **kw):
print "init called"
_valid = False
self.year = year
self.month = month
self.day = day
self.args = args
self.kw = kw

def throwError():
raise ValueError, 'Invalid Date'
for method in _datetime.__dict__.keys():
if method!='__doc__':
setattr(self, method, throwError)


def __new__(cls, year, month, day, *args, **kw):
print "new called"
try:
return _datetime.__new__(cls, year, month, day, *args,
**kw)
except ValueError:
return cls
*************
 
L

Lonnie Princehouse

Uh... are you actually trying to instantiate this class?

mydate = DateTime(2005, 8, 8)

The reason I ask is that __init__ /is/ called when I run your code on
Python 2.4, provided that the above line is added to the end.
 
R

Rob Conner

Ah ok, thats interesting I hadn't even tried a valid date yet. Now how
do I get this thing to call __init__ when I pass in an invalid date and
the ValueError is thrown and caught within __new__.

dt = DateTime(2005, 02, 30)
 
R

Rob Conner

Not takers? This is my attempt to get some attention by bumping my own
post.
 
I

infidel

I think you have to call type.__new__ like this:

def __new__(cls, year, month, day, *args, **kw):
print "new called"
try:
return _datetime.__new__(cls, year, month, day, *args,
**kw)
except ValueError:
return type.__new__(cls, ...)

Are you sure you can specify arbitrary arguments to the __new__ method?
I thought they had to be the class object, the tuple of bases, and the
dictionary of names.
 
I

infidel

Are you sure you can specify arbitrary arguments to the __new__ method?
I thought they had to be the class object, the tuple of bases, and the
dictionary of names.

Nevermind, I think I was imagining metaclasses rather than just regular
overriding of __new__
 
L

Lonnie Princehouse

What kinds of illegal date values are you trying to represent? The
reason I ask is that it's not going to be as easy as subclassing
datetime... datetime is implemented in C. and so enforcement of legal
values is going to be in the C code. For the time.h functions, you're
also going to be constrained by the size of the time_t struct, which is
probably a long int on your platform. See Modules/datetimemodule.c in
the Python source.

One thing you could do would be to copy datetimemodule.c and build your
own C extension type based on it... things like MAXYEAR 9999 could be
changed that way.

The other thing would be to write a pure-python datetime class without
trying to inherit datetime.datetime.
 
R

Rob Conner

I'm out of my league too. I don't know enough about __new__ and
__init__.
I just went another route and did a wrapper for datetime, and didn't
extend it.
Thanks for the effort.

By chance... does anyone know, if I wrote a class, and just wanted to
override __new__ just for the fun of it. What would __new__ look like
so that it behaves exactly the same as it does any other time.
 
S

Steven Bethard

Rob said:
By chance... does anyone know, if I wrote a class, and just wanted to
override __new__ just for the fun of it. What would __new__ look like
so that it behaves exactly the same as it does any other time.

Simple:

class C(object):
def __new__(cls, *args, **kwargs):
return super(C, cls).__new__(cls, *args, **kwargs)

Basically, you're calling object's __new__ method, which in CPython does
something like mallocing the appropriate amount of memory, setting the
__class__ attribute of the object, etc.

Note that __new__() doesn't call __init__(). Both __new__() and
__init__() are called individually by the metaclass. For new-style
classes, "type" is the metaclass, and it's __call__() method looks
something like:

def __call__(cls, *args, **kwargs):
obj = cls.__new__()
if not isinstance(obj.__class__, cls):
return obj
obj.__class__.__init__(obj, *args, **kwargs)
return obj

(But see Objects/typeobject.c:409 for the full gory details.)

STeVe
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top