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.