what does [[...]] mean in python?
Categories:
Understanding Python's Ellipsis (...) and Extended Slicing
![Hero image for what does [[...]] mean in python?](/img/42de7027-hero.webp)
Explore the meaning and practical applications of the ellipsis (...) in Python, particularly in the context of NumPy, extended slicing, and type hinting.
The ...
(ellipsis) in Python is a built-in constant that, while seemingly simple, serves several powerful and distinct purposes. It's often encountered in advanced scenarios, especially when working with multi-dimensional data structures like NumPy arrays or in modern Python's type hinting features. This article will demystify the ellipsis, explaining its core uses and providing practical examples.
Ellipsis in Extended Slicing
One of the most common and impactful uses of the ellipsis is in extended slicing, particularly with libraries like NumPy. When dealing with multi-dimensional arrays, ...
acts as a placeholder for 'as many colons as needed' to specify a full range of dimensions. This significantly simplifies indexing operations, making code cleaner and more readable, especially for arrays with many axes.
import numpy as np
# Create a 3D array
arr = np.arange(27).reshape(3, 3, 3)
print("Original array:\n", arr)
# Accessing the first slice along the first axis
print("\narr[0, :, :] (first slice):\n", arr[0, :, :])
# Using ellipsis to achieve the same result
print("\narr[0, ...] (first slice with ellipsis):\n", arr[0, ...])
# Accessing the last slice along the last axis
print("\narr[:, :, -1] (last slice along last axis):\n", arr[:, :, -1])
# Using ellipsis for the same result
print("\narr[..., -1] (last slice along last axis with ellipsis):\n", arr[..., -1])
# Accessing the middle slice along the second axis
print("\narr[:, 1, :] (middle slice along second axis):\n", arr[:, 1, :])
# Using ellipsis for the same result
print("\narr[:, 1, ...] (middle slice along second axis with ellipsis):\n", arr[:, 1, ...])
Demonstrating ellipsis in NumPy extended slicing for multi-dimensional arrays.
flowchart TD A["Start with N-dimensional array"] --> B{"Need to slice multiple dimensions?"} B -->|Yes| C["Use '...' as placeholder"] C --> D["Example: arr[..., index] or arr[index, ...]"] D --> E["Simplifies indexing for high-dimensional data"] B -->|No| F["Use standard slicing: arr[i, j, k]"] E --> G[End] F --> G[End]
Decision flow for using ellipsis in array slicing.
...
is particularly useful when you don't know the exact number of dimensions in advance or when you want to keep your code flexible for arrays of varying ranks.Ellipsis in Type Hinting (PEP 561)
In modern Python, the ellipsis also plays a crucial role in type hinting, especially when defining generic types or indicating an arbitrary number of arguments. This is specified in PEP 561 and is commonly seen with typing.Tuple
and typing.Callable
.
from typing import Tuple, Callable, Any
# Tuple of arbitrary length, all elements are integers
def process_int_tuple(data: Tuple[int, ...]) -> int:
return sum(data)
print(f"Sum of (1, 2, 3): {process_int_tuple((1, 2, 3))}")
print(f"Sum of (10,): {process_int_tuple((10,))}")
# Callable that takes any number of arguments of type int and returns a float
def apply_function(func: Callable[..., float], *args: int) -> float:
return func(*args)
def my_sum(*nums: int) -> float:
return float(sum(nums))
def my_avg(*nums: int) -> float:
return float(sum(nums)) / len(nums) if nums else 0.0
print(f"Apply my_sum to (1, 2, 3): {apply_function(my_sum, 1, 2, 3)}")
print(f"Apply my_avg to (10, 20): {apply_function(my_avg, 10, 20)}")
# Ellipsis as a literal value (less common, but valid)
def do_something(arg: Any):
if arg is ...:
print("Received the ellipsis literal!")
else:
print(f"Received: {arg}")
do_something(...)
do_something(123)
Examples of ellipsis in type hinting for Tuple
and Callable
.
Ellipsis as a Literal Value
Beyond slicing and type hinting, ...
is also a singleton object of type EllipsisType
(or types.EllipsisType
in older Python versions). This means you can use it as a literal value in your code, though this is less common. It's often used as a placeholder for unimplemented code or as a sentinel value.
def my_function():
# This function is not yet implemented
...
print(type(...))
# Using it as a placeholder in a dictionary
config = {
"setting_a": 10,
"setting_b": ... # To be filled later
}
print(config)
Ellipsis as a literal value and placeholder.
...
can be used as a placeholder for unimplemented code, pass
is generally preferred for empty code blocks as it's more explicit about its intent.