Reputation: 8409
I have a bit of Python code which depends on type checking. I'll try and phrase my problem in the language of math so it's clear. I have a few classes which correspond to subsets of each other and form an inheritance chain.
class Real(object):
pass
class Integer(Real):
pass
class Natural(Integer):
pass
And I have a tuples containing types. Each of these corresponds to the domain of some function.
t1 = ( Real, Real )
t2 = ( Real , Integer )
I would like to do some form of type checking such that given a another tuple ( Natural , Natural )
if every coordinate in the tuple is a subclass of the specified domains. For example for some function getcompatibles
I'd like to have:
getcompatibles( ( Real, Real ) ) = [ t1 ]
getcompatibles( ( Real, Integer ) ) = [ t1, t2 ]
getcompatibles( ( Natural, Natural ) ) = [ t1, t2 ]
getcompatibles( ( Natural, Real ) ) = [ t1 ]
The only solution I could come up with would be to run through every for domain (t1, t2) run through each of the types in __subclasses__
and check to see whether it isinstance
is True for the given input.
Thats extremely inefficient though, is there perhaps a more Pythonic way of doing this?
Upvotes: 2
Views: 1444
Reputation: 881595
def compatible_pred(obj_types, fun_signature):
if len(obj_types) != len(fun_signature): return False
return all(issubclass(of, ft) for of, ft in zip(obj_types, fun_signature))
def is_compatible(obj_types, fun_signatures=(t1, t2)):
return [t for t in fun_signatures if compatible_pred(obj_types, t)]
The is_compatible
name for something that is not a predicate is really, truly confusing: why not give it a sensible name such as getcompatibles
, so that the strongly predicate-sounding iscompatible
could be used instead for what I've had to name compatible_pred
?
Upvotes: 4
Reputation: 43487
Don't check types when you don't have to and count on exception handling - with try
/ except
to catch the instances where the expectation is violated.
In Python, which is a "lazy typed" (but strongly typed, less I upset the purists) language, calling isinstance
repeatedly will certainly cost you in overhead. The question I ask myself when facing such design questions is "If you didn't want this function to handle pairs of Naturals, why did you call it with them?" Presumably you are doing some sort of conditional branch predicated on is_compatible, I'd suggest you change that into a conditional call.
Seeing how you intend to use the result of is_compatible would allow a more focused answer.
Upvotes: 2