Additional Tuple Techniques
In rare cases, we might need to have different behavior based on the types of the data
elements. We have two ways to tackle this; they are as follows:
- We can use the isinstance() function to distinguish the different cases
- We can create our own subclass of numbers.Number or tuple and implement
a proper polymorphic special method names
In some cases, we'll actually need to do both so that we can include appropriate data
type conversions.
When we look back at the ranking example in the previous section, we're tightly
bound to the idea of applying rank-ordering to simple pairs. While this is the way
the Spearman correlation is defined, we might have a multivariate dataset and have
a need to do rank-order correlation among all the variables.
The first thing we'll need to do is generalize our idea of rank-order information. The
following is a namedtuple that handles a tuple of ranks and a tuple of raw data:
Rank_Data = namedtuple("Rank_Data", ("rank_seq", "raw"))
For any specific piece of Rank_Data, such as r, we can use r.rank_seq[0] to get a
specific ranking and r.raw to get the original observation.
We'll add some syntactic sugar to our ranking function. In many previous examples,
we've required either an iterable or a collection. The for statement is graceful about
working with either one. However, we don't always use the for statement, and for
some functions, we've had to explicitly use iter() to make an iterable out of a
collection. We can handle this situation with a simple isinstance() check, as shown
in the following code snippet:
def some_function(seq_or_iter):
if not isinstance(seq_or_iter,collections.abc.Iterator):
yield from some_function(iter(seq_or_iter), key)
return
Do the real work of the function using the iterable
We've included a type check to handle the small difference between the
two collections, which doesn't work with next() and an iterable, which
supports next().
In the context of our rank-ordering function, we will use this variation on the
design pattern:
def rank_data(seq_or_iter, key=lambda obj:obj):
Not a sequence? Materialize a sequence object
if isinstance(seq_or_iter, collections.abc.Iterator):