As a general rule, I think it's better to rely on automated tools to reformat your code than to try to figure out how to apply all those rules like a computer yourself.
The three main choices that I know of are:
black
: Reformats at the syntax level; no configuration at all except for max line length.
yapf
: Reformats at the syntax level; highly configurable.
autopep8
(and predecessors like pep8ify
): Reformats only at the surface level; doesn't change anything that's already PEP 8 compliant. Useful if you want as few changes as possible (e.g., because you're reformatting long-standing code and don't want a massive changelist in source control).
Here's what black
does with your code:
styled_df = df.style.apply(
lambda x: [
"background: rgba(255,0,0,.3)"
if ("BBC" in x["newsSource"] or "Wall" in x["newsSource"]) and idx == 0
else ""
for idx, v in enumerate(x)
],
axis=1,
)
That takes up a whole lot of vertical whitespace. But you can't configure black
to treat it any differently. So, what can you do?
Whenever black
insists on reformatting my code into something that doesn't look good to me, that means I have to reorganize my code into something easier to format.
The obvious thing to do here is turn that giant lambda
into a def
, or maybe even two:
def highlight(x):
return "BBC" in x["newsSource"] or "Wall" in x["newsSource"]
def style(x):
return [
"background: rgba(255,0,0,.3)" if highlight(x) and idx==0 else ""
for idx, v in enumerate(x)
]
styled_df = df.style.apply(style, axis=1)
Having done that… you aren't even using v
; all you're doing is styling the first one (and idx == 0
), and only if the news source includes BBC or Wall.
So, for BBC and Wall things, you're returning one background
plus len(x)-1
empty strings; for other things, you're just returning len(x)
empty strings.
Assuming that's the logic you wanted, let's be explicit about that:
def style(x):
if "BBC" in x["newsSource"] or "Wall" in x["newsSource"]:
first = "background: rgba(255,0,0,.3)"
return [first] + [""]*(len(x)-1)
return [""]*len(x)
styled_df = df.style.apply(style, axis=1)
You might prefer ["" for _ in range(x)]
to [""]*len(x)
; I'm not really sure which is more readable here.
I likely could change this lambda in to a function, but am struggling with how. I'm new to lambdas and got this one from another problem altogether...So yes, agreed the Lambda is the root issue.
A lambda
is a function, just like a def
is. The only differences are:
def
is a statement, so you can't put it in the middle of an expression.
lambda
is an expression, so you can't include any statements in it.
def
gives a function a name.
Other than that, the functions they compile work exactly the same. For example:
func = lambda x: expr(x)
def func(x): return expr(x)
… defines two functions with identical bytecode, and almost everything else the same, except that func.__name__
is 'func'
for the def
but something like '<lambda>'
for the lambda
.
More importantly, if you want to throw loop or a test into the function, with lambda
you'll have to contort it into a comprehension or an if expression; with def
, you can do that if it's appropriate, or use a compound statement if it isn't.
But, on the other hand, if there's no good name for the function, and it really isn't worth thinking about beyond its use as a callback function, lambda
is better. For example, if you're defining a function just to return x - 3
that's only going to be used once, def
would be silly.