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

Use Python’s truth-value test: if not items: runs when items is an empty list, while if items: runs when it contains one or more elements.

items = []

if not items:
    print("The list is empty")
else:
    print("The list has items")

This is the conventional Python style recommended by PEP 8. Use len(items) == 0 when the numeric count is itself part of the logic, and check None separately when “not supplied” differs from “supplied but empty.”

Why if not items detects an empty list

Python allows any object in an if condition. It asks the object for its truth value. An object is false when its __bool__() method returns False or, when that method is absent, its __len__() method returns zero. The built-in false values include empty sequences such as [].

The not operator reverses that result. An empty list is false, so not items becomes True. A non-empty list is true, so not items becomes False.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
def describe(items):
    if not items:
        return "empty"
    return "contains items"

print(describe([]))       # empty
print(describe(["red"])) # contains items

The test checks the number of elements, not whether the elements themselves are truthy. A list containing 0, False, None, or an empty string is still non-empty:

values = [False]

if values:
    print("There is one element")  # This branch runs

Checking both empty and non-empty cases

Use the positive form when the main path needs at least one element:

queue = ["job-17", "job-18"]

if queue:
    first_job = queue.pop(0)
    print(f"Processing {first_job}")
else:
    print("Nothing is queued")

This avoids indexing an empty list. Code such as queue[0] raises IndexError when no element exists, so guard the access with if queue: or handle the exception when that is the intended design.

When len(items) == 0 is the better expression

len(items) == 0 is correct for a list and makes the count explicit:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
items = load_items()

if len(items) == 0:
    print("No items were returned")
elif len(items) == 1:
    print("Exactly one item was returned")
else:
    print(f"{len(items)} items were returned")

Use this form when the program is reasoning about a number, such as distinguishing zero, one, and many. If the only question is whether a sequence has anything in it, PEP 8 prefers if items: and if not items: over if len(items): and if not len(items):.

For a built-in list, both approaches are constant-time operations: obtaining its length does not scan every element. The difference is primarily readability and the fact that direct truth testing also communicates that the code accepts any sequence-like value with normal truth semantics.

Do not confuse None with an empty list

None and [] are both false in a Boolean context, but they often mean different things. None commonly means that no value was provided, while an empty list means a value was provided and contains zero elements.

def report(items):
    if items is None:
        print("No list was provided")
    elif not items:
        print("A list was provided, but it is empty")
    else:
        print(f"The list has {len(items)} items")

report(None)
report([])
report(["ready"])

Use is None for the absence check. Identity checks are the idiomatic way to test for the singleton None; an equality comparison can be overloaded by custom objects.

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

If absence and emptiness have the same meaning in your function, you can deliberately normalize them:

def count_items(items=None):
    return len(items or [])

Only use that shortcut when every false value should be treated as “no items.” If callers might pass another meaningful false value, keep the explicit None branch.

Equality and identity: == [] versus is []

items == [] performs an equality comparison with an empty list and works when items is a list:

items = []
if items == []:
    print("Equal to an empty list")

It is less general and less idiomatic than truth testing. A tuple, string, or another empty sequence will not compare equal to an empty list even though it is empty.

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

Never use items is [] as an emptiness test. The is operator tests object identity: whether both references point to the very same object. The literal [] creates a new list, so it normally has a different identity from items, even when both contain zero elements.

a = []
b = []

print(a == b)  # True: equal contents
print(a is b)  # False: different list objects

Reusable patterns for functions and defaults

Returning a Boolean

A function can return the truth value directly when its contract is “does this list contain anything?”:

def has_items(items):
    return bool(items)

print(has_items([]))       # False
print(has_items([1, 2, 3])) # True

In an if statement, the explicit bool() call is unnecessary. Returning items itself can also be useful when a caller wants the original list or a false value, but return bool(items) when the function promises a Boolean.

Safe default arguments

Do not use a mutable list as a default parameter. Create the list inside the function instead:

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.
def add_tag(tag, tags=None):
    if tags is None:
        tags = []
    tags.append(tag)
    return tags

The None sentinel lets the function distinguish “caller omitted the argument” from a caller who intentionally supplied an existing, possibly empty list.

Removing items only when present

Check before removing a first element or before iterating over optional data:

pending = get_pending_jobs()  # expected to return a list

while pending:
    job = pending.pop()
    process(job)

A while pending: loop naturally stops when the list becomes empty. If get_pending_jobs() may return None, normalize or branch before the loop rather than relying on an accidental false value.

Lists nested inside other data

Check the list at the level where it appears. A dictionary can exist while its list value is empty:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
payload = {"errors": []}

if not payload["errors"]:
    print("The request returned no errors")

When the key may be missing, use a default and decide whether a missing key should mean “empty”:

errors = payload.get("errors", [])
if errors:
    print("Handle errors")

If a missing key is an error that must be reported, test membership first instead of silently supplying an empty list.

Custom sequence objects and truth testing

The same syntax works for objects that implement normal truth-value behavior. Python first uses __bool__(), or falls back to __len__(). A custom class can therefore define what “empty” means:

class Batch:
    def __init__(self, records):
        self.records = records

    def __len__(self):
        return len(self.records)

batch = Batch([])
if not batch:
    print("The batch is empty")

For ordinary lists, this behavior is built in and predictable. If a third-party object has surprising truth semantics, consult its documentation or use its specific size API.

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.

Common mistakes and their fixes

Code or situation What it does Preferred fix
if len(items): Works, but expresses a number as a Boolean and is discouraged by PEP 8 for sequence checks. Use if items:.
if not len(items): Works for sized objects, but is less clear than direct truth testing. Use if not items:.
if items is []: Tests identity against a newly created list, not contents. Use if not items: or, rarely, items == [].
if items == None: Uses equality for a singleton value and can behave unexpectedly with custom objects. Use if items is None:.
if items[0]: Raises IndexError for an empty list and tests the first element’s value, not list length. Guard with if items: first.
Assuming None is a list Operations such as len(items) can raise TypeError. Handle None explicitly or normalize it.

Choosing the right form

Requirement Expression Reason
Run code only when the list is empty if not items: Idiomatic direct truth test.
Run code only when at least one item exists if items: Same rule, without negation.
Compare several count ranges count = len(items) The numeric value is part of the decision.
Distinguish missing from empty if items is None, then elif not items Separates two application states.
Compare list contents with another list items == [] or another list value Equality is the actual requirement.

Testing empty-list branches

Exercise both boundary states and a list containing false-looking values:

def label(items):
    if not items:
        return "empty"
    return "non-empty"

assert label([]) == "empty"
assert label([0]) == "non-empty"
assert label([None, False]) == "non-empty"
assert label(["value"]) == "non-empty"

If your function accepts None, add a separate test for that state and decide whether it should return a special result or raise an error. Tests should also cover the type your API promises; accepting arbitrary objects can expose truth-value behavior you did not intend.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance, readability, and reliability notes

For built-in lists, if not items and len(items) == 0 both inspect list metadata rather than traversing every element. Choose based on intent, not on a presumed speed difference. Direct truth testing is shorter, follows PEP 8, and naturally generalizes to other sequences.

Keep the check close to the operation it protects. Validate a possibly absent value before calling len(), indexing, popping, or iterating. If an API guarantees a list, fail early on invalid types instead of silently converting unrelated false values into an empty list.

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

Or skip the browser setup

If your development task also needs a webpage image for documentation, testing, or an AI workflow, ScreenshotNeo provides a separate website screenshot API; it is not a replacement for Python’s list check. One GET request returns a PNG, JPEG, WebP, or PDF. The service accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status.

For a quick capture with cURL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

The same request in Python (see the ScreenshotNeo API documentation) is:

import requests

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

In Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

ScreenshotNeo also offers an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. Its free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 shots, and every feature is available on every plan. Create a free ScreenshotNeo account.

Frequently Asked Questions

Does a list containing only False count as empty?

No. List truthiness depends on the number of elements, so [False] is non-empty even though its sole element is false.

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

Can I use the same check for a tuple or string?

Yes. Empty built-in sequences are false, so if not value: also handles an empty tuple or string. Keep the variable’s documented type clear.

What happens if the value is a generator?

Generators do not provide ordinary list-style emptiness without consuming values. Convert to a list only when buffering all values is acceptable, or iterate and track whether you received an item.

Should a function accept both None and lists?

Only if that distinction is part of its contract. Document the two states and test them separately; otherwise validate inputs and require one consistent type.

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.

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