Skip to content

Programming FAQ about "How do I apply a method to a sequence of objects?" should include the option of an explicit for-loop #84522

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Dominik1123 mannequin opened this issue Apr 20, 2020 · 7 comments · Fixed by #94660
Labels
3.10 only security fixes 3.11 only security fixes 3.12 only security fixes docs Documentation in the Doc dir easy type-feature A feature request or enhancement

Comments

@Dominik1123
Copy link
Mannequin

Dominik1123 mannequin commented Apr 20, 2020

BPO 40342
Nosy @rhettinger, @mdickinson, @vedgar, @Dominik1123

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:

assignee = None
closed_at = None
created_at = <Date 2020-04-20.21:06:38.162>
labels = ['type-feature', '3.8', '3.9', 'docs']
title = 'Programming FAQ about "How do I apply a method to a sequence of objects?" should include the option of an explicit for-loop'
updated_at = <Date 2020-04-22.07:11:11.110>
user = 'https://github.com/Dominik1123'

bugs.python.org fields:

activity = <Date 2020-04-22.07:11:11.110>
actor = 'veky'
assignee = 'docs@python'
closed = False
closed_date = None
closer = None
components = ['Documentation']
creation = <Date 2020-04-20.21:06:38.162>
creator = 'Dominik V.'
dependencies = []
files = []
hgrepos = []
issue_num = 40342
keywords = []
message_count = 6.0
messages = ['366880', '366885', '366901', '366979', '366980', '366982']
nosy_count = 5.0
nosy_names = ['rhettinger', 'mark.dickinson', 'docs@python', 'veky', 'Dominik V.']
pr_nums = []
priority = 'normal'
resolution = None
stage = None
status = 'open'
superseder = None
type = 'enhancement'
url = 'https://bugs.python.org/issue40342'
versions = ['Python 3.8', 'Python 3.9']

@Dominik1123
Copy link
Mannequin Author

Dominik1123 mannequin commented Apr 20, 2020

Right now the question is simply answered with:

result = [obj.method() for obj in mylist]

However this is only appropriate if the result of the method is needed (i.e. if it's some kind of transformation).

There are many cases where it's not and the method is meant to update the object in place. Here it's better to use a for loop:

    for obj in mylist:
        obj.update()

Sometimes people use a one-way list comprehension hack because it saves one line:

[obj.update() for obj in mylist]

However this is discouraged for multiple reasons (builds a superfluous list, obfuscates the actual intent, ...).

So I feel like the Programming FAQ should actively mention this scenario and promote the usage of a for loop here.

@Dominik1123 Dominik1123 mannequin added 3.8 (EOL) end of life 3.9 only security fixes labels Apr 20, 2020
@Dominik1123 Dominik1123 mannequin assigned docspython Apr 20, 2020
@Dominik1123 Dominik1123 mannequin added docs Documentation in the Doc dir type-feature A feature request or enhancement 3.8 (EOL) end of life 3.9 only security fixes labels Apr 20, 2020
@Dominik1123 Dominik1123 mannequin assigned docspython Apr 20, 2020
@Dominik1123 Dominik1123 mannequin added docs Documentation in the Doc dir type-feature A feature request or enhancement labels Apr 20, 2020
@rhettinger
Copy link
Contributor

The current answer seems reasonable to me. It addresses the question that most people want to have answered. Also, it isn't common to loop over methods that don't return values, because those typically do in-place mutations.

@vedgar
Copy link
Mannequin

vedgar mannequin commented Apr 20, 2020

I must say I agree with Dominik here. Too many times my students write list comprehensions when they mean a for loop. It's not just a "has result vs updates inplace" dichotomy: often it produces some output like a drawing or just a print() call [one of rare things that was better when print was a command is that it was impossible to do this:]. Yes, I know print call is not a method, but e.g. .plot() on DataFrame is. I'd sleep easier if I knew the Programming FAQ didn't encourage this style.

It would be enough to add a sentence of a sort
"If you don't care about the return value of the method, use a for loop.
for obj in mylist: obj.method()
"

@mdickinson
Copy link
Member

This is an antipattern I've seen on multiple occasions in real code. A common offender is:

[worker.join() for worker in workers]

Similarly, things like:

[plugin.start() for plugin in plugins]

I do think it would be worth updating the FAQ text.

@mdickinson
Copy link
Member

However, the list comprehension pattern is not as bad as lines like this one [#1]:

map(lambda plugin: self.start_plugin(plugin), self._plugins)

... which of course stopped working as soon as we transitioned to Python 3. :-(

[#1] https://github.com/enthought/envisage/blob/b7adb8793336dd3859623cb89bcc7bdfefe91b29/enthought/envisage/plugin_manager.py#L105

@vedgar
Copy link
Mannequin

vedgar mannequin commented Apr 22, 2020

Mapping lambdas is always inferior to comprehensions, in fact the main reason comprehensions were introduced was that mapping lambdas was cumbersome. (It didn't work so well for filtering by lambdas, but that's another story.)

As I said, Py3K was beneficial since raw maps weren't eager anymore, but it also gave us a print_function, enabling the new antipattern

[print(obj) for obj in mylist]

which wasn't possible before.

It's too late for Python, but a lesson for some future programming language: procedures and functions are not the same. Function call is an expression having a value, procedure call is a statement having an effect. Both are useful, but conflating them is not.

@ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
@iritkatriel iritkatriel added 3.11 only security fixes easy 3.10 only security fixes 3.12 only security fixes and removed 3.9 only security fixes 3.8 (EOL) end of life labels Jun 24, 2022
kj7rrv added a commit to kj7rrv/cpython that referenced this issue Jul 7, 2022
@kj7rrv
Copy link
Contributor

kj7rrv commented Jul 7, 2022

gh-94660 adds this.

miss-islington added a commit that referenced this issue Nov 11, 2022
(cherry picked from commit 97c493d)

Co-authored-by: Samuel Sloniker <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.10 only security fixes 3.11 only security fixes 3.12 only security fixes docs Documentation in the Doc dir easy type-feature A feature request or enhancement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants