Extend Python Array Using extend() Method: Complete Array Concatenation and Expansion Implementation Guide

Extend python array using extend() method

I’ve lost count of how many times I’ve needed to grow an array mid-script — new data comes in, and I need to fold it into an array I’ve already been building. The method I reach for almost every time is extend(). It’s flexible, fast, and honestly one of the more underappreciated tools in Python’s array module. Let me walk you through exactly how it works, why it behaves the way it does, and where it fits into real projects.

What Is the extend() Method?

extend() is a method on array.array objects that appends all the elements of an iterable onto the end of the array. Unlike fromlist(), which only accepts lists, extend() accepts any iterable — lists, tuples, generators, ranges, or even other array objects with a matching typecode.

array_name.extend(iterable)

Like fromlist(), it modifies the array in place and returns None.

Basic Example

import array

# Original array of integers
numbers = array.array('i', [10, 20, 30])
print("Before:", numbers)

# Extend using a list
numbers.extend([40, 50, 60])
print("After list extend:", numbers)

# Extend using a tuple
numbers.extend((70, 80))
print("After tuple extend:", numbers)

# Extend using a range
numbers.extend(range(90, 100, 5))
print("After range extend:", numbers)

Output:

Before: array('i', [10, 20, 30])
After list extend: array('i', [10, 20, 30, 40, 50, 60])
After tuple extend: array('i', [10, 20, 30, 40, 50, 60, 70, 80])
After range extend: array('i', [10, 20, 30, 40, 50, 60, 70, 80, 90, 95])

This flexibility is exactly why I prefer extend() over fromlist() in most day-to-day code.

Extending One Array With Another

Something I use constantly when merging datasets from different sources is extending one array directly with another array, as long as their typecodes match:

import array

a = array.array('i', [1, 2, 3])
b = array.array('i', [4, 5, 6])

a.extend(b)
print(a)

Output:

array('i', [1, 2, 3, 4, 5, 6])

If the typecodes don’t match, Python raises a TypeError, because it can’t safely reinterpret the raw bytes of one numeric type as another.

a = array.array('i', [1, 2, 3])
b = array.array('d', [4.5, 5.5])
a.extend(b)

Output:

TypeError: can only extend with array of same kind

Internal Working: How extend() Handles Memory

This is where it gets interesting from an implementation standpoint. Because array objects store data in contiguous, fixed-type C buffers (not scattered Python objects like a list does), extending an array means:

  1. Python determines how many new elements are coming in (when possible — for generic iterables it may need to consume the iterable first).
  2. It resizes the internal buffer, which in CPython typically involves a realloc() call under the hood, potentially over-allocating a bit to reduce the number of future reallocations.
  3. It copies the raw bytes of the new elements directly into the buffer, either via a fast bulk memcpy-style copy (when extending with another array of the same typecode) or by converting each Python object into its raw form one at a time (when extending from a list, tuple, or generator).

The array-to-array case is the fastest path because Python can copy raw memory in bulk without touching individual Python objects. Extending from a generic iterable is slightly slower because each item has to be validated and converted individually.

Performance Comparison

I like to benchmark before assuming, so here’s a quick comparison of extending with an array versus a list of the same size:

import array
import time

data_list = list(range(1_000_000))
data_array = array.array('i', data_list)

# Extend with a list
arr1 = array.array('i')
start = time.time()
arr1.extend(data_list)
print("extend with list:", time.time() - start)

# Extend with an array
arr2 = array.array('i')
start = time.time()
arr2.extend(data_array)
print("extend with array:", time.time() - start)

In my tests, extending array-to-array was noticeably faster than extending from a list, which lines up with the internal bulk-copy behavior I described above.

Real-World Use Cases

  • Merging sensor logs: I regularly append newly collected numeric readings onto a running array buffer during long data-acquisition sessions.
  • Streaming data pipelines: When reading chunks of numeric data from a socket or file, I decode each chunk into a small array and extend() it onto a master array.
  • Signal processing: Concatenating audio or signal sample arrays before running FFT or filtering operations.
  • Building lookup tables incrementally: When generating numeric tables programmatically, extend() lets me build them in stages without loading everything into memory as a list first.

