Open abcd3cec-2fbb-4c89-b6e3-cbe78d60e4c2 opened 2 years ago
Do the print docs need to mention something so obvious?
Functions and methods which operate by side-effect typically don't mention that they return None, see for example the docs for various builtin methods:
https://docs.python.org/3/library/stdtypes.html#mutable-sequence-types
e.g. s.append, s.clear, s.extend, s.insert, s.remove, s.reverse
and likewise for list.sort, set.add, dict.clear and many others.
(However, dict.update is a rare exception, it does mention that it returns None.)
We should not feel it necessary to add an explicit comment to every function or method that operates by side-effect stating that they return None.
I opened this ticket on behalf of a user who asked about print() specifically in #python on the Libera IRC network, who I assume does not find this obvious.
I don't think it would be tenable to add this note to every built-in, but that's not the intended scope of this issue. I do think it's worth mentioning for print(), though.
I think it does a better service to users to explain how Python returns None implicitly if a function doesn't have any other explicit return value. If the print() docs had this note, it would be confusing why other similar functions don't.
It's also worth explaining that when a function is designed to explicitly return None in certain cases (e.g. dict.get()) that it shouldn't do so implicitly, but should include an explicit return None
for readability.
Sure, there will always be some users who will find certain things not obvious. Sometimes I'm that user myself.
What did this user think print() returned? What precisely was their question? Perhaps if I saw the conversation in context, I would be more sympathetic to this.
I can see a difference between (for example) the questions:
"I see that print('Hello world') returns None, but is it safe to assume that print will *always* return None? It is not documented anywhere as far as I can see."
and
"What does x = print('Hello world') do?"
The original question was closer to the related issue of "indicate return types for all built-ins," conversation log follows (UTC-5):
09:33:50 ringo__ | is there a stdlib api docs which actually has *full* functions signature?
09:34:27 ringo__ | for example, https://docs.python.org/3/library/functions.html, function
| abs(x), it returns what, int? I need to read the whole sentence to figure
| out the return value of a function?
09:34:48 ringo__ | (or argument for that matter)
09:35:51 bjs | ringo__: well like it says it doesn't just support int
09:36:00 bjs | int, float, or any type that supports it
09:37:01 bjs | in general you can find actual type annotations for the functions in the
| typeshed
| https://github.com/python/typeshed/blob/master/stdlib/builtins.pyi
09:37:32 bjs | I wonder if it would be useful to include the typeshed annotation in the
| docs, or whether it would be more confusing
09:37:49 ringo__ | Thanks bjs ! I'll bookmark this typeshed
09:38:13 SnoopJ | abs() will do whatever __abs__() on the type does, which can be different
| for any given type. You'd expect T -> T but it's not guaranteed.
09:38:18 ringo__ | I used abs() as an example. In fact I was wondering what does print()
| return. I *guessed* it returns None, but the docs won't say
09:39:05 ringo__ | I could do a try-it-yourself approach but I was puzzled why the docs
| simply won't give you full fn signature, ie print(..) -> None
09:39:17 SnoopJ | that one is just an omission :)
How about following "The Python interpreter has a number of functions and types built into it that are always available. They are listed here in alphabetical order." in https://docs.python.org/3/library/functions.html with "Here and elsewhere in these docs, entries for functions (including methods) that always return None usually omit 'Return None' and just say what the function does."
Barry: The PEP-8 'return None' recommendation could be added to the Reference entry for 'return'. But I think this should be a separate issue as 1) it is about coding rather than documentation and 2) there is the possible objection that choosing completely explicit 'return None' versus half explicit, half implicit 'return' and the latter versus completely implicit \<nothing at end> should be left to the style PEP.
Barry: The PEP-8 'return None' recommendation could be added to the Reference entry for 'return'. But I think this should be a separate issue as 1) it is about coding rather than documentation and 2) there is the possible objection that choosing completely explicit 'return None' versus half explicit, half implicit 'return' and the latter versus completely implicit \<nothing at end> should be left to the style PEP.
I do think it's a question of style. Section 7.6 of the language reference says:
If an expression list is present, it is evaluated, else None is substituted.
which is the important concept that beginners should learn.
I agree that the admonition in PEP-8 is really trying to say "don't mix implicit and explicit return styles". Implicit None return is fine if all exit paths are implicit. But once you add an explicit value to a return path, all return paths should use explicit values, including those that return None.
IME, while I do occasionally encounter push back on this when doing reviews, most folks come around to this p.o.v.
The new title is puzzling; the discussion moved to advertising that all functions default to returning None, this is not related to the built-in status.
advertising that all functions default to returning None
This is already communicated in § 4.7 ("Defining Functions") of the official tutorial.
I think it would be a good idea to revise that section so that this property of functions is a little more clear, but that isn't the scope of this ticket.
The title change reflects my intent to submit a PR that adds a hint to the builtins doc.
Please post your proposed change here to be discussed by participants here.
My thought was to add something like this to the top of functions.rst:
Note that some of the functions listed here have the :ref:`default return value <tut-defining-functions> of ``None``.
For reference, the builtins this applies to are:
Which makes me wonder if the hint is even worth having, since it's so few of them.
Note that of these, exec() does what this ticket originally proposed for print() - i.e. it explicitly says that the function returns None.
"have the :ref:`default return value \<tut-defining-functions> of ``None``."
This sounds to me like "by default they return None but you can override this default".
I don't think any change to the doc makes sense here. When you state the obvious people wonder what they're missing.
Steven, I am also inclined to close this. What do you think after the discussion? It is sometimes easier to clarify when we have a confused person present in the discussion.
When you state the obvious...
Obvious to who? New learners coming to Python don't know the same things as people with experience.
New learners coming to Python don't know the same things as people with experience.
IMO, new learners will be worse off by adding "returns None" to all of the builtins. At best it a distractor.
I work with new learners almost every day. The issue never arises. No one writes "x = print('hello world')" and they would be worse off if shown such a possibility.
One other consideration is that MyPy and the tools that use it (such as PyCharm) reject the idea of None as return value. Their view is that no value is returned all. We don't want the docs to contradict that world view.
$ cat hello.py
x = print('hello world')
$ mypy hello.py
hello.py:1: error: "print" does not return a value
Found 1 error in 1 file (checked 1 source file)
What we're debating here is a micro-cosm of the broader "documentation philosophy" questions that I'm hoping the Documentation WG can iron out.
What is "obvious"? Is it obvious that print returns None when file.write does not? Why does "exec" explicitly say it returns None, and no beginners were harmed, but having "print" say it returns None would be bad?
I should have said "redundant information" rather than "obvious".
I consider it redundant to specify that the default behavior applies to some specific case. If I read redundant information I may pause to think why it was necessary to explicitly state it, and whether I am misunderstanding something.
(Let's not make my bad choice of word turn this into a discussion about "what is obvious". The issue will probably never be closed if we do that.)
I think it would be a good idea to revise that section so that this [implicit return of None] property of functions is a little more clear, but that isn't the scope of this ticket.
Discussion about this side issue came up again on Libera, see #92753.
Instead of specifying the return type in the text, which is a bit verbose and easy to miss in a wall of text, the return types could be mentioned in the function signature (if they are not too complicated).
This is already done in some places like this one specifies the return type https://docs.python.org/3/library/time.html#time.clock_gettime
and this one specifies the parameter type https://docs.python.org/3/library/time.html#time.clock_settime
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields: ```python assignee = None closed_at = None created_at =
labels = ['3.11', 'docs']
title = 'return value of builtins is not clearly indicated'
updated_at =
user = 'https://github.com/SnoopJeDi'
```
bugs.python.org fields:
```python
activity =
actor = 'rhettinger'
assignee = 'docs@python'
closed = False
closed_date = None
closer = None
components = ['Documentation']
creation =
creator = 'SnoopJeDi'
dependencies = []
files = []
hgrepos = []
issue_num = 46282
keywords = ['patch']
message_count = 17.0
messages = ['409857', '409870', '409874', '409883', '409886', '410038', '410046', '411632', '411653', '411664', '411668', '411809', '411835', '412797', '412811', '412836', '412838']
nosy_count = 8.0
nosy_names = ['barry', 'terry.reedy', 'nedbat', 'eric.araujo', 'steven.daprano', 'docs@python', 'iritkatriel', 'SnoopJeDi']
pr_nums = ['30435']
priority = 'normal'
resolution = None
stage = 'patch review'
status = 'open'
superseder = None
type = None
url = 'https://bugs.python.org/issue46282'
versions = ['Python 3.11']
```