-->

Why are 2 of the 6 built-in constants assignable?

2020-08-17 06:19发布

问题:

In the documentation on built-in constants (excluding site constants) it's stated that:

Note: The names None, False, True and __debug__ cannot be reassigned (assignments to them, even as an attribute name, raise SyntaxError), so they can be considered “true” constants.

If I'm not mistaken, True and False became "true" contants in Python 3. (As also described in the duplicate.)

Question is, why aren't the other two (Ellipsis, NotImplemented) "true" contants? Is there a use case for re-assigning these (numpy with Ellipsis perhaps?) that has exempted them from this limitation?

Exacerbating my confusion, in the documentation for standard library types, both the Ellipsis and NotImplemented types are, behaviorally, identical to the None type. Namely:

  • They are singletons
  • They don't support special operations.

This question is not related to the proposed duplicate: Why were True and False changed to keywords in Python 3. It asks something completely different, namely, why Ellipsis and NotImplemented are not "true" constants and not why True and False where changed into ones.

回答1:

You can assign to any valid identifier that is not a keyword. What is special about True, False, None is that they are both keywords and identifiers. You can read about the reasoning for that in this question:

Why were True and False changed to keywords in Python 3

Builtins such as NotImplemented or Ellipsis are not special cases, and neither are int, list, type and so on. Assigning to NotImplemented doesn't change the builtin constant. Instead you bind the name Ellipsis to a different value in the current scope. The original Ellipsis is not changed.

Assigning to a keyword is a SyntaxError.

You can see the list of keywords by importing the keywords module.

>>> import keyword
>>> keyword.kwlist

['False',
 'None',
 'True',
 'and',
 'as',
 'assert',
 'break',
 'class',
 'continue',
 'def',
 'del',
 'elif',
 'else',
 'except',
 'finally',
 'for',
 'from',
 'global',
 'if',
 'import',
 'in',
 'is',
 'lambda',
 'nonlocal',
 'not',
 'or',
 'pass',
 'raise',
 'return',
 'try',
 'while',
 'with',
 'yield']

There are lots of builtin identifiers that are not in this list, and you can assign new values to int, Ellipsis etc.

... is a special case, since it's not a valid identifier name in the first place, so it would be impossible to assign to.

Python keeps the list of reserved keywords quite short, compared to many other languages. One reason is probably to keep backwards compatibility with code that for some reason used identifiers such as Ellipsis before it became part of the language.