MartinThoma / flake8-simplify

❄ A flake8 plugin that helps you to simplify code
MIT License
185 stars 19 forks source link

[SIM121] Use ".get" instead of "if X in dict: dict[X]" #50

Closed MartinThoma closed 2 years ago

MartinThoma commented 3 years ago

Explanation

The get(key, default_fallback=None) method of a dictionary is often overlooked. It provides a clear interface that every Python developer should know.

Example

# Bad
name = "some_default"
if "some_key" in some_dict:
    name = some_dict["some_key"]

# Good
name = some_dict.get("some_key", "some_default")
MartinThoma commented 3 years ago
$ astpretty --no-show-offsets /dev/stdin <<< `cat example.txt`
Module(
    body=[
        Assign(
            targets=[Name(id='name', ctx=Store())],
            value=Constant(value='some_default', kind=None),
            type_comment=None,
        ),
        If(
            test=Compare(
                left=Constant(value='some_key', kind=None),
                ops=[In()],
                comparators=[Name(id='some_dict', ctx=Load())],
            ),
            body=[
                Assign(
                    targets=[Name(id='name', ctx=Store())],
                    value=Subscript(
                        value=Name(id='some_dict', ctx=Load()),
                        slice=Constant(value='some_key', kind=None),
                        ctx=Load(),
                    ),
                    type_comment=None,
                ),
            ],
            orelse=[],
        ),
    ],
    type_ignores=[],
)
MartinThoma commented 3 years ago

Related:

if "key" in some_dict:
    for item in some_dict["key"]:
MartinThoma commented 3 years ago

False-Positive (solved):

if key in some_dict:
    file = some_dict[key]
else:
    ...  # anything
MartinThoma commented 3 years ago

False-positive:

if key in some_dict:
    # other_dict["other_key"] does not exist otherwise!
    other_dict["other_key"] = some_dict['key']
Skylion007 commented 3 years ago

I've also seen:

name = "some_default" if "some_key" not in some_dict else some_dict["some_key"]
ROpdebee commented 3 years ago

Kind of related, but might suit a separate rule:

# bad
if key in some_dict:
  some_dict[key].append(value)
else:
  some_dict[key] = [value]

# good
from collections import defaultdict
some_dict = defaultdict(list)
some_dict[key].append(value)

+ sets, dicts as values

MartinThoma commented 2 years ago

I've used defaultdict in the past, but in the past 1-2 years I've rather used this pattern:

# bad
if key in some_dict:
  some_dict[key].append(value)
else:
  some_dict[key] = [value]

# Good
if key not in some_dict:
  some_dict[key] = []
some_dict[key].append(value)

I think it's typically clearer than a default dictionary, especially if the dictionary is passed to other functions.

MartinThoma commented 2 years ago

See https://github.com/MartinThoma/flake8-simplify/pull/52