takewhile
condition is True
We can use a function in itertools.takewhile
to check whether the input is equal to stop word, if not, keep taking input:
>>> from itertools import takewhile
>>> STOP = 'x'
>>> lst = list(takewhile(lambda inp: inp != STOP, iter(input_with_prompt, None)))
enter: 1
enter: 2
enter: 3
enter: x
>>> lst
['1', '2', '3']
Here iter(input_with_prompt, None)
will keep calling input
, because it's sentinel
argument will never be met, as input
returns str
only. This is roughly equivalent to a while True
loop, except the values are lazily calculated.
takewhile
will call __next__
on the callable_iterator
object, and apply the function on the next value, while the condition meets.
This may seem like a redundant and over complicated way of doing the same thing, however, its advantages should be apparent in following examples.
Merits :
- takewhile can be used to test for multiple stop_words:
>>> lst = list(takewhile(lambda inp: inp not in ['q', 'quit', 'Q'], iter(input_with_prompt, None)))
enter: 1
enter: 2
enter: 3
enter: quit
>>> lst
['1', '2', '3']
- Can be used to pass multiple values to the function, using another
iterator
type object, here is an example with itertools.count
that is used to provide different argument to input
at each call.
>>> from itertools import count
>>> lst = list(takewhile(
... lambda inp: inp != STOP,
... (input(f'enter val #{i} ("{STOP}" to quit): ') for i in count(1))
... ))
enter val #1 ("x" to quit): 1
enter val #2 ("x" to quit): 2
enter val #3 ("x" to quit): 3
enter val #4 ("x" to quit): x
>>> lst
['1', '2', '3']
- Can be combined with
range
or itertools.repeat
to stop either when stop_word
is encountered, or number of inputs reaches a specific value.
>>> from itertools import repeat
>>> MAX_NUM = 5
>>> lst = list(takewhile(
... lambda inp: inp != STOP,
... ((input('enter : ') for _ in range(MAX_NUM))
... ))
enter : 1
enter : 2
enter : 3
enter : 4
enter : 5
>>> lst
['1', '2', '3', '4', '5']
# ^ Here stop word is not encountered,
# but input stops when MAX_NUM is reached.
#---------------------------------------------------#
>>> lst = list(takewhile(
... lambda inp: inp != STOP,
... (input('enter : ') for _ in repeat(None, MAX_NUM))
... ))
enter : 1
enter : 2
enter : 3
enter : x
>>> lst
['1', '2', '3']
# ^ here stop word is encountered before MAX_NUM is reached.
NOTE: (f() for _ in range(n))
behaves the same as (f() for _ repeat(None, n))
, however the latter is faster when the when the loop variable is not needed.
- Can be combined with
itertools.starmap
to get nested list
for multiple stopwords.
>>> list_of_list = list(list(val)
... for val in starmap(
... iter,
... [
... (input_with_prompt, 'q'),
... (input_with_prompt, 'quit'),
... (input_with_prompt, 'Q')
... ])
... ))
enter: 1
enter: 2
enter: q
enter: 2
enter: 3
enter: 4
enter: quit
enter: 5
enter: Q
>>> list_of_list
[['1', '2'], ['2', '3', '4'], ['5']]
While this might look a like a very arcane usecase, it can be especially useful for other domains, for example optimization techniques where you want to check the intermediate steps taken to reach a specific result with different hyperparameters.
So for flexibility, takewhile
can be used, but may be at the cost of readability.