How to break up lambda function in to its own function? (Lambda is currently 125+ characters) How to break up lambda function in to its own function? (Lambda is currently 125+ characters) python-3.x python-3.x

How to break up lambda function in to its own function? (Lambda is currently 125+ characters)


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.


First things first: What's your code doing?

Let's read carefully:

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)]

You're only interested in the first element of x, because you do idx == 0. Remember that the index will be zero only in the first iteration. So if x has one 1,000,000 elements, you'll be evaluating 999,999 useless if conditions.

As far as I can understand, the explanation of your algorithm is:

Create a list of the same length of x in which every element is an empty string. If BBC or 'Wall' is present in x['newsSource'] make the first element of this new list be the string background: rgba(255,0,0,.3). Return this new list.

That's easy to codify:

def mysterious_function(x):    new_list = [''] * len(x)    if 'BBC' in x['newsSource'] or 'Wall' in x['newsSource']:        new_list[0] = 'background: rgba(255,0,0,.3)'    return new_list

You can now use the mysterious function in your current code:

styled_df = df.style.apply(mysterious_function, axis=1)

Isn't this better?

(And please give the function a better name)