An empty array in Python is almost always just an empty list: prices = []. Python has no built-in array type you have to declare first, so a pair of square brackets is the whole answer for most code:
prices = []
prices.append(19.99)
print(prices) # [19.99]
When you need typed numbers or math on whole arrays, the array module and NumPy step in. I’ll cover all three, with output from Python 3.14.7 and NumPy 2.5.3.
[[]] * 3 makes three references to one list. The comprehension makes three lists.Create an empty array in Python with []
Here’s the empty list in action, starting from nothing and growing:
prices = []
print(prices, "| type:", type(prices).__name__, "| length:", len(prices))
prices.append(19.99)
prices.append(4.50)
print(prices, "| length:", len(prices))
print()
print("[] == list():", [] == list())
Output:
[] | type: list | length: 0
[19.99, 4.5] | length: 2
[] == list(): True
[] and list() build the same thing. I use [], which is shorter and a touch faster, because it compiles to a single instruction instead of a function call.
A Python list resizes itself, so there’s no capacity to plan. You don’t need to know how many items are coming when you create it.
Lists have more tricks than this article needs. Creating an empty list in Python goes deeper on the list side.
How do I declare an empty array in Python?
You don’t, at least not the way Java or C# make you. If you’re coming from int[] scores = new int[5];, this is the Python version:
# Java: int[] scores = new int[5];
# Python: no declaration and no fixed size
scores: list[int] = [] # the type hint is optional
print(scores)
scores.append(88)
scores.append(92)
print(scores)
scores.append("ninety") # hints are not enforced when the code runs
print(scores)
Output:
[]
[88, 92]
[88, 92, 'ninety']
There’s no declaration step and no fixed size. The variable is created the moment you assign the empty list to it.
The list[int] part is a type hint. Your editor and tools like mypy use it, but Python doesn’t enforce it, which is why appending "ninety" still worked.
So “declare an empty array” in Python really means one of two things: assign [], or create a list of a fixed size up front. The next section covers the second.
If you think in Java, this table maps the declarations you already know:
| Java | Python |
|---|---|
int[] a = new int[5]; | a = [0] * 5 |
String[] a = new String[3]; | a = [None] * 3 |
List<Integer> a = new ArrayList<>(); | a = [] |
int[][] g = new int[2][3]; | g = [[0] * 3 for _ in range(2)] |
a.length / a.size() | len(a) |
The 2D row is the one to copy carefully. It uses a comprehension on purpose, for reasons the 2D section below shows.
Create an empty array of a fixed size (size n)
When you know the size and want to fill slots later, multiply a one-item list:
size = 5
print([None] * size)
print([0] * size)
print([0.0] * size)
print(["" for _ in range(size)])
print()
seats = [None] * size
seats[2] = "Ava"
print(seats, "| length:", len(seats))
Output:
[None, None, None, None, None]
[0, 0, 0, 0, 0]
[0.0, 0.0, 0.0, 0.0, 0.0]
['', '', '', '', '']
[None, None, 'Ava', None, None] | length: 5
[None] * 5 gives five empty slots you can assign by index.None is the usual “nothing here yet” placeholder. Use 0 or 0.0 when the slots will hold numbers you’ll add to.
Multiplying is safe here because None, numbers and strings can’t be changed in place. It stops being safe the moment the item is a list, which is the next section.
There’s a full comparison of the options in initializing a list of size n.
Empty 2D arrays: why [[]] * 3 goes wrong
This is the classic bug. It looks like three empty rows and isn’t:
grid = [[]] * 3
grid[0].append("x")
print("[[]] * 3 ->", grid)
print("how many real lists? ->", len({id(row) for row in grid}))
print()
grid = [[] for _ in range(3)]
grid[0].append("x")
print("comprehension ->", grid)
print()
board = [[0] * 3] * 2
board[0][0] = 9
print("[[0] * 3] * 2, set one ->", board)
Output:
[[]] * 3 -> [['x'], ['x'], ['x']]
how many real lists? -> 1
comprehension -> [['x'], [], []]
[[0] * 3] * 2, set one -> [[9, 0, 0], [9, 0, 0]]
[[]] * 3 copies the reference to one inner list three times. The id check proves it: there’s only one real list, so appending to row 0 shows up in every row.
The same thing happens with [[0] * 3] * 2. Setting one cell set it in both rows.
A list comprehension runs [] fresh for every row, so each row is its own list. For grids and matrices, see creating an empty matrix in Python.
Add items to an empty array
An empty list is only useful once you put things in it. The four common ways:
cart = []
cart.append("apples")
cart.extend(["bread", "milk"])
cart.insert(0, "coffee")
cart += ["eggs"]
print(cart)
cart.append(["salt", "pepper"]) # append adds ONE item, here a whole list
print(cart[-1], "| length:", len(cart))
Output:
['coffee', 'apples', 'bread', 'milk', 'eggs']
['salt', 'pepper'] | length: 6
append() adds one item and extend() adds each item from another list. insert(0, ...) puts one at the front, and += behaves like extend().
Watch the last line. Appending a list adds it as a single nested item, which is a common surprise when you meant extend().
There’s more on this in adding elements to an empty list.
Don’t use [] as a default argument
An empty list as a default value looks harmless and causes one of Python’s best-known bugs:
def add_item(item, cart=[]):
cart.append(item)
return cart
print(add_item("apples"))
print(add_item("bread")) # the "empty" default kept apples
print()
def add_item_fixed(item, cart=None):
if cart is None:
cart = []
cart.append(item)
return cart
print(add_item_fixed("apples"))
print(add_item_fixed("bread"))
Output:
['apples']
['apples', 'bread']
['apples']
['bread']
The default [] is created once, when the function is defined, and then reused on every call. The second call found apples still in there.
Default to None and create the empty list inside the function. That gives every call a fresh one.
Typed empty arrays with the array module
The standard library’s array module gives you a real typed array. You pick a type code when you create it:
from array import array
temps = array("d") # "d" = double-precision float
print(temps, "| length:", len(temps))
temps.append(72.5)
temps.extend([68.0, 75.25])
print(temps)
print()
ids = array("i") # "i" = signed int
for value in (1.5, "7", 2**40):
try:
ids.append(value)
except (TypeError, OverflowError) as err:
print(f"append({value!r}) -> {type(err).__name__}: {err}")
print()
print(array("i", [0]) * 5)
print("bytes per item, i and l:", array("i").itemsize, array("l").itemsize)
Output:
array('d') | length: 0
array('d', [72.5, 68.0, 75.25])
append(1.5) -> TypeError: 'float' object cannot be interpreted as an integer
append('7') -> TypeError: 'str' object cannot be interpreted as an integer
append(1099511627776) -> OverflowError: Python int too large to convert to C long
array('i', [0, 0, 0, 0, 0])
bytes per item, i and l: 4 4
array("d") holds floats and array("i") holds ints. Anything else is refused with a TypeError, and an integer too big for the type code raises OverflowError.
The payoff is memory. Each item is stored as raw bytes instead of a full Python object, which matters once you have millions of numbers.
One portability note for Mac and Linux users: type code "l" is 4 bytes on Windows, as shown, but 8 bytes on 64-bit macOS and Linux. Use "q" when you need 8 bytes everywhere.
Create an empty NumPy array
If you’re doing math on whole arrays, you probably want NumPy. Empty NumPy arrays behave differently from lists in three ways:
import numpy as np
empty = np.array([])
print(empty, "| shape:", empty.shape, "| dtype:", empty.dtype)
print("np.empty((0, 3)).shape ->", np.empty((0, 3)).shape)
print()
grown = np.append(empty, [1, 2, 3])
print("appended ints:", grown, grown.dtype)
print("with dtype=int:", np.append(np.array([], dtype=int), [1, 2, 3]))
print()
old = np.arange(1.0, 6.0) * 1.5
del old
print("np.empty(5):", np.empty(5))
print()
values = [] # collect in a list, convert once
for i in range(5):
values.append(i * 0.5)
print("list then np.array:", np.array(values))
Output:
[] | shape: (0,) | dtype: float64
np.empty((0, 3)).shape -> (0, 3)
appended ints: [1. 2. 3.] float64
with dtype=int: [1 2 3]
np.empty(5): [1.5 3. 4.5 6. 7.5]
list then np.array: [0. 0.5 1. 1.5 2. ]
First, np.array([]) is float64 by default, so appending integers quietly turns them into floats. Pass dtype=int if that matters.
Second, np.empty() doesn’t clear its memory. In my run it handed back the exact values of an array I’d just deleted, so never read from it before you fill it.
Third, don’t grow a NumPy array one item at a time. np.append() copies the whole array every call, so collect in a list and convert once. The NumPy empty array guide measures how much slower the loop is.
Check if an array is empty in Python
For a list, the idiomatic check is just not items. NumPy is where it gets interesting:
import numpy as np
items = []
print("not items ->", not items)
print("len(items) == 0 ->", len(items) == 0)
print("items == [] ->", items == [])
print()
print("np.array([]).size == 0 ->", np.array([]).size == 0)
for arr in (np.array([]), np.array([0]), np.array([1, 2])):
try:
print(f"bool({arr.tolist()}) -> {bool(arr)}")
except ValueError as err:
print(f"bool({arr.tolist()}) -> ValueError: {err}")
Output:
not items -> True
len(items) == 0 -> True
items == [] -> True
np.array([]).size == 0 -> True
bool([]) -> ValueError: The truth value of an empty array is ambiguous. Use `array.size > 0` to check that an array is not empty.
bool([0]) -> False
bool([1, 2]) -> ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
if not arr works for lists but raises ValueError on an empty NumPy array.An empty list is falsy, so if not items: reads naturally. len(items) == 0 works too, and some teams prefer it for being explicit.
Falsy doesn’t mean equal to False, though. [] == False is False, and [] is None is False too. Use is None only for a variable that might hold no list at all.
For NumPy, use arr.size == 0. Recent NumPy raises ValueError for the truth value of an empty array, which contradicts a lot of older advice that says if not arr is fine.
It’s also misleading on one item: bool(np.array([0])) is False even though the array isn’t empty. Checking if a NumPy array is empty covers the edge cases.
list, array or NumPy: which empty array should you use?
| You need | Use | Create it empty with |
|---|---|---|
| A general collection that grows | list | [] |
| A fixed number of slots | list | [None] * n |
| A grid of empty rows | list of lists | [[] for _ in range(n)] |
| Compact storage of one number type | array.array | array("d") |
| Math on whole arrays | NumPy | np.array([]) or np.zeros(n) |
For everyday scripts, the first row covers nearly everything. I reach for the array module rarely, and for NumPy the moment there’s arithmetic across the whole collection.
If you actually need an array full of starting values rather than an empty one, initializing an array in Python is the better guide.
A few more array guides that build on this one:
- Create an array of zeros in Python
- Check the length of an array
- Append to an array in Python
- Work with 2D NumPy arrays
Frequently asked questions
How do I create an empty array in Python?
Use an empty list: items = []. For typed numbers use array("d") from the array module, and for math use NumPy’s np.array([]).
How do I declare an empty array of size n in Python?
Python doesn’t declare sizes, but [None] * n or [0] * n gives you n slots to fill by index. With NumPy, np.zeros(n) does the same.
Is a Python list the same as an array?
Not exactly. A list holds any mix of types and grows freely, while array.array and NumPy arrays hold one numeric type. For most code, a list is what people mean by an array in Python.
Why does [[]] * 3 change every row?
Because it repeats a reference to one inner list three times. Use [[] for _ in range(3)] to get three separate lists.
How do I check if an array is empty?
For a list, if not items:. For a NumPy array, use arr.size == 0, because the truth value of an empty NumPy array raises ValueError.
Is np.empty() really empty?
No. It allocates memory without clearing it, so it can contain leftover values. Use np.zeros() if you need known starting values.
What type codes does the array module support?
Common ones are "i" for int, "q" for 8-byte int and "d" for float. The full table is in the Python array module documentation.
Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn