forked from mrlan/EnglishPal
53 lines
1.4 KiB
Python
53 lines
1.4 KiB
Python
# from more_itertools 10.2
|
|
def always_iterable(obj, base_type=(str, bytes)):
|
|
"""If *obj* is iterable, return an iterator over its items::
|
|
|
|
>>> obj = (1, 2, 3)
|
|
>>> list(always_iterable(obj))
|
|
[1, 2, 3]
|
|
|
|
If *obj* is not iterable, return a one-item iterable containing *obj*::
|
|
|
|
>>> obj = 1
|
|
>>> list(always_iterable(obj))
|
|
[1]
|
|
|
|
If *obj* is ``None``, return an empty iterable:
|
|
|
|
>>> obj = None
|
|
>>> list(always_iterable(None))
|
|
[]
|
|
|
|
By default, binary and text strings are not considered iterable::
|
|
|
|
>>> obj = 'foo'
|
|
>>> list(always_iterable(obj))
|
|
['foo']
|
|
|
|
If *base_type* is set, objects for which ``isinstance(obj, base_type)``
|
|
returns ``True`` won't be considered iterable.
|
|
|
|
>>> obj = {'a': 1}
|
|
>>> list(always_iterable(obj)) # Iterate over the dict's keys
|
|
['a']
|
|
>>> list(always_iterable(obj, base_type=dict)) # Treat dicts as a unit
|
|
[{'a': 1}]
|
|
|
|
Set *base_type* to ``None`` to avoid any special handling and treat objects
|
|
Python considers iterable as iterable:
|
|
|
|
>>> obj = 'foo'
|
|
>>> list(always_iterable(obj, base_type=None))
|
|
['f', 'o', 'o']
|
|
"""
|
|
if obj is None:
|
|
return iter(())
|
|
|
|
if (base_type is not None) and isinstance(obj, base_type):
|
|
return iter((obj,))
|
|
|
|
try:
|
|
return iter(obj)
|
|
except TypeError:
|
|
return iter((obj,))
|