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
Photo by samsommer on Unsplash

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 [] over list().

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.

Photo by Artiom Vallat on Unsplash