[perflint] Improve docs for try-except-in-loop (PERF203) (#12947)

This commit is contained in:
Alex Waygood 2024-08-17 16:00:15 +01:00 committed by GitHub
parent 52ba94191a
commit f9d8189670
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -15,21 +15,29 @@ use crate::settings::types::PythonVersion;
/// Exception handling via `try`-`except` blocks incurs some performance /// Exception handling via `try`-`except` blocks incurs some performance
/// overhead, regardless of whether an exception is raised. /// overhead, regardless of whether an exception is raised.
/// ///
/// When possible, refactor your code to put the entire loop into the /// To optimize your code, two techniques are possible:
/// `try`-`except` block, rather than wrapping each iteration in a separate /// 1. Refactor your code to put the entire loop into the `try`-`except` block,
/// `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 /// 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 /// As with all `perflint` rules, this is only intended as a
/// micro-optimization, and will have a negligible impact on performance in /// micro-optimization. In many cases, it will have a negligible impact on
/// most cases. /// performance.
/// ///
/// ## Example /// ## Example
/// ```python /// ```python
/// string_numbers: list[str] = ["1", "2", "three", "4", "5"] /// string_numbers: list[str] = ["1", "2", "three", "4", "5"]
/// ///
/// # `try`/`except` that could be moved out of the loop:
/// int_numbers: list[int] = [] /// int_numbers: list[int] = []
/// for num in string_numbers: /// for num in string_numbers:
/// try: /// try:
@ -37,6 +45,16 @@ use crate::settings::types::PythonVersion;
/// except ValueError as e: /// except ValueError as e:
/// print(f"Couldn't convert to integer: {e}") /// print(f"Couldn't convert to integer: {e}")
/// break /// 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: /// Use instead:
@ -49,6 +67,12 @@ use crate::settings::types::PythonVersion;
/// int_numbers.append(int(num)) /// int_numbers.append(int(num))
/// except ValueError as e: /// except ValueError as e:
/// print(f"Couldn't convert to integer: {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 /// ## Options