Python List Conversion: Convert Data Types to Lists
Practical python list conversion: converting tuples, strings, sets, generators, and ranges into lists, plus element type conversion and memory tradeoffs.
Python list conversion is one of the most frequent operations in everyday Python code. The list() constructor accepts any iterable, but the details matter: strings behave differently from tuples, generators are consumed once, and nested data can surprise you. This article covers the common conversion paths and the decisions behind them.
The list() Constructor and Iterables
The list() constructor is the foundation of python list conversion. It takes any iterable and builds a new list by iterating over it:
list((1, 2, 3)) # [1, 2, 3] list({1, 2, 3}) # [1, 2, 3] list(range(5)) # [0, 1, 2, 3, 4]
The result is always a shallow copy in the sense that the elements themselves are not copied; only the references are placed into the new list. If the elements are mutable objects, the new list shares those objects with the original container. This matters when you convert a list of dictionaries and later mutate a dictionary through one reference.
Converting Strings to Lists
Strings are iterables, but list("hello") produces ['h', 'e', 'l', 'l', 'o'] — a list of single characters. That is usually not what you want when you need to split text into words.
text = "one two three" list(text) # ['o', 'n', 'e', ' ', 't', 'w', 'o', ...] text.split() # ['one', 'two', 'three']
Use list() only when you genuinely need character-level access. For word-level conversion, str.split() is the correct tool, and it accepts a delimiter for non-whitespace separators:
"a,b,c".split(",") # ['a', 'b', 'c']
Converting Tuples, Sets, and Ranges
Tuples convert directly with list(), and the element order is preserved. Sets convert to lists as well, but the order is not guaranteed because sets are unordered. If you need deterministic ordering after converting a set, sort the result:
data = {3, 1, 2} list(data) # order varies between runs sorted(data) # [1, 2, 3]
Ranges are lazy sequences, so list(range(10)) materializes the values. For large ranges this allocates memory proportional to the number of elements; if you only need to iterate once, keep the range object instead.
Converting Generators and Other One-Pass Iterables
Generators and other iterator objects can also be passed to list(), but they are single-pass. Once converted, the generator is exhausted:
gen = (x * 2 for x in range(5)) items = list(gen) # [0, 2, 4, 6, 8] list(gen) # [] — the generator is exhausted
This is a common source of bugs. If you need the values twice, either convert once and reuse the list, or create a fresh generator for each pass.
Converting Lists to Other Types
Conversion is not one-directional. A list can become a tuple with tuple(mylist), a set with set(mylist), or a string with ", ".join(mylist) when the elements are strings. The same shallow-copy semantics apply: tuple(mylist) shares element references with the original list.
items = [1, 2, 3] tuple(items) # (1, 2, 3) set(items) # {1, 2, 3}
Converting a list to a set removes duplicates, which is often the real goal. If order matters, a set will not preserve it; use dict.fromkeys(mylist) to deduplicate while keeping insertion order.
Type Conversion Inside Lists
Sometimes the goal is not converting the container but converting the elements. A list of numeric strings often needs to become a list of integers:
values = ["1", "2", "3"] [int(v) for v in values] # [1, 2, 3] list(map(int, values)) # [1, 2, 3]
Both produce the same result, but a list comprehension is generally more readable when the transformation involves a condition:
[int(v) for v in values if v.isdigit()]
map() returns an iterator, so wrapping it in list() is required to materialize the result. For a one-off conversion, the comprehension is usually clearer.
Performance and Memory Considerations
list() and list comprehensions both allocate a new list and append elements one at a time internally. The practical difference is small for typical data sizes. The larger cost appears when you convert a large iterator just to iterate once — the list holds every element in memory while the original iterator would have streamed them.
For repeated conversions of the same data, the conversion itself is cheap, but the resulting list occupies memory for its lifetime. If you are processing a file line by line, converting the entire file iterator into a list defeats the purpose of streaming.
Choosing the Right Conversion Approach
The decision depends on what you need after the conversion. Use list() for a direct container change from any iterable. Use str.split() when converting text into words. Use a comprehension when you also need to transform or filter elements. Use sorted() when the source is unordered and you need deterministic output.
A generator that must be reused should be converted once and the resulting list stored. A range that only needs iteration should stay a range. The right choice is the one that matches how the data will be consumed, not the one with the shortest syntax.