diff --git a/README.md b/README.md index a94efdf..2b4497e 100644 --- a/README.md +++ b/README.md @@ -359,33 +359,37 @@ It is compatible with heterogeneous types. I.e., #### `as_list` By default, when `read` is [called with multiple types](#multiple-tokens), -it returns a `list` with the requested tokens. If, for some reason, you -don't need implicit conversion to a `list`, `read` can return a -generator instead. This is achieved by passing `as_list=False`, as in -`read(float, amount=10000, as_list=False)`. +it returns a generator with the requested tokens. If you want the result +as a `list` instead, pass `as_list=True`, as in +`read(float, amount=10000, as_list=True)`. -This has the advantage of avoiding unnecessary iteration to create the -list and copy the tokens into it. For example, you could use it to create -a large `numpy` array: +When reading a single token (one type with `amount=1`), `read` normally +returns the token directly (e.g., an `int` or `str`). Passing +`as_list=True` will wrap the result in a list, e.g., +`read(int, as_list=True)` returns `[5]` instead of `5`. + +Using `as_list=False` (the default) has the advantage of avoiding +unnecessary iteration to create the list and copy the tokens into it. +For example, you could use it to create a large `numpy` array: ```python import numpy as np from easyinput import read -arr = np.array(read(float, amount=1000000, as_list=False)) +arr = np.array(read(float, amount=1000000)) ``` -In the previous block of code, only one iteration through all of +In the previous block of code, only one iteration through all of the tokens takes place—the one to fill the `np.array`— whilst if `as_list` were set to -`False`, two iterations would take place: one to fill the list, and +`True`, two iterations would take place: one to fill the list, and another to fill the array. Keep in mind that the generator returned by `read` when `as_list` is -set to `True` *does not consume any input until you iterate through it*. +set to `False` *does not consume any input until you iterate through it*. This is the reason for which `read_many` does **not** support this keyword argument: it *must* consume input in order to discern -whether it should keep going or not, so it always returns +whether it should keep going or not, so it always returns multiple-token queries as lists.
@@ -683,7 +687,7 @@ a.say_word() ## Interface -- *(function)* **`easyinput.read(*types, amount=1, file=_StdIn, as_list=True)`**
+- *(function)* **`easyinput.read(*types, amount=1, file=_StdIn, as_list=False)`**
Returns tokens from the input stream specified by `file`. `_StdIn` is an alias for standard input. @@ -705,10 +709,13 @@ Returns tokens from the input stream specified by `file`. (e.g. `io.StringIO`) that specifies where to read input from. - `as_list: bool`
- If `True`, if more than one token is requested, converted - tokens are returned as a list, and thus input is - immediately consumed. Otherwise, a generator is - returned (and no input is consumed). + If `True`, the result is returned as a list. For single-token + reads, this wraps the token in a list (e.g., `[5]` instead of `5`). + For multiple-token reads, converted tokens are returned as a list, + and thus input is immediately consumed. + If `False` (the default), single-token reads return the token + directly, and multiple-token reads return a generator + (no input is consumed until iterated). - *(function)* **`easyinput.read_many(*types, amount=1, file=_StdIn)`**
Returns a generator that yields tokens from the input stream diff --git a/easyinput/tokenizer.py b/easyinput/tokenizer.py index 00e0744..66ed0fe 100644 --- a/easyinput/tokenizer.py +++ b/easyinput/tokenizer.py @@ -112,18 +112,21 @@ def multiple_tokens(self, amount, type1=str, *types): _StdIn = StdIn() -@kwd_only(file=_StdIn, amount=1, as_list=True) # Python 2 compatibility +@kwd_only(file=_StdIn, amount=1, as_list=False) # Python 2 compatibility def read(*types, **kwargs): """ Py3 signature: - `read(*types, file:iter=_StdIn, amount:int=1, as_list:bool=True)` + `read(*types, file:iter=_StdIn, amount:int=1, as_list:bool=False)` This function returns one or more tokens converted to the types specified by *types. This is the main function in the module. """ tokens, amount, as_list = _get_tokenizer(kwargs), _get_amount(kwargs), kwargs['as_list'] method, args = _select_method(tokens, types, amount, as_list) - return method(*args) + result = method(*args) + if as_list and not isinstance(result, list): + return [result] + return result @kwd_only(file=_StdIn, amount=1) # Python 2 compatibility diff --git a/test/test_amount.py b/test/test_amount.py index 3b15cab..0f61f19 100644 --- a/test/test_amount.py +++ b/test/test_amount.py @@ -33,3 +33,17 @@ def test_4(): expected = ('a', 2, 'c', 3) tokens = easyinput.read(chr, int, amount=2, file=source) assert all(inp == val for inp, val in zip(tokens, expected)) + +def test_5(): + source = io.StringIO("5 4 ") + expected = [5] + tokens = easyinput.read(int, amount = 1, as_list = True, file=source) + assert isinstance(tokens, list) + assert tokens == expected + +def test_6(): + source = io.StringIO("hello good bye") + expected = ["hello"] + tokens = easyinput.read(str, amount = 1, as_list = True, file = source) + assert isinstance(tokens, list) + assert tokens == expected