开发者

How can I extend Python's datetime.datetime with my own methods?

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):
    开发者_JAVA技巧    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 bit late, but the following works:

import ctypes as c

_get_dict = c.pythonapi._PyObject_GetDictPtr
_get_dict.restype = c.POINTER(c.py_object)
_get_dict.argtypes = [c.py_object]

import datetime

def millisecond(td):
    return (td.microsecond / 1000)
d = _get_dict(datetime.datetime)[0]
d['millisecond'] = millisecond

now = datetime.datetime.now()
print now.millisecond(), now.microsecond

Basically, you use ctypes to get an editable copy of the classes dictionary, and then just put your method in. I use this only to backport functions to older python versions, which I think is fairly clean. For example:

from datetime import timedelta
try:
    timedelta.total_seconds # new in 2.7
except AttributeError:
    def total_seconds(td):
        return float(td.days * 24 * 3600 + td.seconds + td.microseconds / 1e6)
    d = _get_dict(timedelta)[0]
    d['total_seconds'] = total_seconds
    # works now in 2.4


unutbu was so close to what you originally asked for:

class DateTime(datetime.datetime):
    @property
    def millisecond(self):
        return self.microsecond/1000.0

datetime.datetime = DateTime

I use this pattern to implement APIs that will only show up in 3.3 while working in 3.1 or 3.2. The rest of the class keeps right on working as it ever did, with no performance loss.

Edited to add: This only works with 2.6+ for builtins, because it only works on new-style classes. Builtins were old-style until 2.6.


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.


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


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