views:

38

answers:

3

I'm currently using an assert statement with isinstance. Because datetime is a subclass of date, I also need to check that it isn't an instance of datetime. Surely there's a better way?

from datetime import date, datetime

def some_func(arg):
    assert isinstance(arg, date) and not isinstance(arg, datetime),\
        'arg must be a datetime.date object'
    # ...
+1  A: 

The Python way is not to check it, just go ahead and let your code do what it needs to do, and if the object doesn't have a required method or something, the code will fail with an exception at the point where that method will be called. This is called duck typing and it is part of what makes Python so flexible.

Now, if you really can't accept a datetime.datetime object... well, why can't you? A datetime can do anything a date can do, so I can't imagine what reason you'd have for disallowing a datetime, or indeed any subclass of date.

If you really really have a good reason for doing this (I guess maybe as a debugging thing, but even then, I don't get it...):

assert type(arg) == datetime.date
David Zaslavsky
I'm writing a graph plotting function for day-over-day data, and if you pass in a `datetime` object, the information it spits is gibberish (but may look correct at first glance). For this reason, I'd rather raise an exception than spit out data that could leave a user of my library rather baffled and scratching their head for a while. If an exception was raised somewhere I wouldn't bother doing this, but since it might confuse someone who accidentally uses `datetime`, I'd rather raise an exception.
rmh
Thanks for your edit; that example helped! I don't know why I didn't think to use `type()`.
rmh
+3  A: 

I don't understand your motivation for rejecting instances of subclasses (given that by definition they support all the behavior the superclass supports!), but if that's really what you insist on doing, then:

if type(arg) is not datetime.date:
    raise TypeError('arg must be a datetime.date, not a %s' % type(arg))

Don't use assert except for sanity check during development (it gets turned to a no-op when you run with python -o), and don't raise the wrong kind of exception (such as, an AssertionError when a TypeError is clearly what you mean here).

Using isinstance and then excluding one specific subclass is not a sound way to get a rigidly specified exact type with subclasses excluded: after all, the user might perfectly well subclass datetime.date and add whatever it is you're so keep to avoid by rejecting instances of datetime.datetime specifically!-)

Alex Martelli
Thanks! I wouldn't normally think about doing this type of checking, but as I posted on the other response: I'm writing a graph plotting function for day-over-day data, and if you pass in a datetime object, the information it spits is gibberish (but may look correct at first glance). If an exception was raised somewhere during the execution of my function I wouldn't bother, but it confused me when I accidentally passed in a `datetime` and I wouldn't want to do that to a user of my library.
rmh
Oh, and thanks for pointing out my misuse of `AssertionError`. A `TypeError` is indeed what I meant.
rmh
A: 

If your problem is that the graph goes wonky because it is using fractions of a day, you can test for that in other ways e.g. hasattr(arg, 'hour') distinguishes between a datetime instance and a date instance.

John Machin