Skip to content

NAM107: a generator under a name that sounds like a list

Junior

A function with yield in it is a generator. Calling it returns an iterator that produces values one at a time, and only once. A caller who thinks they got a list can loop over it a second time and get nothing.

def collect_entry(root):  # NAM107: contains yield
    for path in root.iterdir():
        yield path


def iter_entries(root):  # says it is lazy
    for path in root.iterdir():
        yield path

To fix it, name it with a lazy prefix such as iter_, walk_ or generate_, or end the name with a plural (entries).

This check is off unless you turn it on with --select NAM107.

Senior

The bug from an unexpected generator surfaces two loops later, far from the function: the second for finds the iterator exhausted, or len() raises a TypeError. A name that says "lazy" or "many" warns the caller to wrap it in list() when they need to reuse it.

It stays quiet on:

  • a plural last word: items, values, user_records.
  • a lazy prefix: iter_, walk_, gen_, generate_, stream_, scan_, traverse_, produce_, yield_, enumerate_, chunk_.
  • dunders.
  • a yield that belongs to a protocol: a pytest fixture, a @contextmanager, an @asynccontextmanager, a pluggy @hookimpl wrapper. There the noun name is correct (db_session, client).

The check is opt-in because it reports too much in some codebases. In a protocol-heavy library, a generator method is often the interface itself, such as an auth flow that yields requests.

Expert

The leading underscores come off before the prefix test, so _walk counts as lazy. The suggested name keeps a private name private: _entry suggests _iter_entry. The plural test is crude: the last word ends in s and not in ss, so status passes for a plural and class doesn't.

The corpus rate is what keeps it opt-in: 17.08 per thousand functions in httpx, 14.75 in rich and 10.82 in click, against 2.22 in CPython. The false-positive class is the undecorated protocol generator: an abstract method on a base class, or a generator-based flow where yield request is the API. Telling those apart from a misnamed helper needs either decorator conventions that don't exist yet, or knowledge of the base class, which this AST-only design doesn't have. It stays opt-in until a narrower detector brings the rate down.