10

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.

Bob Holver
  • 277
  • 1
  • 9
  • 1
    So here's my opinion: there is definitely no use case for overwriting **any** builtin object. Any such code should be treated as dangerous. On the other hand making them all keywords would make it harder to maintain (on the C side). So I guess its a matter of the evolution of Python. Also `None`, `False` and `True` are used all the time so there's a special focus on them. – freakish Jul 07 '17 at 13:09
  • 4
    Funny enough, `Ellipsis = 2` is alright, but `... = 2` raises `SyntaxError: can't assign to Ellipsis`. – Right leg Jul 07 '17 at 13:09
  • @freakish That is one opinion. Granted that Python likes simplicitly (especially after simplifying things in the transition to Python 3) I can't see how the extra complexity of maintaining only 2 other names trumps the uniformity of the contants behaving the same. That's why I thought there must be some use-case. – Bob Holver Jul 07 '17 at 13:11
  • @Rightleg `...` is not syntactically valid as a name, afaik, names can't start with a `.`. – Bob Holver Jul 07 '17 at 13:12
  • @BobHolver Why do you think there are only 2 other names? For example there are dozens builtin functions: https://docs.python.org/2/library/functions.html – freakish Jul 07 '17 at 13:12
  • @freakish built-in constants is what this question is about. – Bob Holver Jul 07 '17 at 13:13
  • @BobHolver There are no constants in Python sensu stricto. There are only constant keywords. And how are they different from builtin functions? Is it ok to overwrite for example `abs`? – freakish Jul 07 '17 at 13:13
  • 2
    [Python Built-in Constants](https://docs.python.org/3/library/constants.html) – AChampion Jul 07 '17 at 13:15
  • @BobHolver I know that, but when you try to write `.a = 1`, you get `SyntaxError: invalid syntax`. Here it explicitly mentions `Ellipsis`. – Right leg Jul 07 '17 at 13:15
  • @AChampion It's just a word they used in docs that doesn't mean anything. – freakish Jul 07 '17 at 13:16
  • @freakish A built-in function is clearly different from a constant; and really it is the docs to define the language spec – Chris_Rands Jul 07 '17 at 13:20
  • @freakish words mean something or we wouldn't be able to communicate. Constants are not [`keywords`](https://docs.python.org/3/reference/lexical_analysis.html#keywords) (`as`, `in`, `for`, etc.), which you cannot reassign. Constants are not [built-in `functions`](https://docs.python.org/3/library/functions.html) (`abs()`, `min()`, `max()`, etc.), which you can reassign (bad form!!). Python treats some built-in constants as special. Fair question from the OP. – AChampion Jul 07 '17 at 13:21
  • 1
    @AChampion You are wrong. `True`, `False` and `None` are **keywords** in Python3+. That's why it's a **SyntaxError** when trying to assign to them. There is no concept of constantness in Python. It's a meaningless word in Python. – freakish Jul 07 '17 at 13:26
  • @freakish sorry we will just have to disagree, they are constants because the language defines them as being constants, as in `a = True` is meaningful, vs `a = if` which is meaningless. – AChampion Jul 07 '17 at 13:28
  • @AChampion Lol, it's not a matter of disagreeing. I'm talking about **facts**, here's a proof: https://docs.python.org/3.5/reference/lexical_analysis.html?highlight=keywords#keywords For Python3+ `True = 1` **is meaningless**. – freakish Jul 07 '17 at 13:30
  • 1
    @freakish those are just words and don't mean anything - or you would also accept: https://docs.python.org/3.5/library/constants.html, `a = True` is meaningful as in `True` has a value - in fact a constant value. – AChampion Jul 07 '17 at 13:32
  • @AChampion No, these are not only words. There's a well defined and documented meaning and behaviour behind the word `keyword` unlike the word `constant`. Especially since these are not constants as some of them can be overwritten as pointed out by OP. It's a semantic inconsitency. I don't know why did you ignore docs about keywords. – freakish Jul 07 '17 at 13:34
  • @freakish let me refine one of my earlier statements, some (built-in) constants are defined as keywords. Constants have values so can be used in expressions and RHS of assignment statements, they are distinct from other keywords that cannot be used in expressions. I'm not ignoring the documentation. Hopefully, this refinement just points out that things can be constants and keywords both defined in the documentation - neither ignored. – AChampion Jul 07 '17 at 13:46
  • Possible duplicate of [Why were True and False changed to keywords in Python 3](https://stackoverflow.com/questions/18050815/why-were-true-and-false-changed-to-keywords-in-python-3) – Håken Lid Jul 07 '17 at 13:47
  • 1
    @AChampion Show me a piece of Python docs defining what `constant` means and how it should behave. Otherwise you are only saying what you think constant should mean. I might even agree with you. But AFAIK it's not the case. – freakish Jul 07 '17 at 13:48

1 Answers1

5

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.

Håken Lid
  • 22,318
  • 9
  • 52
  • 67
  • 2
    I understand that assigning to keywords is not allowed. The question isn't about why it is an error to assign to `True`, rather, it's why `Ellipsis` and `NotImplemented` are specified as "constants" when they are assignable. Backwards compatibility is an issue, of course, but the transition from 2 to 3 would allow such a change, as was done with `True` and `False`. – Bob Holver Jul 07 '17 at 13:40
  • The original builtin constant is unchanged, even if you assign the name to some other value in the current scope. – Håken Lid Jul 07 '17 at 13:58
  • 1
    Yes, I understand how binding works too. This still does not answer *why* you can re-bind (assign to) the aforementioned names. – Bob Holver Jul 07 '17 at 14:00
  • 2
    Because there's nothing special about those names. There just like any other non-keyword identifier in Python. – Håken Lid Jul 07 '17 at 14:11
  • 1
    @BobHolver: You can consider `True` and `False` to have changed from constants to boolean literals. – Ry- Jul 07 '17 at 14:39
  • 1
    @BobHolver I think your answer is in the last paragraph - "Python keeps the list of reserved keywords quite short". Things are only made into keywords when there is a compelling reason to do so. – Mark Ransom Jul 07 '17 at 17:50
  • As one case where adding keywords to the language broke existing code, the tensorflow library [used to have a function](https://stackoverflow.com/q/51996163/12299000) with an argument named `async`, which is a keyword in more recent versions of Python. – kaya3 Mar 07 '20 at 00:02