No, [] and list() Are Not the Same in Python — Here’s Why It Matters
Think [] and list() are interchangeable? Think again.
![No, [] and list() Are Not the Same in Python — Here’s Why It Matters](/content/images/size/w1200/2025/08/0-r11z8vy38760iatq.jpg)
Don’t let the brackets fool you. Subtle differences can wreak unexpected havoc.
No, []
and list()
Are Not the Same in Python — Here’s Why It Matters
If you’re like most Python developers, you’ve likely written []
and list()
countless times — often without a second thought. After all, both give you an empty list, right?
Yes — and no.
While these two constructs appear to do the same thing, they aren’t always interchangeable. Beneath the surface lie subtle (and not-so-subtle) differences that can impact your code’s performance, readability, and even correctness.
In this article, we’re going to uncover the nuanced differences between []
and list()
in Python — when they behave the same, when they don’t, and how to choose the right one based on real-world use cases.
Let’s get into it.
The Basics: []
vs list()
At first glance, both of these create an empty list:
a = []
b = list()
print(a == b) # True
So far, so good. But here’s where things start to diverge.
Performance: Speed Isn’t Just a Buzzword
Python’s []
syntax is actually faster than calling list()
.
Benchmarking Time:
import timeit
print(timeit.timeit('[]', number=1000000))
print(timeit.timeit('list()', number=1000000))
On most machines, you’ll find that []
runs faster. Why?
[]
is a literal — it’s parsed directly by Python’s interpreter.list()
is a function call — and function calls in Python come with overhead.
If you care about micro-optimizations (e.g., in tight loops), prefer[]
overlist()
.
Readability and Intent
Sometimes the choice is not about performance — it’s about clarity.
Consider this:
usernames = list() # Looks like you're starting with an empty list
Versus:
usernames = []
Many Python developers find []
cleaner and more “Pythonic.” But in situations where you're converting from another iterable, list()
becomes necessary:
list('hello') # ['h', 'e', 'l', 'l', 'o']
So it’s not just about empty lists — it’s about context.
Function Defaults: The Pitfall of []
Let’s talk about mutable default arguments — one of the most common beginner traps in Python.
Wrong:
def append_item(item, lst=[]):
lst.append(item)
return lst
You might expect this to return a fresh list each time. But nope — it keeps reusing the same list object.
print(append_item('a')) # ['a']
print(append_item('b')) # ['a', 'b']
Correct:
def append_item(item, lst=None):
if lst is None:
lst = list() # or lst = []
lst.append(item)
return lst
Because []
in a function definition is evaluated once, when the function is defined — not each time it’s called. This leads to unexpected shared state.
Use list()
(or []
) inside the function body to avoid this trap.
Flexibility: list()
Can Take an Argument
Unlike []
, list()
can be used to convert other iterables into a list.
list(range(3)) # [0, 1, 2]
list((1, 2, 3)) # [1, 2, 3]
list({1, 2, 3}) # [1, 2, 3]
list(map(str, [1,2])) # ['1', '2']
Trying to do this with []
won’t even compile:
[]('abc') # TypeError
So list()
wins when you're converting data.
Mutability Is the Same
Regardless of how you create the list, the result is mutable:
a = []
b = list()
a.append(1)
b.append(2)
print(a) # [1]
print(b) # [2]
Both behave identically once created.
But how you create them — that’s where intention and performance matter.
Object Identity: Not Always the Same
a = []
b = []
print(a is b) # False
Each call to []
or list()
returns a new object — no shared reference.
This means:
[] == [] # True
[] is [] # False
Equality checks values. Identity checks memory addresses. Keep that in mind when using is
vs ==
.
When to Use []
- Creating an empty list (performance win).
- Readability and conciseness.
- Inside loops or functions for fresh lists.
- As a default constructor in most places.
results = []
When to Use list()
- Converting other iterables to lists.
- Avoiding mutable default argument pitfalls (inside functions).
- When clarity matters in a conversion pipeline.
- For dynamic list creation from generators or maps.
names = list(map(str.upper, ['alice', 'bob']))
Real-World Example: List Initialization in Loops
Here’s a subtle but practical case — initializing a list inside a loop.
Don’t Do This:
output = []
for _ in range(3):
output.append([])
Looks fine — but what if you did this?
output = [[]] * 3
output[0].append(1)
print(output)
You’d expect [[1], [], []]
, but get [[1], [1], [1]]
— because [] * 3
replicates the same list object.
Better:
output = [list() for _ in range(3)]
Or:
output = [[] for _ in range(3)]
This creates three independent lists.
Conclusion: It’s Not Just About Syntax
On the surface, []
and list()
may look like harmless twins. But in practice, understanding their differences is critical — especially when it comes to performance, function defaults, and converting data structures.
If you’re optimizing performance or aiming for clean, idiomatic code, reach for []
.
If you're converting iterables or guarding against shared state, list()
is your tool.
Make the choice consciously — not out of habit.
In Python, clarity counts. Know your tools, and wield them with intent.
