145

I'm still getting used to Python conventions and using Pylint to make my code more Pythonic, but I'm puzzled by the fact that Pylint doesn't like single character variable names. I have a few loops like this:

for x in x_values:
   my_list.append(x)

and when I run pylint, I'm getting Invalid name "x" for type variable (should match [a-z_][a-z0-9_]{2,30} -- that suggests that a valid variable name must be between 3 and 31 characters long, but I've looked through the PEP8 naming conventions and I don't see anything explicit regarding single lower case letters, and I do see a lot of examples that use them.

Is there something I'm missing in PEP8 or is this a standard that is unique to Pylint?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Amanda
  • 12,099
  • 17
  • 63
  • 91

7 Answers7

196

A little more detail on what gurney alex noted: you can tell Pylint to make exceptions for variable names which (you pinky swear) are perfectly clear even though less than three characters. Find in or add to your pylintrc file, under the [FORMAT] header:

# Good variable names which should always be accepted, separated by a comma
good-names=i,j,k,ex,Run,_,pk,x,y

Here pk (for the primary key), x, and y are variable names I've added.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mlncn
  • 3,308
  • 2
  • 23
  • 20
  • 11
    This is the best answer. – giorgiosironi Jun 08 '16 at 08:13
  • 1
    Doesn't seem to work in `pylint 1.8.3`. http://pylint.pycqa.org/en/1.8/user_guide/options.html – James Mar 31 '18 at 19:26
  • 1
    Yes it does. http://pylint.pycqa.org/en/1.8/technical_reference/features.html?highlight=good-names – Aratz Feb 26 '19 at 12:44
  • 5
    What I'd really like is to have pylint accept (on request) short vars when they are used in comprehensions. Compare ```return [customer_address for customer_address in thing.get_customer_addresses() if customer_address.is_proper()]``` vs ```return [a for a in thing.get_customer_addresses() if a.is_proper()]``` I claim the latter is more clear, as a is obvious from the context. In general, variable length should correlate with scope of the variable. – EdvardM Oct 24 '19 at 07:03
  • 8
    To help VS Code users, add this to the `settings.json` file to properly configure the pylint: `"python.linting.pylintArgs": ["--good-names=i,j,k,ex,Run,_,pk,x,y,z,e"]` – Daniel Lavedonio de Lima Apr 05 '21 at 01:29
  • 1
    pylint now has `good-names-rgxs`, which I think is an even better option. See https://stackoverflow.com/questions/21833872/why-does-pylint-object-to-single-character-variable-names/69049347#69049347 – wisbucky Sep 03 '21 at 18:39
53

Pylint checks not only PEP8 recommendations. It has also its own recommendations, one of which is that a variable name should be descriptive and not too short.

You can use this to avoid such short names:

my_list.extend(x_values)

Or tweak Pylint's configuration to tell Pylint what variable name are good.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
warvariuc
  • 57,116
  • 41
  • 173
  • 227
  • A lot of pylint's own recommendations are stupid. It infers whether variables are constants, and often gets it wrong (since code today cannot predict intent or future code). – AdamC Mar 15 '23 at 13:47
33

In explicitly typed languages, one-letter name variables can be ok-ish, because you generally get the type next to the name in the declaration of the variable or in the function / method prototype:

bool check_modality(string a, Mode b, OptionList c) {
    ModalityChecker v = build_checker(a, b);
    return v.check_option(c);
}

In Python, you don't get this information, so if you write:

def check_modality(a, b, c):
    v = build_checker(a, b)
    return v.check_option(c)

you're leaving absolutely no clue for the maintenance team as to what the function could be doing, and how it is called, and what it returns. So in Python, you tend to use descriptive names:

def check_modality(name, mode, option_list):
    checker = build_checker(name, mode)
    return checker.check_option(option_list)

And you even add a docstring explaining what the stuff does and what types are expected.

Arthur Tacca
  • 8,833
  • 2
  • 31
  • 49
gurney alex
  • 13,247
  • 4
  • 43
  • 57
  • 23
    While I do agree with you in these cases, forcing 3 or more characters in a variable name does not mean it will be descriptive. I'm currently using `with open(FILE) as f: items = f.readlines()` for example, where the variable `f` is really obvious, but I get pylint warnings. This made me change to flake8. – Axel Örn Sigurðsson Aug 20 '14 at 14:05
  • 4
    you can also change the pylint rules to allow 'f' a variable name. There are already exceptions for i, j AFAIR. – gurney alex Aug 21 '14 at 10:21
  • 22
    for the people who downvoted this answer: I'm the guy who introduced the rule in Pylint, and the reason is exactly the one given. You may not agree with this decision, but this is nevertheless the answer to the question... – gurney alex Mar 09 '16 at 07:56
  • 4
    I totally follow your reasoning, however often in algorithms and mathematical programming some values are typically named with one letter. I think a function called `f` is totally different than an `OptionList` called c. Especially when I cannot rename it to `function` because it shadows a built-in. – kap Mar 27 '19 at 12:40
  • 1
    I agree with this reasoning for function parameters, but it is not applicable for local variables – uuu777 Mar 20 '20 at 12:33
  • @zzz777: I think your claim is valid, but I'd make an exception for local names living in a really long lexical scope if it's possible the name could be present throughout the scope. – user1071847 Jun 04 '20 at 14:46
  • 2
    Sigh.... Python *is* strongly-typed. So what is your point, exactly? Did you mean "dynamically-typed"? And even then, Python now supports static type hints. Your rule is happy with nonsensical variable names `for file in range(numpy):`, but complains about `for i in range(n):`. This is a bad decision with a bad justification. – Eric Duminil Jun 15 '21 at 20:50
  • Now that we have type hints in python, shouldn't it look for type hints first and only then give a warning? – ParSal Mar 24 '22 at 07:50
  • I went ahead and changed "strongly typed" to "explicitly typed" in the answer to avoid confusion. But I realised even that is probably not exactly what was meant e.g. they probably meant to include C# and C++ but both these allow type inference (with `var x = ...` and `auto x = ...``). But hopefully that is clear enough. (Like others, I think the reasoning is nonsense, but it is a literal answer to the question.) – Arthur Tacca Nov 04 '22 at 11:41
