Black insists that function and class definitions should be separated by blank lines. Good rule! However, I think it's slightly overenthusiastic.
For functions at the same level of nesting, this is a good idea:
def foo():
pass
+
def bar():
pass
And it's not just between two functions, but between any start/end of a function and surrounding code:
FOO = 1
+
def foo():
pass
+
BAR = 2
But! This seems unnecessary – and dare I say, ugly and less readable – when the adjacent line of code is on a different nesting level:
if clogged_stream_maker is not None:
async def flipped_clogged_stream_maker():
return reversed(await clogged_stream_maker())
else:
flipped_clogged_stream_maker = None
I claim that the above snippet (source would be better without any blank lines.
The same applies to classes, like, how does this blank line help anything? (source
def test_wrap_non_iobase():
+
class FakeFile:
def close(self): # pragma: no cover
pass
The intuition here is that blank lines are separators, not headers/footers. And you only need separation between items at the same level of nesting. We don't insist on using blank lines to separate a class or def from the beginning or end of the file; similarly, we shouldn't insist on using them to separate a class or def from the beginning or end of a block.
This would also make black's handling of def and class more consistent with its handling of import. Currently black does use the rule I suggest for blank lines after import statements:
# Black insists on a blank line after the import here:
import foo
BAR = 1
# But not here:
try:
import foo
except ImportError:
pass
This annoys me because I have a codebase with lots of functions whose first order of business is to define a nested function:
async def foo(): # black wants to insert a blank line after this line
def bar():
...
return await run_sync_in_worker_thread(bar)
Note that making this change would not introduce churn into existing codebases, because black already preserves blank lines. It would just introduce fewer unnecessary blank lines in the future.
Black insists that function and class definitions should be separated by blank lines. Good rule! However, I think it's slightly overenthusiastic.
For functions at the same level of nesting, this is a good idea:
def foo(): pass + def bar(): passAnd it's not just between two functions, but between any start/end of a function and surrounding code:
But! This seems unnecessary – and dare I say, ugly and less readable – when the adjacent line of code is on a different nesting level:
I claim that the above snippet (source would be better without any blank lines.
The same applies to classes, like, how does this blank line help anything? (source
def test_wrap_non_iobase(): + class FakeFile: def close(self): # pragma: no cover passThe intuition here is that blank lines are separators, not headers/footers. And you only need separation between items at the same level of nesting. We don't insist on using blank lines to separate a
classordeffrom the beginning or end of the file; similarly, we shouldn't insist on using them to separate aclassordeffrom the beginning or end of a block.This would also make black's handling of
defandclassmore consistent with its handling ofimport. Currently black does use the rule I suggest for blank lines afterimportstatements:This annoys me because I have a codebase with lots of functions whose first order of business is to define a nested function:
Note that making this change would not introduce churn into existing codebases, because black already preserves blank lines. It would just introduce fewer unnecessary blank lines in the future.