Refactoring Python Applications for Simplicity¶
重构并精简Python应用1
Metrics¶
行数/Lines of Code¶
- Linux
# file
$ wc -l file.py
# folder
$ find . -name \*.py | xargs wc -l
- windows
Get-ChildItem -Path *.py -Recurse | Measure-Object –Line
链路复杂度/Cyclomatic Complexity¶
-
tool
pip install radon radon cc cyclomatic_example.py -s
-
explain
-
F means function, M means method, and C means class.
- main is the name of the function.
- 4 is the line the function starts on.
- B is the rating from A to F. A is the best grade, meaning the least complexity.
- The number in parentheses, 6, is the cyclomatic complexity of the code.
难度度量元/Halstead Metrics¶
- 4 Measures
- Operands are values and names of variables.
- Operators are all of the built-in keywords, like if, else, for or while.
- Length (N) is the number of operators plus the number of operands in your program.
-
Vocabulary (h) is the number of unique operators plus the number of unique operands in your a program.
-
3 metrics
-
Volume (V) represents a product of the length and the vocabulary.
- Difficulty (D) represents a product of half the unique operands and the reuse of operands.
-
Effort (E) is the overall metric that is a product of volume and difficulty.
-
explain
import sys # import (operator), sys (operand) if len(sys.argv) > 1: ... # 5 operators - if - ( - ) - > - : # 2 operands - sys.argv - 1
-
commands
radon hal cyclomatic_example.py
# time = effort/18
# bugs = volumn/3000
Maintainability Index/MI¶
- command
radon mi cyclomatic_example.py -s
-
explian
- lower than 25: hard to maintain
- over 75: easy to maintain
wily: Capture and Track Complexity¶
- command
$ pip install wily
-
explain
-
wily build: iterate through the Git history and analyze the metrics for each file
- wily report: see the historical trend in metrics for a given file or folder
- wily graph: graph a set of metrics in an HTML file
example: wily¶
$ git clone https://github.com/requests/requests
$ cd requests
$ ls
# build
$ wily build requests
# Lines/MI/Cyclomatic Complexity
$ wily report requests/api.py
#
$ wily list-metrics
# report
$ wily report requests/api.py maintainability.rank raw.sloc
#graph
$ wily graph requests/sessions.py maintainability.mi
# html
$ wily graph requests/sessions.py maintainability.mi -o my_report.html
Pre-commit Hook¶
-
shell
$ wily diff requests/api.py $ pip install pre-commit
-
.pre-commit-config.yaml
repos: - repo: local hooks: - id: wily name: wily entry: wily diff verbose: true language: python additional_dependencies: [wily]
-
shell
$ pre-commit install
Refactoring¶
- Using rope
pip install rope
from rope.base.project import Project
proj = Project('requests')
[f.name for f in proj.get_files()]
api = proj.get_file('api.py')
from rope.refactor.rename import Rename
change = Rename(proj, api).get_changes('new_api')
proj.do(change)
- Using VSCode
- Using Pycharm
- etc.
Anti-Patterns¶
- Functions Be Objects
- Objects Be Functions
- "Triangular" code=>Flat Code
-
Handling Complex Dictionaries With Query Tools
# pip install jmespath import jmespath jmespath.search("network.lines", data)
-
Using attrs and dataclasses to Reduce Code
-
https://realpython.com/python-refactoring/#using-wily-to-capture-and-track-your-projects-complexity ↩