Local variable definition in Python list comprehension
James Tsai
jamestztsai at gmail.com
Fri Sep 2 18:28:39 EDT 2022
在 2022年9月2日星期五 UTC+2 00:17:23,<cameron... at gmail.com> 写道:
> On 02Sep2022 07:01, Chris Angelico <ros... at gmail.com> wrote:
> >On Fri, 2 Sept 2022 at 06:55, James Tsai <james... at gmail.com> wrote:
> >> No but very often when I have written a neat list/dict/set
> >> comprehension, I find it very necessary
> >> to define local variable(s) to make it more clear and concise. Otherwise I have to break it down
> >> to several incrementally indented lines of for loops, if statements, and variable assignments,
> >> which I think look less nice.
> >
> >Well, if it's outgrown a list comp, write it on multiple lines. Like I
> >said, not everything has to be a one-liner.
> True, but a comprehension can be more expressive than a less
> "functional" expression (series of statements).
>
> James, can you provide (a) a real world example where you needed to
> write a series of statements or loops and (b) a corresponding example of
> how you would have preferred to have written that code, possibly
> inventing some syntax or misusing ":=" as if it workeed they way you'd
> like it to work?
>
> Cheers,
> Cameron Simpson <c... at cskk.id.au>
Yeah, I think list comprehension is particularly useful to construct a deeply nested list/dict. For example, I am now using Plotly to visualize a cellular network including several base stations and users. Here is the function I have written:
def plot_network(area, base_stations, users):
bs_poses = np.array([bs.pos for bs in base_stations])
ue_poses = np.array([ue.pos for ue in users])
fig = px.scatter(x=bs_poses[:, 0], y=bs_poses[:, 1])
fig.add_scatter(x=ue_poses[:, 0], y=ue_poses[:, 1])
fig.update_layout(
xaxis=dict(range=[0, area[0]], nticks=5),
yaxis=dict(range=[0, area[1]], nticks=5),
shapes=[dict(
type="circle",
fillcolor="PaleTurquoise",
x0=x-r, y0=y-r, x1=x+r, y1=y+r,
hovertext=f"({x:.2f}, {y:.2f})",
opacity=0.3
) for bs in base_stations for x, y in [bs.pos]
for r in [bs.cell_radius]],
)
return fig
Simply put, I want to scatter the BSs and users, and additionally I want to draw a big circle around each BS to represent its cell coverage. I can choose to write 'x0=bs.pos[0]-bs.cell_radius, y0=...' instead, but it becomes less concise, and if x, y, or r is the return value of a function instead of a property, it becomes more computationally expensive to repeat calling the function as well. I also can create the list of 'shapes' by appending to a list, like
shapes = []
for bs in base_stations:
x, y = bs.pos
r = bs.cell_radius
shapes.append(dict(...))
fig.update_layout(
xaxis=dict(range=[0, area[0]], nticks=5),
yaxis=dict(range=[0, area[1]], nticks=5),
shapes=shapes
)
But in my opinion this is much less concise. I think it looks better to create the list within the nested structure. So I totally agree that list comprehension adds much expressiveness in Python. I only wonder whether it is a good idea to introduce a specific syntax for local variable assignment in list comprehensions, instead of using "for r in [bs.cell_radius]".
I am also surprised to know that the assignment operator ":=" in a list comprehension will assign a variable outside of the scope of the comprehension. I think it does not make sense since a list comprehension without a ":=" will never change name bindings outside itself.
More information about the Python-list
mailing list