Is It Pythonic to Use List Comprehensions For Just Side Effects

Is it Pythonic to use list comprehensions for just side effects?

It is very anti-Pythonic to do so, and any seasoned Pythonista will give you hell over it. The intermediate list is thrown away after it is created, and it could potentially be very, very large, and therefore expensive to create.

List comprehensions for side effects - idiomatically correct or an abomination?

List comprehensions are for creating a list. That's not what you're doing here, so I'd avoid it.

Avoiding Side Effects in List Comprehension

Your specific question only prints the representation of your actual generator object formed by the generator expression, namely this one-

(sum(dictionary[site] for site in dictionary) for dictionary in listofdictionaries)

See this answer on printing generators for further details-
https://stackoverflow.com/a/44616115

For this example you may be better off using a list comprehension, e.g.

print([sum(dictionary.values()) for dictionary in listofdictionaries])

You coudl print the generator by unpakcing it first but for this example it appears less readable and less effective-

print(*(sum(dictionary.values()) for dictionary in listofdictionaries))

Side effects can be quite a broad term- https://en.wikipedia.org/wiki/Side_effect_(computer_science) but as per the previous answer you're not modifying your dictionary in any way with these methods so there are no side effects.

Python loops vs comprehension lists vs map for side effects (i.e. not using return values)

I think that this variation on Abhijit answer, which at the same time is a variation of my 4th point is the best.

for r in res:
r.update(r.pop('some_key', {}))
  • Has all the advantages of using a regular for loop
  • Is easy to understand
  • Takes just 2 lines of code
  • Doesn't need the if clause

Are list comprehensions fully evaluated before being used in the rest of the code?

It calculates all of them. You can verify with something like this:

>>> [(i, print(i)) for i in range(3)][1]
0
1
2
(1, None)

This isn't really "internal", because this is well-defined behaviour and list comprehensions can have side-effects (even if they shouldn't).

What is the difference between normal loops and list comprehension?

A list comprehension is used to comprehend (Make) a list. It is useful only when making lists. However, here you are not making a list, so it is not recommended to use list comprehension. You only print the value and not store it as a list. Here, use a for a loop.

The reason you get None is - the list comprehension basically becomes a list of print() functions like [print(...),print(...)....]

So when you call them it becomes like - print(print(...)), which, if you try this code, will return a None along with the output.

So, do not use list comprehension unless you are using it to build a list.

References - This and That

Error in Comprehensions list but correct in for loop

First of all:

  • Don't use list comprehensions for side effects. You are creating a list object with None references, then discarding it again. That's a waste of computer resources.

    Always use a for loop if all you needed was a loop.

  • You can set attributes on self with the setattr() function. exec() should be a last resort, as it opens you to all sorts of performance and security issues.

You can use:

for key, value in self.dict_.items():
setattr(self, value, str(key))

to achieve the same thing.

Alternatively, give your class a __getattr__ hook and have it look up attributes lazily:

def __getattr__(self, name):
try:
return str(self.dict_[name])
except KeyError:
# raise an AttributeError instead
raise AttributeError(name) from None

The __getattr__ hook is called for any attribute not explicitly set on your instance.

Now, for what actually goes wrong:

exec() can't see self because a list comprehension is a new scope, as if you ran:

def create_static_variables(self):
def inner_function():
for key, value in self.dict_.items():
exec("self." + str(value) + " = " + str(key))
inner_function()

At compile time, Python can see the self in self.dict_.items() and bind it as a closure (taking it from the local namespace of the create_static_variables() call. But exec() doesn't run at compile time and so can only see globals or locals.

You could use exec(..., globals(), {"self": self}) to pass along the self binding in a new local namespace, to work around that.



Related Topics



Leave a reply



Submit