views:

68

answers:

4

I'm trying to extend Python's datetime.datetime class with a couple of extra methods. So, for example I'm doing:

import datetime

class DateTime(datetime.datetime):
    def millisecond(self):
        return self.microsecond/1000

but then if I do

>>> d = DateTime(2010, 07, 11, microsecond=3000)
>>> print d.millisecond()
3
>>> delta = datetime.timedelta(hours=4)
>>> newd = d + delta
>>> print newd.millisecond()
AttributeError: 'datetime.datetime' object has no attribute 'millisecond'

This is obviously because doing d + delta calls the datetime.datetime.__add__() method which returns a datetime.datetime object.

Is there any way I can make this datetime.datetime object convert to a DateTime object? Or would I have to reimplement all the operators in my DateTime subclass to return the correct type?

A: 

You could use monkeypatching to add the method to the original DateTime.

Fabian
Or mixins: <http://en.wikipedia.org/wiki/Mixin>. (Override `datetime.datetime.__bases__`.)
katrielalex
+2  A: 

In this case I'd prefer simple free-standing functions:

import datetime
def millisecond(dt):
    return dt.microsecond/1000

Mixins are possible in Python (see the comment), but I think in such cases they are superfluous.

Philipp
A: 

At the simplet level, you can do something like this

import datetime
def millisecond(self):
    return self.microsecond/1000

datetime.datetime.millisecond = millisecond

However a dynamically inserted mixin might be neater - or just defining a function and passing it an instance of datetime.

In general monkeypatching isn't very Pythonic - its more of a Ruby approach to problems.

Glenjamin
+1  A: 

I tried implementing a solution using monkey-patching but ran into the error:

TypeError: can't set attributes of built-in/extension type 'datetime.datetime'

This happens with datetime.datetime.millisecond = millisecond and GvR's __metaclass__=monkeypatch_class.

Perhaps datetime.so can not be monkey-patched. If that's true, then you might want to consider this:

import datetime

class DateTime(datetime.datetime):
    @property
    def millisecond(self):
        return self.microsecond/1000.0
    def __add__(self,other):
        result=super(DateTime,self).__add__(other)
        result=DateTime(result.year,
                        result.month,
                        result.day,
                        result.hour,
                        result.minute,
                        result.second,
                        result.microsecond,
                        result.tzinfo)        
        return result
    __radd__=__add__

d = DateTime(2010, 07, 11, microsecond=3000)
print d.millisecond
# 3.0

delta = datetime.timedelta(hours=4)
newd = d + delta
print newd.millisecond
# 3.0

# This uses __radd__
newd = delta + d
print newd.millisecond
# 3.0
unutbu