AFAIU, you want to make sure that some objects behave ("follow an interface") at an earlier time than that of the actual use. In your example, you want to know that objects are appropriate at instance creation time, not when they will actually be used.
Keeping in mind that we're talking Python here, I won't suggest assert
(what if python -O
or an environment variable PYTHONOPTIMIZE is set to 1 when your program runs?) or checking for specific types (because that unnecessarily restricts the types you can use), but I will suggest early testing functionality, something along the lines:
def __init__(self, a_number, a_boolean, a_duck, a_sequence):
self.a_number= a_number + 0
self.a_boolean= not not a_boolean
try:
a_duck.quack
except AttributeError:
raise TypeError, "can't use it if it doesn't quack"
else:
self.a_duck= a_duck
try:
iter(a_sequence)
except TypeError:
raise TypeError, "expected an iterable sequence"
else:
self.a_sequence= a_sequence
I used try… except… else
in this suggestion because I want to set the instance members only if the test succeeded, even if the code is changed or augmented. You don't have to do it so, obviously.
For function arguments and setting properties, I wouldn't do these tests in advance, I'd just use the provided objects and act on thrown exceptions, unless the suspect objects are going to be used after a lengthy process.