142

Why does PEP 8 recommend not having spaces around = in a keyword argument or a default parameter value?

Is this inconsistent with recommending spaces around every other occurrence of = in Python code?

How is:

func(1, 2, very_long_variable_name=another_very_long_variable_name)

better than:

func(1, 2, very_long_variable_name = another_very_long_variable_name)

Any links to discussion/explanation by Python's BDFL will be appreciated.

Mind, this question is more about kwargs than default values, i just used the phrasing from PEP 8.

I'm not soliciting opinions. I'm asking for reasons behind this decision. It's more like asking why would I use { on the same line as if statement in a C program, not whether I should use it or not.

TylerH
  • 20,799
  • 66
  • 75
  • 101
soulcheck
  • 36,297
  • 6
  • 91
  • 90
  • The reasoning behind doing one vs. the other for this are mainly subjective. With shorter keys & values and args on the same line, no spaces does improve readability. But longer keys or values and multi-line args do not play as well with that. The most important is just to be consistent in what you decide to use. – Akaisteph7 Aug 24 '23 at 15:40

7 Answers7

89

I guess that it is because a keyword argument is essentially different than a variable assignment.

For example, there is plenty of code like this:

kw1 = some_value
kw2 = some_value
kw3 = some_value
some_func(
    1,
    2,
    kw1=kw1,
    kw2=kw2,
    kw3=kw3)

As you see, it makes complete sense to assign a variable to a keyword argument named exactly the same, so it improves readability to see them without spaces. It is easier to recognize that we are using keyword arguments and not assigning a variable to itself.

Also, parameters tend to go in the same line whereas assignments usually are each one in their own line, so saving space is likely to be an important matter there.

Rajesh Chamarthi
  • 18,568
  • 4
  • 40
  • 67
