internal circular class references

Carl Banks pavlovevidence at gmail.com
Thu Dec 11 13:56:13 EST 2008


On Dec 11, 11:33 am, Ethan Furman <et... at stoneleaf.us> wrote:
> Good question.  My goal with NullDate is to have a date object that I
> can treat the same regardless of whether or not it actually holds a
> date.  NullDates with no value should sort before any NullDates with a
> value, should be comparable to dates as well as NullDates, and should
> support all the same methods.  In other words, I don't want to have to
> worry about whether my date object has an actual date under most
> circumstances (printing, using as dictionary keys, comparing, etc.).
>
> Does my design make more sense given these expanded requirements, or
> could it still be done simpler?  For that matter, do my requirements
> make sense?


Your requirements make sense, but I think your approach is overkill.

In particular, I think you are unnecessarily constraining yourself by
forcing the dates and non-dates to be of the same data type.  There's
usually no reason for that.  Python's duck typing allows you to write
code that supports multiple types, as long as each type provides the
same methods and operations and such.

For instance, say you have a function like this that works for
ordinary datetime.date objects:

def print_date(date):
    print date.strftime()

Now you want to be able to pass it a particular object that indicates
no date was specified.  Just define the class, like so:

class NullDate(object):
    def strftime(self):
        print "<no date specified>"

Now you could pass either a regular datetime.date object, or a
NullDate object, like so:

print_date(datetime.date(1976,10,6))
print_date(NullDate())

So, to (almost) get what you want, you need to just define a NullDate
class that implements all the methods of datetime.date.  Then the only
thing you have to do is, when you're extracting the date from your dbf
file, instead of always creating a datetime.date, create a
datetime.date object when the date is specified, and a NullDate object
when it's not.  You could write a factory function to do it, for
instance:

def create_date_or_not(dbf_cell):
    if dbf_cell.contents:
        return datetime.date.fromordinal(dbf_cell.contents)
    return NullDate()

Now, you did throw one little curveball into the requirements above:
that NullDate needs to be comparable with datetime.date objects.  I'd
handle this by subclassing datetime.date to allow comparisons with
NullDates.

class ValidDate(datetime.date):
    def __eq__(self,other):
        if isinstance(other,NullDate):
            return False
        return super(ValidDate,self).__eq__(other)
    # and so on

class NullDate(object):
    def __eq__(self,other):
        if isinstance(other,NullDate):
            return True
        return False
    # note: in Python 3.0 you would want to throw exceptions
    # for unexpected types

Then use ValidDate instead of datetime.date when the date is
specified.


Carl Banks



More information about the Python-list mailing list