wemake-python-styleguide icon indicating copy to clipboard operation
wemake-python-styleguide copied to clipboard

Forbid types in variable name

Open orsinium opened this issue 4 years ago • 8 comments

Rule request

Thesis

Forbid using built-in type name in the variable name, either as prefix or suffix. It applies to all variable definitions: function arguments, assignments, with.

# bad
username_str = 'root'
username_str = current_user()
USERNAME_STR = 'root'
str_username = 'root'

# good
username = current_user()
username: str = current_user()
stranger = 'root'
default_user = User()

The rule should be applied to built-in types only: str, int, float, set, dict, and so on. Having context = Context() is fine.

Reasoning

Type annotations are better, they can be statically checked. Names can get outdated.

orsinium avatar Feb 18 '21 12:02 orsinium

Good one! Are there any exceptions?

I guess there are: like list - it can me a lot of things, not just list() type.

sobolevn avatar Feb 18 '21 12:02 sobolevn

I'd be confused if variable somethiing_list has type set or whatever ;)

orsinium avatar Feb 18 '21 13:02 orsinium

It can have other types as well, for example: module_list = ModuleList()

sobolevn avatar Feb 18 '21 13:02 sobolevn

Good point. Let's try to classify then

  • Abbreviated, can be safely banned: int (integer), bool (boolean), dict (dictionary).
  • Joined words, can be banned: frozenset (frozen set), bytearray (byte array).
  • Real words but rarely used, consider banning: float (hard to imagine context where it means something except floating point number), tuple (I know it is used for database entities but word "record" is a better synonym), bytes (can be something like "bytes_count", probably), complex (same as float, what else can be complex if not numbers).
  • Real words, proceed carefully: set, list, slice, type, range.

orsinium avatar Feb 18 '21 13:02 orsinium

I'm not sure about this one. I feel like there's a valid use case. Suppose you have a consuming API that takes a string but your data structure is using an int and the API doesn't auto-cast. Performing a cast every time seems silly. What would you propose the variable name be?

user = User(123)
user_id_as_str = str(user.id)

some_api(user_id_as_str)
some_other_api(user_id_as_str)
# etc..

Sxderp avatar Mar 16 '21 15:03 Sxderp

We can probably move this to typed-linter, because it has type information, which will make the implementation way easier.

sobolevn avatar Mar 16 '21 15:03 sobolevn

We can probably move this to typed-linter, because it has type information, which will make the implementation way easier.

  1. My philosophy is "something is better than nothing". It's ok to cover only some cases, not all.
  2. The issue is about the type information in the name independently of the actual type. If the name says str but the actual type is int, It's even worse.

orsinium avatar Mar 17 '21 09:03 orsinium

What would you propose the variable name be?

In your sample, user_id doesn't conflict with anything, so it should be just user_id, why not.

Suppose you have a consuming API that takes a string but your data structure is using an int and the API doesn't auto-cast.

I can't recall such API, TBH, where int should be explicitly cast to str. For instance:

import requests
requests.get('http://httpbin.org/get', params=dict(id=1)).json()['args']
# {'id': '1'}

orsinium avatar Mar 17 '21 09:03 orsinium