Why Doesn't Python Raise an Error for Duplicate Class Attributes?

There’s a general attitude that emitting warnings about suspicious code is a job for static analysis tools / linters, not the runtime interpreter. This is explained a bit in this post from a related thread about emitting a warning for code like x == 2 or 3:

Even if a warning was added for this, it likely wouldn’t end up being that useful, since:

  1. It couldn’t be enabled by default, as that would be disruptive to end users[1]
  2. major linters already have rules that detect re-binding names without usage (I know PyCharm and Ruff do), so there’d be little benefit to experienced users
  3. Inexperienced users that don’t know how to use a linter also likely wouldn’t know how to enable an optional warning (point in case, do you run Python with warnings enabled, e.g. with -Wall or -X dev? I know I rarely do :wink:)

This behavior is possible because the body of a class statement is just an “ordinary” namespace where statements are executed. The body of the class is executed like any other chunk of code, and whatever names are bound at the end of execution become attributes of the class object. You’re free to bind, re-bind, and even un-bind[2] names as you like, just like in any other scope.

You’re also not limited to simple assignment statements like a = b by the way. All sorts of statements are allowed, including many that perform assignments in exactly the same way that a classic assignment statement does (obligatory: Lots of things are assignments).

Assuming that by uniqueness you mean not allowing names in a class body to be rebound after their first assignment, then enforcing uniqueness would break a lot of code.

Parts of the standard library depend on the ability to re-assign names in class bodies. For example, property and typing.overload both make use of repeated assignments to the same name using def statements. It’s also not entirely unusual to use “multi-step initialization” as a way of simplifying complex assignments. For example, rewriting this:

class Foo:
    name = a(b(c))

as this:

class Foo:
   name = c
   name = b(name)
   name = a(name)

  1. writing a warning to stdout would risk corrupting the output of a program, and many CI environments interpret anything written to stderr as a job failure. Both are undesirable ↩︎

  2. i.e. del ↩︎

3 Likes