sub-classing the types in the builtin module datetime

Colin J. Williams cjw at sympatico.ca
Thu Aug 16 23:33:43 CEST 2007


attn.steven.kuo at gmail.com wrote:
> On Aug 15, 5:54 pm, "Colin J. Williams" <c... at sympatico.ca> wrote:
>> I posted this about 5 hours ago, but it seems to have gone astray.
> 
> 
> (snipped)
> 
>>  >
>>  >> I wish to sub-class (if that's the right word) datetime and to use a
>>  >> different signature for the constructor.
>>  >>
>>  >> The second part has gone smoothly, but it is difficult to access the
>>  >> type's methods from the sub-class instance.
>>  >>
>>  >> I'm beginning to wonder whether it might might be simpler to write my
>>  >> own Date class.
>>  >>
>>  >> Does anyone have any comments please?
>>  >>
>>  >> Colin W.
> 
> (snipped)
> 
> 
>> Yes, I should have posted an example, but I thought that others might
>> have experienced the problem.
>>
>> It is illustrated at the bottom of this script:
>>
>> # subClassing.py
>>
>> import datetime
>> import new
>> import sys
>> import types
>>
>> class Date(datetime.datetime):
>>    ''' Date(s) -> a date object.__class__
>>          where s is an 8 digit string'''
>>
>>    def __new__(cls, YYmmdd):
>>      ''' YYmmdd is a string, in the form yyyymmdd i.e. 8 digits.
>>      or            a 3-tuple of integers in the form (y, m, d)
>>      or            a 6-tuple of integers in the form (y, m, d, h, m,
>> s) '''
> 
> 
> (snipped)
> 
>> a= datetime.datetime(2007, 7, 31)
>> d= Date('20070731')
>> tm= datetime.time(1, 2)
>> try:
>>    print a.today()
>> #  print d.today()        # grief
>>    print a.now()
>> #  print d.now()          # grief
>>    print a.combine(a, tm)  # OK, but  why not a.combine(tm)?
>> #  e= d.combine(d, tm)    # grief
>>    print a.utcnow()
>> #  print d.utcnow()       # grief
>>    print a.ctime()
>>    print d.ctime()
>> except:
>>    print 'Grief'
>>    print sys.exc_info()
>>
>> Colin W.
> 
> 
> 
> 
> 
> This problem arises when you change the function signature of __new__.
> I'm a little unclear as to why but it seems for the classmethods
> (thosed marked with the METH_CLASS flag in the C source code), you
> need to arrange to bypass the normal method resolution (I used a
> metaclass
> to do this):
> 
> 
> 
> import datetime
> 
> class Date(datetime.datetime):
>     pass
> 
> class FixClassMethods(type):
>     def __init__(cls, classname, bases, classdict):
>         # add strptime if using Python 2.5
>         flagged_as_meth_class = ('today', 'now', 'fromtimestamp',
>         'fromordinal', 'now', 'utcnow', 'utcfromtimestamp', 'combine')
>         for meth in flagged_as_meth_class:
>             setattr(cls, meth, getattr(datetime.datetime, meth))
> 
> class DateChangesNewSignature(datetime.datetime):
>     @staticmethod
>     def str2ymd(strval):
>         yyyy, mm, dd = (int(substr) for substr in (strval[:4],
>             strval[4:6], strval[6:]))
>         return yyyy, mm, dd
> 
>     def __new__(cls, strval):
>         yyyy, mm, dd = DateChangesNewSignature.str2ymd(strval)
>         return super(DateChangesNewSignature,cls).__new__(cls, yyyy,
> mm,
>                 dd)
>     def __init__(self, strval):
>         yyyy, mm, dd = DateChangesNewSignature.str2ymd(strval)
>         super(DateChangesNewSignature, self).__init__(yyyy, mm,
>                 dd)
> 
> class DLast(DateChangesNewSignature):
>     __metaclass__ = FixClassMethods
> 
> f = Date(2007,07,07)
> print f
> print f.today()
> 
> f2 = DateChangesNewSignature("20070707")
> print f2
> try:
>     print f2.today()
> except TypeError, e:
>     print str(e)
>     print "Uh?"
> 
> 
> f3 = DLast("20070707")
> print f3
> print f3.today()
> 
> 
> I get:
> 
> 2007-07-07 00:00:00
> 2007-08-16 12:57:41.480679
> 2007-07-07 00:00:00
> __new__() takes exactly 2 arguments (9 given)
> Uh?
> 2007-07-07 00:00:00
> 2007-08-16 12:57:41.483104
> 
> 
> --
> Hope this helps,
> Steven
> 
Steven,

Many thanks, I'll try this out tomorrow.

Colin W




More information about the Python-list mailing list