Lately, I’ve been adding asserts to nearly every single function I make to validate every input as sort of a poor-man’s replacement for type checking or to prevent myself from accidentally inputting malformed data while developing. For example,
def register_symbol(self, symbol, func, keypress=None):
assert(isinstance(symbol, basestring))
assert(len(symbol) == 1)
assert(callable(func))
assert(keypress is None or type(keypress) is int)
self.symbols_map[symbol] = (func, keypress)
return
However, I’m worried that this goes against the idea of duck typing, and that I might be going too overboard or constricting myself unnecessarily. Can you ever have too many assert statements? When’s a good time to stop?
I only use
asserts if they provide far better diagnostics than the error messages that I would get otherwise. Your third assertmight be an example for such an assert — if
funcis not callable, you will get an error message at a completely different line of code than where the actual error is, and it might not be obvious how the non-callable object ended up inself.symbols_map. I write “might” because this depends on the rest of your code — if this is the only place whereself.symbols_mapgets updated, the assert might also be unnecessary.The first and last assert definitely are against the idea of duck-typing,
and the second one is redundant. Ifsymbolisn’t a string of length 1, chances are thatself.symbols_map[symbol]will raise aKeyErroranyway, so no need for the asserts.The last assert is also wrong —
type(keypress)cannot beNone, and type checks should be done withisinstance(). There might be very specialised applications where you cannot allow subtypes, but than the check should be performed withtype(x) is intinstead oftype(x) == int. Checking forNoneshould be done byx is None, not bytype(x) is NoneType.You should probably write a good set of unit tests — they will be far more useful than the asserts, and might make almost all of your asserts redundant.