21

Nowadays there is also an option to override regexp. I.e., if you want to allow single characters as variables:

pylint --variable-rgx="[a-z0-9_]{1,30}$" <filename>

So, Pylint will match PEP8 and will not bring additional violations on top. Also you can add it to .pylintrc.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jimilian
  • 3,859
  • 30
  • 33
  • 3
    For version `> 1.8.3` this seems to be the answer. Can put this in your `.pylintrc` as well for permanent config: `variable-rgx=[a-z0-9_]{1,30}$`. – James Mar 31 '18 at 19:39
  • 12
    --variable-rgx="[a-z_][a-z0-9_]{0,30}$" may be a little more appropriate, "9" shouldn't be a valid variable name. – Eric Le Fort Feb 28 '19 at 22:48
  • 1
    pylint now has `good-names-rgxs`, which I think is an even better option. See https://stackoverflow.com/questions/21833872/why-does-pylint-object-to-single-character-variable-names/69049347#69049347 – wisbucky Sep 03 '21 at 18:40
17

The deeper reason is that you may remember what you intended a, b, c, x, y, and z to mean when you wrote your code, but when others read it, or even when you come back to your code, the code becomes much more readable when you give it a semantic name. We're not writing stuff once on a chalkboard and then erasing it. We're writing code that might stick around for a decade or more, and be read many, many times.

Use semantic names. Semantic names I've used have been like ratio, denominator, obj_generator, path, etc. It may take an extra second or two to type them out, but the time you save trying to figure out what you wrote even half an hour from then is well worth it.

Russia Must Remove Putin
  • 374,368
  • 89
  • 403
  • 331
  • 10
    Thanks. Here's the final code -- https://gist.github.com/amandabee/8969833 -- I see your point about code that I (or you) can read in a year, but in this case, I think x and y are genuinely descriptive. – Amanda Feb 17 '14 at 21:32
  • OTOH if I'm extracting an element
    from an XML document, storing it in a variable 'dt' seems quite clear, while storing it as 'date' (which is what this element happens to represent) could be confusing, and making up something like 'the_dt_field' is just silly logorrhea. (No, I have no control over the element's name; it's someone else's schema.) There must be many such exceptions which test the rule.
    – Mark Wood Aug 27 '20 at 14:16
  • 4
    Yes, and in 2 decades, we'll still understand that `i` is an integer between `0` and `n`, or that `x`, `y` and `z` are 3 floats describing a point in 3D. We might not understand the convoluted variable names which have been chosen to replace them, though. – Eric Duminil Jun 15 '21 at 20:54
  • If you have a function to sum the elements of a list (yes I know there's a built in, this is just an example), then `for element in list_to_sum: result += element` is not any clearer than `for x in list_to_sum: result += x`. There is a very common convention, in all languages, that the loop variable for very short loops should only be one characters. Making the variable name longer actually makes the code harder to read, if anything. – Arthur Tacca Nov 04 '22 at 11:56
11

pylint now has good-names-rgxs, which adds additional regex patterns to allow for variable names.

The difference is that that variable-rgx will override any previous rules, whereas good-names-rgxs adds rules on top of existing rules. That makes it more flexible, because you don't need to worry about breaking previous rules.

Just add this line to pylintrc to allow 1 or 2 length variable names:

good-names-rgxs=^[_a-z][_a-z0-9]?$

^          # starts with
[_a-z]     # 1st character required
[_a-z0-9]? # 2nd character optional
$          # ends with
wisbucky
  • 33,218
  • 10
  • 150
  • 101
2

The configuration that pylint itself generates will allow i, j, k, ex, Run, though not x,y,z.

The general solution is to adjust your .pylintrc, either for your account ($HOME/.pylintrc) or your project (<project>/.pylintrc).

First install pylint, perhaps inside your .env:

source myenv/bin/activate
pip install pylint

Next run pylint, but the file is too long to maintain manually right from the start, and so save on the side:

pylint --generate-rcfile > ~/.pylintrc--full

Look at the generated ~/.pylintrc--full. One block will say:

[BASIC]

# Good variable names which should always be accepted, separated by a comma.
good-names=i,
           j,
           k,
           ex,
           Run,
           _

Adjust this block as you like (adding x,y,..), along with any other blocks, and copy your selected excerpts into ~/.pylintrc (or <project>/.pylintrc).

Sam
  • 563
  • 5
  • 15