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 thesetattr()
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
Why Does This Unboundlocalerror Occur (Closure)
Switch Between Two Frames in Tkinter
Why Is the Order in Dictionaries and Sets Arbitrary
What Is Truthy and Falsy? How Is It Different from True and False
How to Dynamically Create Variables
How to Read/Process Command Line Arguments
Pip' Is Not Recognized as an Internal or External Command
Use Different Python Version With Virtualenv
How to Flush the Output of the Print Function
How to Sort a Dictionary by Key
How to Make a Dictionary from Separate Lists of Keys and Values
Pygame Mouse Clicking Detection
Why Doesn't Calling a String Method Do Anything Unless Its Output Is Assigned
What Is the Python "With" Statement Designed For
How to Get Output from Subprocess.Popen(). Proc.Stdout.Readline() Blocks, No Data Prints Out