Reputation: 789
I am attempting to build a function that takes an iterable and returns a tuple, provided that the iterable will always be iterated over in a canonical way. For example, if the input iterable is list
or tuple
-like, I want to accept the input, but not if it is dict
-like (where there isn't a guarantee on the order of the keys). Is there any python function to detect the different between objects that are always iterated in the same order vs. those where the order could change version-to-version or depend on PYTHONHASHSEED
?
isinstance(x, collections.Sequence)
does most of what I want, but generators are not sequences. The following code seems to do what I want, but I'm not sure if I'm leaving something out or if there is a more general way to capture the idea of an ordered, but not necessarily indexable, iterable.
import collections, types
def to_tuple(x):
if isinstance(x, collections.Sequence) or isinstance(x, types.GeneratorType):
return tuple(x)
raise Exception("Cannot be iterated canonically")
Upvotes: 4
Views: 974
Reputation: 1284
You may want to check if slicing operation is defined:
def to_tuple(x):
return tuple(x[:])
That rules out dictionaries, generators, but welcomes strings, tuples, lists...
Upvotes: 1
Reputation: 280335
There's no such function. Even with generators, you'd want to be able to catch
(x for x in {1, 2, 3})
but permit
(x for x in [1, 2, 3])
I'd recommend just raising a warning if type(x) is dict
. Not even isinstance(x, dict)
, because OrderedDicts are ordered.
Upvotes: 3