fortran
  • 74,053
  • 25
  • 135
  • 175
  • 15
    this could be the case, but still seems strange to introduce this IMO iconsistency in code style recommendations for such a well designed language, only to save 2 characters. It's as if java code style said that it's petter to put `{` on a new line after `if` (saves the same number of characters) but not in class definition. Also a keyword parameter is different than default value but still uses the same style recommendation. – soulcheck Jan 13 '12 at 16:00
  • 4
    As I said, they are different things. It makes sense to write them differently. – fortran Jan 13 '12 at 16:06
  • 13
    i'd say it's not really more readable than `kw1 = kw1, kw2 = kw2` ;) but maybe that was what Guido and Barry thought. – soulcheck Jan 13 '12 at 16:17
  • 16
    The fact that keyword argument is fundamentally different than variable assignment is not a valid argument to have different conventions IMO, because the difference is already clear from context. The former happens _within_ a function call, and the latter needs to stand alone at the current indentation level. IMO, for variable names longer than 5-6 characters (i.e. real life for most), the variant with spaces is hands-down more readable. – Axel Feb 07 '18 at 11:17
  • 1
    I think it's a mistake to attempt to dictate, in too strict of terms, code formatting. I've worked on hundreds of diverse software projects with all sorts of coding conventions and the consistency _within_ the project is what clearly maters. There is no singular "right" way to do things outside of syntax requirements of the language its self (e.g., Python's indentation). For example, in the Wine project it's generally expected that assignment operators for concurrent lines of variable initializations should be aligned, where as PEP8 says you should only have one space on either side of it. – Daniel Santos Sep 05 '20 at 07:40
29

There are pros and cons.

I very much dislike how PEP8 compliant code reads. I don't buy into the argument that very_long_variable_name=another_very_long_variable_name can ever be more human readable than very_long_variable_name = another_very_long_variable_name. This is not how people read. It's an additional cognitive load, particularly in the absence of syntax highlighting.

There is a significant benefit, however. If the spacing rules are adhered to, it makes searching for parameters exclusively using tools much more effective.

Hywel Thomas
  • 799
  • 9
  • 5
  • 1
    Well, if you adhere to putting spaces around =, searching using tools should be no different. – NoName Jan 23 '20 at 19:09
  • 9
    @NoName if you put spaces around assignments and no spaces around default/keywords, then searching **for either excluding the other** is easier (search with or without spaces). – Ptival Nov 30 '20 at 10:11
  • Downvote. Very long variable names are not pythonic, and you should stick to a rule not just for the looks. If a pythonic = small variable name looks good without whitespaces, it should be a rule. A space after a parameter is only needed for a default value, see [Pep8](https://peps.python.org/pep-0008/#other-recommendations): *When combining an argument annotation with a default value, however, do use spaces around the = sign*. – questionto42 Jun 11 '23 at 20:03
17

I wouldn't use very_long_variable_name as a default argument. So consider this:

func(1, 2, axis='x', angle=90, size=450, name='foo bar')

over this:

func(1, 2, axis = 'x', angle = 90, size = 450, name = 'foo bar')

Also, it doesn't make much sense to use variables as default values. Perhaps some constant variables (which aren't really constants) and in that case I would use names that are all caps, descriptive yet short as possible. So no another_very_...

rplnt
  • 2,341
  • 16
  • 14
  • 1
    those are keyword arguments, a similar example is in PEP i only made it less readable – soulcheck Jan 13 '12 at 15:45
  • 4
    You're saying (essentially): to make the no-space rule sensible, write very short variable names. But IF one has long-ish variable names, then the no-space rule makes for a cluttered environment. The argument that 'it's not an assignment, so they're different things' doesn't cut it for me, because I care more about legibility than about semantics and because if it's not a 'default value for an assignment', then what is it? – PatrickT Jun 23 '16 at 19:23
  • 2
    @PatrickT The argument "it's not an assignment, so they're different things" does nothing to explain _why it is_ (a philosophical notion); It merely explains _why it can be_ (a syntactic notion). – Mateen Ulhaq May 03 '17 at 23:47
12

IMO leaving out the spaces for args provides cleaner visual grouping of the arg/value pairs; it looks less cluttered.

JoeC
  • 145
  • 1
  • 2
  • 1
    I generally like spaces, so much so I tend to put spaces just inside the parentheses as well so all parameters are surrounded by space. But I do think the `arg1=40` is more readable since the relationship is more obvious. – Charlie Gorichanaz Apr 22 '16 at 22:28
9

For me it makes code more readable and is thus a good convention.

I think the key difference in terms of style between variable assignments and function keyword assignments is that there should only be a single = on a line for the former, whereas generally there are multiple =s on a line for the latter.

If there were no other considerations, we would prefer foo = 42 to foo=42, because the latter is not how equals signs are typically formatted, and because the former nicely visually separates the variable and value with whitespace.

But when there are multiple assignments on one line, we prefer f(foo=42, bar=43, baz=44) to f(foo = 42, bar = 43, baz = 44), because the former visually separates the several assignments with whitespace, whereas the latter does not, making it a bit harder to see where the keyword/value pairs are.

Here's another way of putting it: there is a consistency behind the convention. That consistency is this: the "highest level of separation" is made visually clearer via spaces. Any lower levels of separation are not (because it would be confused with the whitespace separating the higher level). For variable assignment, the highest level of separation is between variable and value. For function keyword assignment, the highest level of separation is between the individual assignments themselves.

Denziloe
  • 7,473
  • 3
  • 24
  • 34
6

I personally feel that a single space before and after ALL assignment operators = should be standard regardless of the programming/markup language, because it helps the eye differentiate between tokens of different channels (i.e. isolating a variable/parameter name token, from an assignment operator token =, from a value token/sequence of expression value tokens).

It is neither readable nor intuitive to clump three tokens of three different channels into a single "parameter-name-assignment-operator-value/expression-tuple" token.

For example, let's consider non-delimited tokens:

def my_func(par1: str, par2: str):
    print('%s %s' % (par1, par2))

cond = 'conditional string'
my_func(par1='string with a lot of spaces',
        par2=cond if cond is not None else 'no string')

Granted, the value passed to par2 should probably be stored into a variable rather than passed as a "ternary" expression...

par2 = cond if cond is not None else 'no string'
my_func(par1='string with a lot of spaces', 
        par2=par2)

...but should we decide to use the ternary expression anyways, I find that adding the delimiting spaces before and after the assignment operators to be more readable, almost like a dictionary object (which python parameter sequences basically are):

my_func(par1 = 'string with a lot of spaces', 
        par2 = cond if cond is not None else 'no string')
# OR
par2 = cond if cond is not None else 'no string'
my_func(par1 = 'string with a lot of spaces', 
        par2 = par2)
rolling_codes
  • 15,174
  • 22
  • 76
  • 112
5

I think there are several reasons for this, although I might just be rationalizing:

  1. It saves space, allowing more function definitions and calls to fit on one line and saving more space for the argument names themselves.
  2. By joining each keyword and value, you can more easily separate the different arguments by the space after the comma. This means you can quickly eyeball how many arguments you've supplied.
  3. The syntax is then distinct from variable assignments, which may have the same name.
  4. Additionally, the syntax is (even more) distinct from equality checks a == b which can also be valid expressions inside a call.
otus
  • 5,572
  • 1
  • 34
  • 48