Common Mistakes

  1. Trying to extend with a mismatched typecode — This is the single most common error I see. Always confirm both arrays share the same typecode before extending.
  2. Expecting a return valueextend() returns None. Don’t do numbers = numbers.extend(more).
  3. Extending with a generator more than once — Generators are exhausted after one pass. If you try to reuse the same generator object for another extend() call, it will add nothing.
  4. Confusing extend() with append()append() adds a single element; passing a list to append() would insert it as an invalid element and raise a TypeError since arrays only hold scalars of their typecode.

Debugging Tips

If extend() throws a TypeError, the first thing I check is the typecode of both objects:

print(array_a.typecode, array_b.typecode)

If they don’t match, I either rebuild one array with the correct typecode or convert it explicitly:

converted = array.array('i', [int(x) for x in array_b])
array_a.extend(converted)

Using extend() to Merge Data From Multiple Sensors or Sources

A pattern I run into often in data-collection scripts is pulling readings from several independent sources and merging them into one master array for later analysis. extend() makes this straightforward:

import array

sensor_a = array.array('i', [12, 15, 14])
sensor_b = array.array('i', [20, 22])
sensor_c = array.array('i', [8, 9, 10, 11])

combined = array.array('i')
for sensor_data in (sensor_a, sensor_b, sensor_c):
    combined.extend(sensor_data)

print(combined)

Output:

array('i', [12, 15, 14, 20, 22, 8, 9, 10, 11])

I like this pattern because it keeps each source’s data isolated until I’m ready to combine it, which makes debugging individual sources much easier if something looks off in the merged result.

extend() vs. fromlist() vs. + Operator

Arrays also support concatenation via the + operator, which creates a new array rather than modifying one in place:

a = array.array('i', [1, 2])
b = array.array('i', [3, 4])
c = a + b
print(c)

Output:

array('i', [1, 2, 3, 4])

I use + when I need a fresh array and want to keep the originals untouched, and extend() when I want to grow an existing array in place without the overhead of allocating a brand-new object.

Combining extend() With File and Stream Reading

One pattern I use a lot in practice is extending an array incrementally while reading numeric data from a file or stream in chunks, rather than loading everything into memory as one giant list first:

import array
import struct

master = array.array('i')

with open('numbers.bin', 'rb') as f:
    while chunk := f.read(4096):
        count = len(chunk) // 4
        values = struct.unpack(f'{count}i', chunk[:count * 4])
        master.extend(values)

print("Total values loaded:", len(master))

This keeps memory usage predictable even for fairly large files, since I’m processing manageable chunks at a time rather than reading everything in one shot.

Thread Safety Considerations

Something I learned the hard way is that extend(), like most mutating operations on Python built-in objects, isn’t guaranteed to be atomic from a thread-safety standpoint when multiple threads modify the same array concurrently. While CPython’s Global Interpreter Lock (GIL) prevents low-level memory corruption for a single operation, interleaving multiple extend() calls from different threads without synchronization can still produce data in an order you don’t expect. If I need to extend an array from multiple threads, I wrap the operation with a threading.Lock:

import array
import threading

shared_array = array.array('i')
lock = threading.Lock()

def add_data(values):
    with lock:
        shared_array.extend(values)

FAQs

Can extend() accept a string? No, unless the array’s typecode is a character-compatible type and even then, modern Python array module doesn’t support string typecodes the way it once did informally — you’ll want to pass numeric iterables.

Does extend() work with generators? Yes, and this is one of its biggest advantages over fromlist(), which only works with lists.

Is extend() faster than a manual append loop? Generally yes, especially when extending with another array, because the operation can leverage bulk memory copying instead of per-element Python-level overhead.

What happens if the iterable is empty? Nothing changes — the array remains as it was, and no error is raised.

Summary

extend() is the most versatile way to grow a Python array, accepting lists, tuples, generators, ranges, and other arrays, as long as typecodes align. It’s implemented efficiently at the C level, especially when extending array-to-array, making it my default choice over fromlist() for almost all real-world data expansion tasks.

References

Total
0
Shares

Leave a Reply

Previous Post
Insert value in an array using insert() method

Insert Value in an Array Using insert() Method: Complete Array Index-Based Insertion Implementation Guide

Next Post
Add items from list into array using fromlist() method in python

Add Items from List into Array Using fromlist() Method in Python: Complete Array Extension Implementation Guide

Related Posts