In this particular case, that may result in code that breaks with tradition. But I can't see a way to preserve the tradition without creating special or edge cases. For example, we can't follow the first option and get clean formatting with a function like zip. You'll have a train wreck of bad options about where to put the braces and how to place the comprehension's body in relation to the braces that enclose it. Versus, with Black's style, the answer is easy and straightforward, because you just do it the same way you would anywhere else:
zipped = zip(
{
apple.stem
for satchel in satchels
for apple in satchel
},
{
apple.core
for satchel in satchels
for apple in satchel
}
)
IMO, that's good, even if it isn't what we're all used to. Having a bunch of special cases just to match what someone might think is more aesthetically pleasing in specific situations is not a desirable feature in a set of autoformatting rules. zipped = zip({
apple.stem
for satchel in satchels
for apple in satchel
}, {
apple.core
for satchel in satchels
for apple in satchel
}) zipped = zip({
apple.stem
for satchel in satchels
for apple in satchel
},
someList
)
or zipped = zip({
apple.stem
for satchel in satchels
for apple in satchel
}, someList)
(Which admittedly looks reasonably tidy, but starts to get gross again if we start looking at 3-ary functions.)You've also got to contend with the first not being a comprehension meaning that the comprehension's indenting can't so easily be kept the same:
zipped = zip(
someList,
{
apple.stem
for satchel in satchels
for apple in satchel
}
)
Which is where I was going with the comment about edge cases. Personally, I don't want formatting rules where you might decide to format the arguments to a function in different ways depending on the specifics of what other arguments the function has. I like simple. Give me one rule for when it all fits on one line, and another rule for when it doesn't. And make sure neither of the rules causes me to have to re-indent things just because a function picked up an additional argument. And make sure that the rules are completely oblivious to the function's arity. zipped = {apple.stem: apple.core
for satchel in satchels
for apple in satchel}Not sure what came about of object comprehensions though.
Maybe that would fail to put long strings on their own line?
stems = {
apple.stem for satchel in satchels for apple in satchel
}
basket.add(stems)
I concede that without black it wouldn't have made sense to make that refactoring, but since I really want to use an autoformatter, and black is the best autoformatter I have, I'd rather restructure my code slightly so that I can just use black 100% all the time.I’m kind of thinking of it as something like baking some exercise into your day by putting a walk into your commute: the little nudge of not fighting the tool on something minor means you don’t skip little things, and over time that adds up more than it seems at first.
You always end up adapting to the tool, while adapting the tool to you
Until you oneday reach a perfect harmony with your tool... until you introduce another one, and the equilibrium must once again be found.
Also of note, this is a general principle/behavior (eg you and your furniture..!)
To be clear though, in your example, it would format it as:
basket.add({apple.stem for satchel in satchels for apple in satchel})
It might also format it as basket.add(
{apple.stem for satchel in satchels for apple in satchel}
)
It only formats like your example if the statement is much further indented I believeMy understanding is that by using Black you're saying I choose to not express my opinions about formatting aesthetics and delegate that decision to Black instead.
Which, as a longtime Go dev and now Rust dev, I love formatters that are opinionated. I don't always love what Gofmt or Rustfmt do, but I definitely like consistency that the community has in code style.
So I don't care what Black thinks - I care what, hopefully, everyone uses. Though, I could see a situation where formatting can be altered and the project has a format config. Meaning that while code fmt differs between projects, it would be consistent among all devs working on X projects.
I was initially grumpy about my org adopting black because I preferred single quotes, but the level of standardization is a huge win in my book. I never even think about my code style anymore, I just write it and then run black.
Yeah, I keep seeing people singing the praises of black and I'm really dreading the inevitable future where people start acting like this dude's opinion is Correct Official Python Style.
Precisely. I wonder why ML has not been applied here.
black isn't an uglifier/minifier. it's undoubtedly readable.
>predictable
why?
There is a great autoformatter that does not have this issue. Using it guarantees that you'll never have to stick with an outdated version of a language because your autoformatter of choice hasn't been updated for the current one, or even worse, is not maintained anymore.
It's called "cat".
I super dislike black's formatting, and I think it's really rare to actually see it in codebases. It wraps weirdly (sometimes not at all). I'd prefer to use yapf, but last I checked it still crashes on "f-strings".
Here's a small example:
Black formats this as: I've never seen Python code like that.I totally believe using a formatter is good practice. Black is in a challenging position of coming into a community with a lot of existing code and customs, and I get that. But I also think that's an opportunity, rather than having to guess at what is good, there's a wealth of prior art to look at. I wish it had done this, rather than essentially codify the author's style.