Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Start with [1], print the current row, then build the next row by adding adjacent values with zeroes at the edges. This simple row-by-row method prints Pascal’s Triangle without storing previous rows.

Print the triangle one row at a time

Each row begins and ends with 1. Every value between them is the sum of the two values directly above it. For example, the middle values in [1, 2, 1] combine to make the next row, [1, 3, 3, 1].

Here is a complete function that prints each row using Python list notation:

def print_pascals_triangle(rows: int) -> None:
    if not isinstance(rows, int) or isinstance(rows, bool):
        raise TypeError("rows must be an integer")
    if rows < 0:
        raise ValueError("rows must be zero or greater")

    row = [1]
    for _ in range(rows):
        print(row)
        row = [left + right for left, right in zip([0] + row, row + [0])]

print_pascals_triangle(5)

Output:

[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]

The argument is the number of rows to print, not the index of the last row. A value of 5 prints five rows, beginning with the single-value top row. A value of 0 prints nothing; negative values are rejected instead of silently producing confusing output.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why the zero padding works

The expression [0] + row puts a zero before the current row, while row + [0] puts one after it. Pairing those lists lines up each value with its neighbor. For [1, 2, 1], the padded lists are [0, 1, 2, 1] and [1, 2, 1, 0]. Adding corresponding entries gives [1, 3, 3, 1]. The zeroes make the edge values remain 1 without a special case.

An explicit-loop version

If you are learning how the adjacent additions work, write out the loop instead of using a list comprehension:

def print_pascals_triangle(rows: int) -> None:
    if not isinstance(rows, int) or isinstance(rows, bool):
        raise TypeError("rows must be an integer")
    if rows < 0:
        raise ValueError("rows must be zero or greater")

    row = [1]
    for _ in range(rows):
        print(row)
        padded = [0] + row + [0]
        next_row = []
        for i in range(len(padded) - 1):
            next_row.append(padded[i] + padded[i + 1])
        row = next_row

print_pascals_triangle(5)

Both implementations use the same recurrence. In either one, assign a newly built list to row; do not overwrite values in the current row while also using them to calculate the next one.

Or skip the browser setup

Pascal’s Triangle is generated locally by the Python code above; a screenshot API does not calculate it. If you also need a website screenshot from Python, ScreenshotNeo offers a one-request screenshot API. The example below captures https://python.org as a WebP image. See the ScreenshotNeo API documentation for request options.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://python.org"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

ScreenshotNeo removes known cookie or consent banners, newsletter popups and chat widgets before capture; those cleanup steps can be turned off. Bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server provides screenshot tools for AI agents. The free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots. See ScreenshotNeo or sign up for the free plan.

Generate rows for reuse or centered output

Printing each row directly is convenient, but it couples generation to display. If another part of a program needs to inspect, format, or test the rows, make a generator that yields them:

def pascal_rows(rows: int):
    if not isinstance(rows, int) or isinstance(rows, bool):
        raise TypeError("rows must be an integer")
    if rows < 0:
        raise ValueError("rows must be zero or greater")

    row = [1]
    for _ in range(rows):
        yield row
        row = [left + right for left, right in zip([0] + row, row + [0])]

for row in pascal_rows(5):
    print(row)

Each yielded row is a list. The generator then rebinds row to a new list, so the row already yielded is not changed by the next iteration. To keep every row for later use, materialize the generator with list(pascal_rows(5)).

Print a centered visual triangle

print(row) displays list brackets and commas; it does not create a centered triangle. For a visual layout, convert the values to text, join them with spaces, and center each line against the widest line. The following code also handles rows=0:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
def print_centered_pascals_triangle(rows: int) -> None:
    data = list(pascal_rows(rows))
    if not data:
        return

    lines = [" ".join(map(str, row)) for row in data]
    width = max(map(len, lines))
    for line in lines:
        print(line.center(width))

print_centered_pascals_triangle(5)

The output is a text approximation of a triangle:

     1
    1 1
   1 2 1
  1 3 3 1
1 4 6 4 1

Centering is most reliable in a monospaced terminal or code block. The spaces separate numbers, but the values do not occupy equal character widths once they have different numbers of digits, so large triangles may not look perfectly symmetrical. This changes only presentation; the generated values are the same.

Choose between streaming and storing

The right implementation depends on whether the program only needs to display rows or needs to revisit them.

Approach Best for Retained row data Trade-off
Print each row as it is generated Plain list output when no later formatting is needed O(n) working data for the current and next row Uses less memory, but does not keep earlier rows
Yield rows from a generator Processing rows one at a time in another function O(n) working data, excluding anything the caller stores Flexible and streamable; a second pass requires generating the rows again unless the caller stores them
Materialize all rows Centered formatting, indexing, or repeated use O(n²) data across all rows Convenient for later access, with more memory as the row count grows

Here, n means the requested number of rows. Each new row contains one more value than the previous one, so generating n rows performs a quadratic number of additions overall. The count describes additions, not their exact running time: Python integers can grow in size, so arithmetic on very large values takes more work than arithmetic on small ones. Printing or formatting also takes time proportional to the output produced.

Centered output needs the width of the widest line before printing the first line. Storing the rows, as in the example, makes that easy. For a very large triangle where retaining all rows is undesirable, generate the rows once to determine the width, then generate them again to print. That trades a second pass of additions for lower retained memory.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Check the result and troubleshoot mistakes

  • The top row is missing or values are wrong: initialize with [1], not an empty list. The first row is the starting point for the recurrence.
  • The edge values disappear: add zero padding on both ends before pairing adjacent values. Without it, the next row has no outer pair to produce each edge 1.
  • A row contains unexpected values: build a fresh next-row list from the unchanged current row, then replace the current row. Updating a list in place while reading it mixes values from different rows.
  • The output has brackets and commas: that is what print(row) does for a Python list. Join string representations of values with spaces when you want plain text, and use center() for line alignment.
  • There is no output: check whether the requested count is zero. Zero rows is valid in the provided functions and intentionally prints nothing.
  • A negative count does not make sense for your program: reject it explicitly, as these examples do with ValueError. If you obtain the count from user input, convert the input to an integer and handle invalid text before calling the function.
  • A count such as 5.0 is rejected: it is a float, not an integer argument. Supply an integer row count; the examples also reject booleans rather than treating True as one row.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Test the behavior you depend on

A small test checks the first rows, the row count, and the boundaries. These checks can be run after defining pascal_rows:

expected = [
    [1],
    [1, 1],
    [1, 2, 1],
    [1, 3, 3, 1],
    [1, 4, 6, 4, 1],
]
actual = list(pascal_rows(5))

assert actual == expected
assert len(actual) == 5
assert all(row[0] == 1 and row[-1] == 1 for row in actual)
assert list(pascal_rows(0)) == []

These assertions check both the known sample and two useful interface expectations: requesting five rows returns five, while requesting zero returns an empty sequence.

When the row method is the right fit

The row-list approach directly mirrors the defining rule: edges are ones, and interior values come from adjacent values above. It is a practical default for printing, learning, and modest row counts. Use the generator when you want to separate calculation from output; keep a list of all rows only when later access or a centered first pass justifies the additional storage.

Frequently Asked Questions

Why is the first row written as [1]?

It is the starting row: with no preceding values, the triangle begins with a single 1.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Does this function return a list of all rows?

The printing function writes rows to the console and returns None. Use list(pascal_rows(n)) when you need a reusable collection.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.