diff --git a/crates/ruff_linter/src/rules/perflint/rules/try_except_in_loop.rs b/crates/ruff_linter/src/rules/perflint/rules/try_except_in_loop.rs index d5c57ce2ef679..0fe6e87ce8798 100644 --- a/crates/ruff_linter/src/rules/perflint/rules/try_except_in_loop.rs +++ b/crates/ruff_linter/src/rules/perflint/rules/try_except_in_loop.rs @@ -15,21 +15,29 @@ use crate::settings::types::PythonVersion; /// Exception handling via `try`-`except` blocks incurs some performance /// overhead, regardless of whether an exception is raised. /// -/// When possible, refactor your code to put the entire loop into the -/// `try`-`except` block, rather than wrapping each iteration in a separate -/// `try`-`except` block. +/// To optimize your code, two techniques are possible: +/// 1. Refactor your code to put the entire loop into the `try`-`except` block, +/// rather than wrapping each iteration in a separate `try`-`except` block. +/// 2. Use "Look Before You Leap" idioms that attempt to avoid exceptions +/// being raised in the first place, avoiding the need to use `try`-`except` +/// blocks in the first place. /// /// This rule is only enforced for Python versions prior to 3.11, which -/// introduced "zero cost" exception handling. +/// introduced "zero-cost" exception handling. However, note that even on +/// Python 3.11 and newer, refactoring your code to avoid exception handling in +/// tight loops can provide a significant speedup in some cases, as zero-cost +/// exception handling is only zero-cost in the "happy path" where no exception +/// is raised in the `try`-`except` block. /// -/// Note that, as with all `perflint` rules, this is only intended as a -/// micro-optimization, and will have a negligible impact on performance in -/// most cases. +/// As with all `perflint` rules, this is only intended as a +/// micro-optimization. In many cases, it will have a negligible impact on +/// performance. /// /// ## Example /// ```python /// string_numbers: list[str] = ["1", "2", "three", "4", "5"] /// +/// # `try`/`except` that could be moved out of the loop: /// int_numbers: list[int] = [] /// for num in string_numbers: /// try: @@ -37,6 +45,16 @@ use crate::settings::types::PythonVersion; /// except ValueError as e: /// print(f"Couldn't convert to integer: {e}") /// break +/// +/// # `try`/`except` used when "look before you leap" idioms could be used: +/// number_names: dict[int, str] = {1: "one", 3: "three", 4: "four"} +/// for number in range(5): +/// try: +/// name = number_names[number] +/// except KeyError: +/// continue +/// else: +/// print(f"The name of {number} is {name}") /// ``` /// /// Use instead: @@ -49,6 +67,12 @@ use crate::settings::types::PythonVersion; /// int_numbers.append(int(num)) /// except ValueError as e: /// print(f"Couldn't convert to integer: {e}") +/// +/// number_names: dict[int, str] = {1: "one", 3: "three", 4: "four"} +/// for number in range(5): +/// name = number_names.get(number) +/// if name is not None: +/// print(f"The name of {number} is {name}") /// ``` /// /// ## Options