{"id":318,"date":"2026-07-07T09:58:22","date_gmt":"2026-07-07T01:58:22","guid":{"rendered":"https:\/\/numsimlab.com\/?p=318"},"modified":"2026-07-07T09:58:22","modified_gmt":"2026-07-07T01:58:22","slug":"ruff-%e5%ae%8c%e5%85%a8%e5%85%a5%e9%97%a8","status":"publish","type":"post","link":"https:\/\/numsimlab.com\/?p=318","title":{"rendered":"Ruff \u5b8c\u5168\u5165\u95e8"},"content":{"rendered":"\n<!-- Generated by   -->\n<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Ruff \u5b8c\u5168\u5165\u95e8 \u00b7 Ruff Complete Guide<\/title>\n<style>\n*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}\nhtml{scroll-behavior:smooth}\n:root{\n  --bg:#f8f9fa;--bg2:#fff;--ink:#1a1a2e;--muted:#6c7086;--rule:#e2e4eb;\n  --accent:#2563eb;--accent2:#16a34a;--accent3:#dc2626;--accent4:#d97706;--accent5:#7c3aed;\n  --card-bg:#fff;--code-bg:#f1f3f5;\n  --tag-g:#dcfce7;--tag-g-t:#166534;--tag-b:#dbeafe;--tag-b-t:#1e40af;\n  --tag-r:#fee2e2;--tag-r-t:#991b1b;--tag-y:#fef9c3;--tag-y-t:#713f12;--tag-p:#f3e8ff;--tag-p-t:#581c87;\n  --shadow:0 1px 3px rgba(0,0,0,.08);--radius:8px;--max-w:940px\n}\n[data-theme=\"dark\"]{\n  --bg:#0b0b1a;--bg2:#16162a;--ink:#e2e4f0;--muted:#7f8396;--rule:#26263e;\n  --accent:#60a5fa;--accent2:#4ade80;--accent3:#f87171;--accent4:#fbbf24;--accent5:#a78bfa;\n  --card-bg:#16162a;--code-bg:#1e1e36;\n  --tag-g:#14532d;--tag-g-t:#bbf7d0;--tag-b:#1e3a5f;--tag-b-t:#bfdbfe;\n  --tag-r:#7f1d1d;--tag-r-t:#fecaca;--tag-y:#713f12;--tag-y-t:#fef08a;\n  --tag-p:#3b1f6e;--tag-p-t:#e9d5ff;--shadow:0 1px 3px rgba(0,0,0,.3)\n}\nbody{font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",\"Noto Sans SC\",\"PingFang SC\",\"Microsoft YaHei\",sans-serif;background:var(--bg);color:var(--ink);line-height:1.7;font-size:15px;transition:background .3s,color .3s}\nheader{position:fixed;top:0;left:0;right:0;z-index:100;background:var(--bg2);border-bottom:1px solid var(--rule);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);transition:background .3s}\n.header-inner{max-width:var(--max-w);margin:0 auto;display:flex;align-items:center;justify-content:space-between;padding:0 1.5rem;height:56px}\n.logo{font-weight:700;font-size:.95rem;color:var(--accent);display:flex;align-items:center;gap:.4rem}\n.controls{display:flex;align-items:center;gap:.5rem}\n.lang-switch{display:flex;border:1px solid var(--rule);border-radius:6px;overflow:hidden}\n.lang-switch button{background:0 0;border:none;color:var(--muted);padding:.3rem .7rem;font-size:.8rem;cursor:pointer;transition:all .2s;font-family:inherit}\n.lang-switch button.active{background:var(--accent);color:#fff}\n.lang-switch button:not(.active):hover{color:var(--ink);background:var(--rule)}\n.theme-toggle{background:0 0;border:1px solid var(--rule);border-radius:6px;color:var(--muted);width:34px;height:34px;font-size:1rem;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}\n.theme-toggle:hover{color:var(--ink);background:var(--rule)}\nmain{max-width:var(--max-w);margin:0 auto;padding:80px 1.5rem 3rem}\n.lang-section{display:none}.lang-section.active{display:block}\nh1{font-size:1.9rem;font-weight:800;line-height:1.3;margin-bottom:.5rem;letter-spacing:-.02em}\nh1 .sub{display:block;font-size:.85rem;font-weight:400;color:var(--muted);margin-top:.25rem;letter-spacing:0}\nh2{font-size:1.35rem;font-weight:700;margin:2.5rem 0 1rem;padding-bottom:.5rem;border-bottom:2px solid var(--accent);letter-spacing:-.01em}\nh3{font-size:1.05rem;font-weight:600;margin:1.5rem 0 .6rem;color:var(--accent)}\nh4{font-size:.95rem;font-weight:600;margin:1rem 0 .4rem;color:var(--ink)}\np{margin-bottom:.8rem}\na{color:var(--accent);text-decoration:none}a:hover{text-decoration:underline}\n.hero{text-align:center;padding:2rem 0 1rem}\n.hero p{font-size:1rem;color:var(--muted);max-width:700px;margin:0 auto}\n.tag{display:inline-block;padding:.12rem .5rem;border-radius:4px;font-size:.72rem;font-weight:600;margin-right:.25rem;white-space:nowrap}\n.tag-g{background:var(--tag-g);color:var(--tag-g-t)}.tag-b{background:var(--tag-b);color:var(--tag-b-t)}\n.tag-r{background:var(--tag-r);color:var(--tag-r-t)}.tag-y{background:var(--tag-y);color:var(--tag-y-t)}\n.tag-p{background:var(--tag-p);color:var(--tag-p-t)}\n.card{background:var(--card-bg);border:1px solid var(--rule);border-radius:var(--radius);padding:1.25rem;margin-bottom:1rem;box-shadow:var(--shadow)}\n.info-box{background:var(--bg);border-left:4px solid var(--accent);padding:.9rem 1.1rem;margin:1rem 0;border-radius:0 var(--radius) var(--radius) 0;font-size:.88rem}\n.info-box strong{color:var(--accent)}\n.info-box.warn{border-left-color:var(--accent4)}.info-box.warn strong{color:var(--accent4)}\n.info-box.danger{border-left-color:var(--accent3)}.info-box.danger strong{color:var(--accent3)}\n.toc{background:var(--card-bg);border:1px solid var(--rule);border-radius:var(--radius);padding:1.15rem 1.4rem;margin-bottom:2rem;box-shadow:var(--shadow)}\n.toc h3{margin:0 0 .5rem;font-size:.9rem;color:var(--muted);text-transform:uppercase;letter-spacing:.05em}\n.toc ol{padding-left:1.1rem;columns:2;column-gap:2rem}\n.toc li{margin-bottom:.25rem;font-size:.88rem}.toc a{color:var(--ink)}.toc a:hover{color:var(--accent);text-decoration:none}\npre.code-block{background:var(--code-bg);padding:.85rem 1rem;border-radius:var(--radius);overflow-x:auto;font-family:\"SF Mono\",Consolas,\"Courier New\",monospace;font-size:.82rem;line-height:1.5;margin:.6rem 0;border:1px solid var(--rule)}\ncode,.inline-code{background:var(--code-bg);padding:.12rem .4rem;border-radius:4px;font-family:\"SF Mono\",Consolas,\"Courier New\",monospace;font-size:.83rem;border:1px solid var(--rule)}\n.table-wrap{overflow-x:auto;margin:1.2rem 0}\ntable{width:100%;border-collapse:collapse;font-size:.82rem}\nthead th{background:var(--accent);color:#fff;padding:.6rem .5rem;text-align:center;font-weight:600;white-space:nowrap}\nthead th:first-child{border-radius:6px 0 0 0}thead th:last-child{border-radius:0 6px 0 0}\ntbody td{padding:.55rem .5rem;border-bottom:1px solid var(--rule);text-align:center;vertical-align:middle}\ntbody tr:nth-child(even){background:var(--bg)}\ntbody td:first-child{text-align:left;font-weight:600}\n.terminal{background:#1a1a2e;color:#a8e6cf;border-radius:var(--radius);padding:.9rem 1rem;font-family:\"SF Mono\",Consolas,\"Courier New\",monospace;font-size:.82rem;line-height:1.6;margin:.6rem 0;overflow-x:auto;border:1px solid #333}\n.terminal .prompt{color:#60a5fa}.terminal .comment{color:#6c7086;font-style:italic}.terminal .output{color:#e2e4f0}\n[data-theme=\"dark\"] .terminal{background:#08081a}\n.steps{counter-reset:step;list-style:none;padding:0}\n.steps li{counter-increment:step;position:relative;padding:.85rem 1rem .85rem 2.8rem;margin-bottom:.5rem;border-left:2px solid var(--rule);border-radius:0 var(--radius) var(--radius) 0;background:var(--card-bg);box-shadow:var(--shadow)}\n.steps li::before{content:counter(step);position:absolute;left:-13px;top:.85rem;width:26px;height:26px;border-radius:50%;background:var(--accent);color:#fff;display:flex;align-items:center;justify-content:center;font-size:.78rem;font-weight:700}\n.steps li .cmd{display:block;background:var(--code-bg);padding:.4rem .7rem;border-radius:5px;font-family:\"SF Mono\",Consolas,\"Courier New\",monospace;font-size:.82rem;margin:.3rem 0;overflow-x:auto;border:1px solid var(--rule)}\n.steps li .note{display:block;color:var(--muted);font-size:.82rem;margin-top:.2rem}\n.flow-diagram{background:var(--card-bg);border:1px solid var(--rule);border-radius:var(--radius);padding:1.25rem;margin:1.25rem 0;text-align:center}\n.flow-row{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:.35rem;margin:.4rem 0}\n.flow-item{display:inline-block;padding:.4rem .8rem;border-radius:6px;font-weight:600;font-size:.82rem;text-align:center;background:var(--accent);color:#fff;min-width:60px}\n.flow-item.green{background:var(--accent2)}.flow-item.red{background:var(--accent3)}.flow-item.yellow{background:var(--accent4);color:#1a1a2e}.flow-item.purple{background:var(--accent5)}\n.flow-arrow{color:var(--muted);font-size:1rem}\n.cmd-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:.75rem;margin:1rem 0}\n.cmd-card{background:var(--card-bg);border:1px solid var(--rule);border-radius:var(--radius);padding:.9rem;box-shadow:var(--shadow)}\n.cmd-card h4{margin:0 0 .35rem;font-size:.88rem;color:var(--accent)}\n.cmd-card .cmd{font-family:\"SF Mono\",Consolas,\"Courier New\",monospace;font-size:.8rem;background:var(--code-bg);padding:.3rem .5rem;border-radius:4px;display:block;margin-bottom:.3rem;border:1px solid var(--rule)}\n.cmd-card .desc{font-size:.8rem;color:var(--muted)}\n.two-col{display:grid;grid-template-columns:1fr 1fr;gap:1.25rem;margin:1.25rem 0}\n.col{background:var(--card-bg);border:1px solid var(--rule);border-radius:var(--radius);padding:1.25rem;box-shadow:var(--shadow)}\n.col h4{margin-top:0}\n.compare-box{display:grid;grid-template-columns:1fr 1fr;gap:1rem;margin:1rem 0}\n.compare-col{background:var(--card-bg);border:1px solid var(--rule);border-radius:var(--radius);padding:1rem;box-shadow:var(--shadow)}\n.compare-col h4{margin:0 0 .4rem;font-size:.88rem}\n.compare-col.bad h4{color:var(--accent3)}\n.compare-col.good h4{color:var(--accent2)}\npre.example{background:var(--code-bg);padding:.6rem .8rem;border-radius:6px;font-family:\"SF Mono\",Consolas,\"Courier New\",monospace;font-size:.78rem;line-height:1.5;margin:.4rem 0;border:1px solid var(--rule);color:var(--ink)}\nfooter{max-width:var(--max-w);margin:3rem auto 0;padding:2rem 1.5rem 3rem;border-top:1px solid var(--rule);text-align:center;font-size:.82rem;color:var(--muted)}\nfooter .links{display:flex;justify-content:center;gap:1.5rem;flex-wrap:wrap;margin-bottom:.8rem}\nfooter .links a{color:var(--muted)}footer .links a:hover{color:var(--accent)}\n@media(max-width:640px){\n  h1{font-size:1.4rem}.toc ol{columns:1}.header-inner{padding:0 1rem}main{padding:72px 1rem 2rem}\n  .steps li{padding-left:2.4rem}.steps li::before{left:-11px;width:22px;height:22px;font-size:.7rem}\n  .two-col{grid-template-columns:1fr}.cmd-grid{grid-template-columns:1fr}.compare-box{grid-template-columns:1fr}\n}\n<\/style>\n<\/head>\n<body>\n\n<header>\n  <div class=\"header-inner\">\n    <div class=\"logo\"><span>\u26a1<\/span> Ruff Complete Guide<\/div>\n    <div class=\"controls\">\n      <div class=\"lang-switch\">\n        <button class=\"active\" onclick=\"setLang('zh')\" id=\"btn-zh\">\u4e2d\u6587<\/button>\n        <button onclick=\"setLang('en')\" id=\"btn-en\">English<\/button>\n      <\/div>\n      <button class=\"theme-toggle\" onclick=\"toggleTheme()\" title=\"Toggle theme\">&#9788;<\/button>\n    <\/div>\n  <\/div>\n<\/header>\n\n<main>\n\n<!-- ==================== ZH ==================== -->\n<div class=\"lang-section active\" id=\"lang-zh\">\n<div class=\"hero\">\n  <h1>Ruff \u5b8c\u5168\u5165\u95e8<\/h1>\n  <p>\u9762\u5411\u96f6\u57fa\u7840\uff1a\u4ec0\u4e48\u662f Ruff\u3001\u4e3a\u4ec0\u4e48\u9700\u8981\u5b83\u3001\u5982\u4f55\u5b89\u88c5\u4f7f\u7528\u3001\u914d\u7f6e\u4e0e\u5b9e\u6218<\/p>\n<\/div>\n\n<div class=\"toc\">\n  <h3>\u76ee\u5f55<\/h3>\n  <ol>\n    <li><a href=\"#zh-what\">\u4ec0\u4e48\u662f Ruff<\/a><\/li>\n    <li><a href=\"#zh-why\">\u4e3a\u4ec0\u4e48\u9700\u8981 Ruff<\/a><\/li>\n    <li><a href=\"#zh-concepts\">\u4e24\u4e2a\u6838\u5fc3\u6982\u5ff5\uff1aLinter \u4e0e Formatter<\/a><\/li>\n    <li><a href=\"#zh-install\">\u5b89\u88c5 Ruff<\/a><\/li>\n    <li><a href=\"#zh-lint\">\u4ee3\u7801\u68c0\u67e5\uff08Lint\uff09<\/a><\/li>\n    <li><a href=\"#zh-format\">\u4ee3\u7801\u683c\u5f0f\u5316\uff08Format\uff09<\/a><\/li>\n    <li><a href=\"#zh-config\">\u914d\u7f6e Ruff<\/a><\/li>\n    <li><a href=\"#zh-vscode\">\u4e0e VS Code \u96c6\u6210<\/a><\/li>\n    <li><a href=\"#zh-workflow\">\u65e5\u5e38\u5f00\u53d1\u5de5\u4f5c\u6d41<\/a><\/li>\n    <li><a href=\"#zh-cheat\">\u5e38\u7528\u547d\u4ee4\u901f\u67e5\u8868<\/a><\/li>\n  <\/ol>\n<\/div>\n\n<!-- Section 1 -->\n<h2 id=\"zh-what\">\u4e00\u3001\u4ec0\u4e48\u662f Ruff<\/h2>\n<p>Ruff \u662f\u4e00\u4e2a<strong>\u7528 Rust \u7f16\u5199<\/strong>\u7684 Python \u4ee3\u7801\u68c0\u67e5\u5668\uff08Linter\uff09\u548c\u683c\u5f0f\u5316\u5de5\u5177\uff08Formatter\uff09\uff0c\u7531 <strong>Astral<\/strong> \u516c\u53f8\uff08\u540c\u65f6\u4e5f\u5f00\u53d1\u4e86 uv \u7b49\u5de5\u5177\uff09\u5f00\u53d1\u3002\u5b83\u80fd\u591f\u5728\u6beb\u79d2\u7ea7\u522b\u5b8c\u6210\u5bf9\u6574\u4e2a\u9879\u76ee\u7684\u4ee3\u7801\u68c0\u67e5\u548c\u683c\u5f0f\u5316\u3002<\/p>\n\n<div class=\"info-box\">\n  <strong>\u4e00\u53e5\u8bdd\u603b\u7ed3\uff1a<\/strong>Ruff = \u4e00\u4e2a\u5de5\u5177\u66ff\u4ee3 <code>Flake8 + Black + isort + pydocstyle + ...<\/code> \u7684 Python \u4ee3\u7801\u8d28\u91cf\u7ba1\u5bb6\u3002\n<\/div>\n\n<div class=\"card\">\n  <h4>Ruff \u7684\u6838\u5fc3\u80fd\u529b<\/h4>\n  <p><span class=\"tag tag-b\">Linter<\/span> \u68c0\u67e5\u4ee3\u7801\u98ce\u683c\u548c\u6f5c\u5728\u9519\u8bef\uff08800+ \u6761\u5185\u7f6e\u89c4\u5219\uff09<\/p>\n  <p><span class=\"tag tag-g\">Formatter<\/span> \u81ea\u52a8\u7edf\u4e00\u4ee3\u7801\u683c\u5f0f\uff08\u4e0e Black \u517c\u5bb9\u7684\u683c\u5f0f\u5316\u98ce\u683c\uff09<\/p>\n  <p><span class=\"tag tag-y\">\u81ea\u52a8\u4fee\u590d<\/span> \u5f88\u591a\u89c4\u5219\u9519\u8bef\u53ef\u4ee5\u4e00\u952e\u81ea\u52a8\u4fee\u590d<\/p>\n  <p><span class=\"tag tag-p\">\u6781\u901f<\/span> \u6bd4\u4f20\u7edf\u5de5\u5177\u5feb 10~100 \u500d<\/p>\n<\/div>\n\n<!-- Section 2 -->\n<h2 id=\"zh-why\">\u4e8c\u3001\u4e3a\u4ec0\u4e48\u9700\u8981 Ruff<\/h2>\n\n<h3>2.1 Python \u4ee3\u7801\u8d28\u91cf\u5de5\u5177\u7684\u4f20\u7edf\u56f0\u5883<\/h3>\n<p>\u5728 Ruff \u51fa\u73b0\u4e4b\u524d\uff0cPython \u5f00\u53d1\u8005\u901a\u5e38\u9700\u8981\u5b89\u88c5\u548c\u4f7f\u7528<strong>\u591a\u4e2a\u72ec\u7acb\u5de5\u5177<\/strong>\u6765\u7ba1\u7406\u4ee3\u7801\u8d28\u91cf\uff1a<\/p>\n\n<div class=\"table-wrap\">\n<table>\n  <thead>\n    <tr><th>\u5de5\u5177<\/th><th>\u4f5c\u7528<\/th><th>\u914d\u7f6e\u590d\u6742\u5ea6<\/th><\/tr>\n  <\/thead>\n  <tbody>\n    <tr><td><code>Flake8<\/code><\/td><td>\u4ee3\u7801\u98ce\u683c\u68c0\u67e5\uff08PEP 8\uff09<\/td><td>\u9700\u914d\u7f6e\u591a\u4e2a\u63d2\u4ef6<\/td><\/tr>\n    <tr><td><code>Black<\/code><\/td><td>\u4ee3\u7801\u683c\u5f0f\u5316<\/td><td>\u9700\u5355\u72ec\u5b89\u88c5<\/td><\/tr>\n    <tr><td><code>isort<\/code><\/td><td>import \u8bed\u53e5\u6392\u5e8f<\/td><td>\u9700\u5355\u72ec\u914d\u7f6e<\/td><\/tr>\n    <tr><td><code>pydocstyle<\/code><\/td><td>\u6587\u6863\u5b57\u7b26\u4e32\u89c4\u8303<\/td><td>\u9700\u5355\u72ec\u914d\u7f6e<\/td><\/tr>\n    <tr><td><code>pyupgrade<\/code><\/td><td>\u4ee3\u7801\u5347\u7ea7\u5efa\u8bae<\/td><td>\u9700\u5355\u72ec\u5b89\u88c5<\/td><\/tr>\n    <tr><td><code>bandit<\/code><\/td><td>\u5b89\u5168\u68c0\u67e5<\/td><td>\u9700\u5355\u72ec\u5b89\u88c5<\/td><\/tr>\n  <\/tbody>\n<\/table>\n<\/div>\n\n<div class=\"card\">\n  <h4>\u4f20\u7edf\u5de5\u5177\u94fe\u7684\u4e09\u5927\u75db\u70b9<\/h4>\n  <p><strong>\u914d\u7f6e\u7e41\u7410\uff1a<\/strong>\u6bcf\u4e2a\u5de5\u5177\u90fd\u9700\u8981\u5355\u72ec\u5b89\u88c5\u548c\u914d\u7f6e\uff0c\u7ecf\u5e38\u8fd8\u8981\u5904\u7406\u5b83\u4eec\u4e4b\u95f4\u7684\u517c\u5bb9\u95ee\u9898\u3002<\/p>\n  <p><strong>\u901f\u5ea6\u7f13\u6162\uff1a<\/strong>\u5927\u578b\u9879\u76ee\u8fd0\u884c\u4e00\u8f6e\u68c0\u67e5\u53ef\u80fd\u9700\u8981\u51e0\u5341\u79d2\u751a\u81f3\u51e0\u5206\u949f\uff0c\u4e25\u91cd\u5f71\u54cd\u5f00\u53d1\u4f53\u9a8c\u3002<\/p>\n  <p><strong>\u4f9d\u8d56\u6df7\u4e71\uff1a<\/strong>\u591a\u4e2a\u5de5\u5177\u5e26\u6765\u4e86\u5927\u91cf\u7684\u4f9d\u8d56\u5305\uff0c\u73af\u5883\u7ef4\u62a4\u6210\u672c\u8d8a\u6765\u8d8a\u9ad8\u3002<\/p>\n<\/div>\n\n<h3>2.2 Ruff \u7684\u4f18\u52bf<\/h3>\n<div class=\"card\">\n  <h4><span class=\"tag tag-g\">All-in-One<\/span> \u4e00\u7ad9\u5f0f\u66ff\u4ee3<\/h4>\n  <p>Ruff \u5c06 Linter\uff08\u4ee3\u7801\u68c0\u67e5\uff09\u548c Formatter\uff08\u4ee3\u7801\u683c\u5f0f\u5316\uff09\u96c6\u6210\u5230\u4e00\u4e2a\u5de5\u5177\u4e2d\uff0c\u5185\u7f6e 800+ \u6761\u89c4\u5219\uff0c\u66ff\u4ee3\u4e86 Flake8\u3001Black\u3001isort\u3001pydocstyle \u7b49\u51e0\u4e4e\u6240\u6709\u4f20\u7edf\u5de5\u5177\u3002<\/p>\n<\/div>\n<div class=\"card\">\n  <h4><span class=\"tag tag-y\">\u6781\u901f<\/span> \u6027\u80fd\u63d0\u5347 10~100 \u500d<\/h4>\n  <p>Ruff \u4f7f\u7528 Rust \u8bed\u8a00\u7f16\u5199\uff0c\u5229\u7528\u5e76\u884c\u5904\u7406\u6280\u672f\u3002\u5728\u5927\u578b\u9879\u76ee\u4e2d\uff0c\u539f\u672c\u9700\u8981 30 \u79d2\u7684\u68c0\u67e5\uff0cRuff \u53ef\u80fd\u53ea\u9700\u8981 0.3 \u79d2\u3002<\/p>\n<\/div>\n<div class=\"card\">\n  <h4><span class=\"tag tag-p\">\u4e0e Black \u517c\u5bb9<\/span> \u683c\u5f0f\u7edf\u4e00<\/h4>\n  <p>Ruff \u7684\u683c\u5f0f\u5316\u5668\u8f93\u51fa\u4e0e Black \u5b8c\u5168\u4e00\u81f4\uff0c\u53ef\u4ee5\u65e0\u7f1d\u66ff\u6362 Black\uff0c\u65e0\u9700\u62c5\u5fc3\u683c\u5f0f\u5316\u98ce\u683c\u6539\u53d8\u3002<\/p>\n<\/div>\n\n<!-- Section 3 -->\n<h2 id=\"zh-concepts\">\u4e09\u3001\u4e24\u4e2a\u6838\u5fc3\u6982\u5ff5\uff1aLinter \u4e0e Formatter<\/h2>\n\n<div class=\"two-col\">\n  <div class=\"col\">\n    <h4><span class=\"tag tag-b\">Linter<\/span> \u4ee3\u7801\u68c0\u67e5\u5668<\/h4>\n    <p>Linter \u5c31\u50cf\u4ee3\u7801\u7684<strong>&#8220;\u4f53\u68c0\u533b\u751f&#8221;<\/strong>\u2014\u2014\u5b83\u5206\u6790\u4ee3\u7801\uff0c\u627e\u51fa\uff1a<\/p>\n    <ul style=\"margin-left:1.2rem;margin-top:.4rem;\">\n      <li>\u672a\u4f7f\u7528\u7684\u53d8\u91cf\/\u5bfc\u5165<\/li>\n      <li>\u8bed\u6cd5\u9519\u8bef<\/li>\n      <li>\u4e0d\u7b26\u5408 PEP 8 \u89c4\u8303\u7684\u5199\u6cd5<\/li>\n      <li>\u6f5c\u5728 Bug\uff08\u5982\u53d8\u91cf\u8d4b\u503c\u540e\u672a\u4f7f\u7528\uff09<\/li>\n      <li>\u5b89\u5168\u95ee\u9898<\/li>\n    <\/ul>\n    <p style=\"margin-top:.4rem;\">Linter <strong>\u53ea\u68c0\u67e5\uff0c\u4e0d\u4fee\u6539<\/strong>\u4ee3\u7801\uff08\u9664\u975e\u4f7f\u7528\u81ea\u52a8\u4fee\u590d\uff09\u3002<\/p>\n  <\/div>\n  <div class=\"col\">\n    <h4><span class=\"tag tag-g\">Formatter<\/span> \u683c\u5f0f\u5316\u5de5\u5177<\/h4>\n    <p>Formatter \u5c31\u50cf\u4ee3\u7801\u7684<strong>&#8220;\u7f8e\u5bb9\u5e08&#8221;<\/strong>\u2014\u2014\u5b83\u81ea\u52a8\u8c03\u6574\uff1a<\/p>\n    <ul style=\"margin-left:1.2rem;margin-top:.4rem;\">\n      <li>\u7f29\u8fdb\uff08\u7a7a\u683c\/Tab\uff09<\/li>\n      <li>\u884c\u957f\u5ea6<\/li>\n      <li>\u7a7a\u767d\u95f4\u8ddd<\/li>\n      <li>\u5f15\u53f7\u98ce\u683c<\/li>\n      <li>import \u6392\u5e8f<\/li>\n    <\/ul>\n    <p style=\"margin-top:.4rem;\">Formatter <strong>\u76f4\u63a5\u4fee\u6539<\/strong>\u4ee3\u7801\uff0c\u7edf\u4e00\u683c\u5f0f\u3002<\/p>\n  <\/div>\n<\/div>\n\n<div class=\"compare-box\">\n  <div class=\"compare-col bad\">\n    <h4>\u274c \u672a\u7ecf Format \u7684\u4ee3\u7801<\/h4>\n    <pre class=\"example\">import os,sys\n\ndef  hello(name):\n  if name==\"world\":\n    print(\"Hello,world!\")\n  else:\n    print(\"Hello,\"+name+\"!\")\n<\/pre>\n  <\/div>\n  <div class=\"compare-col good\">\n    <h4>\u2705 Ruff Format \u540e\u7684\u4ee3\u7801<\/h4>\n    <pre class=\"example\">import os\nimport sys\n\n\ndef hello(name):\n    if name == \"world\":\n        print(\"Hello, world!\")\n    else:\n        print(\"Hello, \" + name + \"!\")\n<\/pre>\n  <\/div>\n<\/div>\n\n<!-- Section 4 -->\n<h2 id=\"zh-install\">\u56db\u3001\u5b89\u88c5 Ruff<\/h2>\n\n<div class=\"cmd-grid\">\n  <div class=\"cmd-card\">\n    <h4><span class=\"tag tag-b\">pip \u5b89\u88c5\uff08\u63a8\u8350\uff09<\/span><\/h4>\n    <div class=\"cmd\">pip install ruff<\/div>\n    <div class=\"desc\">\u63a8\u8350\u5728\u865a\u62df\u73af\u5883\u4e2d\u5b89\u88c5<\/div>\n  <\/div>\n  <div class=\"cmd-card\">\n    <h4><span class=\"tag tag-g\">uv \u5b89\u88c5\uff08\u6700\u5feb\uff09<\/span><\/h4>\n    <div class=\"cmd\">uv add &#8211;dev ruff<\/div>\n    <div class=\"desc\">\u5982\u679c\u4f7f\u7528 uv \u7ba1\u7406\u4f9d\u8d56<\/div>\n  <\/div>\n  <div class=\"cmd-card\">\n    <h4><span class=\"tag tag-y\">\u9a8c\u8bc1\u5b89\u88c5<\/span><\/h4>\n    <div class=\"cmd\">ruff &#8211;version<\/div>\n    <div class=\"desc\">\u8f93\u51fa\u7248\u672c\u53f7\u5373\u5b89\u88c5\u6210\u529f<\/div>\n  <\/div>\n  <div class=\"cmd-card\">\n    <h4><span class=\"tag tag-p\">pyproject.toml \u4f9d\u8d56<\/span><\/h4>\n    <div class=\"cmd\">[project.optional-dependencies]\ndev = [&#8220;ruff&#8221;]<\/div>\n    <div class=\"desc\">\u4f5c\u4e3a\u5f00\u53d1\u4f9d\u8d56\u5199\u5165\u9879\u76ee\u914d\u7f6e<\/div>\n  <\/div>\n<\/div>\n\n<!-- Section 5 -->\n<h2 id=\"zh-lint\">\u4e94\u3001\u4ee3\u7801\u68c0\u67e5\uff08Lint\uff09<\/h2>\n\n<h3>5.1 \u57fa\u672c\u68c0\u67e5<\/h3>\n<pre class=\"code-block\"># \u68c0\u67e5\u5f53\u524d\u76ee\u5f55\u4e0b\u6240\u6709 Python \u6587\u4ef6\nruff check .\n\n# \u68c0\u67e5\u5355\u4e2a\u6587\u4ef6\nruff check main.py\n\n# \u68c0\u67e5\u5e76\u5c1d\u8bd5\u81ea\u52a8\u4fee\u590d\nruff check . --fix\n\n# \u67e5\u770b\u8be6\u7ec6\u8f93\u51fa\uff08\u663e\u793a\u95ee\u9898\u6240\u5728\u884c\uff09\nruff check . --output-format=concise<\/pre>\n\n<h3>5.2 \u89c4\u5219\u524d\u7f00\u901f\u67e5<\/h3>\n<div class=\"table-wrap\">\n<table>\n  <thead>\n    <tr><th>\u524d\u7f00<\/th><th>\u542b\u4e49<\/th><th>\u793a\u4f8b<\/th><\/tr>\n  <\/thead>\n  <tbody>\n    <tr><td><code>E<\/code><\/td><td>PEP 8 \u9519\u8bef\uff08Error\uff09<\/td><td><code>E501<\/code> \u884c\u8fc7\u957f<\/td><\/tr>\n    <tr><td><code>W<\/code><\/td><td>PEP 8 \u8b66\u544a\uff08Warning\uff09<\/td><td><code>W291<\/code> \u884c\u5c3e\u7a7a\u767d<\/td><\/tr>\n    <tr><td><code>F<\/code><\/td><td>Pyflakes\uff08\u903b\u8f91\u9519\u8bef\uff09<\/td><td><code>F401<\/code> \u672a\u4f7f\u7528\u5bfc\u5165<\/td><\/tr>\n    <tr><td><code>I<\/code><\/td><td>isort\uff08import \u6392\u5e8f\uff09<\/td><td><code>I001<\/code> import \u672a\u6392\u5e8f<\/td><\/tr>\n    <tr><td><code>N<\/code><\/td><td>\u547d\u540d\u89c4\u8303<\/td><td><code>N802<\/code> \u51fd\u6570\u540d\u5e94\u5c0f\u5199<\/td><\/tr>\n    <tr><td><code>UP<\/code><\/td><td>pyupgrade\uff08\u5347\u7ea7\u5efa\u8bae\uff09<\/td><td><code>UP009<\/code> \u4f7f\u7528\u65b0\u8bed\u6cd5<\/td><\/tr>\n    <tr><td><code>S<\/code><\/td><td>bandit\uff08\u5b89\u5168\u68c0\u67e5\uff09<\/td><td><code>S101<\/code> \u4e0d\u5e94\u4f7f\u7528 assert<\/td><\/tr>\n    <tr><td><code>B<\/code><\/td><td>Bugbear\uff08\u5e38\u89c1 Bug\uff09<\/td><td><code>B008<\/code> \u9ed8\u8ba4\u53c2\u6570\u4e2d\u7684\u53ef\u53d8\u5bf9\u8c61<\/td><\/tr>\n  <\/tbody>\n<\/table>\n<\/div>\n\n<div class=\"info-box\">\n  <strong>\u5e38\u7528\u547d\u4ee4\uff1a<\/strong><code>ruff check . --select E,W,F,I<\/code> \u8868\u793a\u53ea\u68c0\u67e5 E\uff08PEP8 \u9519\u8bef\uff09\u3001W\uff08PEP8 \u8b66\u544a\uff09\u3001F\uff08\u903b\u8f91\u9519\u8bef\uff09\u3001I\uff08import \u6392\u5e8f\uff09\u8fd9\u56db\u7c7b\u89c4\u5219\u3002\n<\/div>\n\n<!-- Section 6 -->\n<h2 id=\"zh-format\">\u516d\u3001\u4ee3\u7801\u683c\u5f0f\u5316\uff08Format\uff09<\/h2>\n\n<pre class=\"code-block\"># \u683c\u5f0f\u5316\u5f53\u524d\u76ee\u5f55\u4e0b\u6240\u6709 Python \u6587\u4ef6\nruff format .\n\n# \u683c\u5f0f\u5316\u5355\u4e2a\u6587\u4ef6\nruff format main.py\n\n# \u9884\u89c8\u683c\u5f0f\u5316\u6548\u679c\uff08\u4e0d\u5b9e\u9645\u4fee\u6539\uff09\nruff format . --diff\n\n# \u68c0\u67e5\u4ee3\u7801\u662f\u5426\u5df2\u683c\u5f0f\u5316\uff08CI \u573a\u666f\u5e38\u7528\uff09\nruff format . --check<\/pre>\n\n<div class=\"info-box warn\">\n  <strong>\u6ce8\u610f\uff1a<\/strong><code>ruff format .<\/code> \u4f1a\u76f4\u63a5\u4fee\u6539\u6587\u4ef6\u3002\u5982\u679c\u4e0d\u786e\u5b9a\u6548\u679c\uff0c\u5148\u7528 <code>ruff format . --diff<\/code> \u9884\u89c8\u6539\u52a8\u3002\n<\/div>\n\n<h3>\u683c\u5f0f\u5316\u4e0e Linter \u7684\u533a\u522b<\/h3>\n<div class=\"table-wrap\">\n<table>\n  <thead>\n    <tr><th>\u5bf9\u6bd4\u9879<\/th><th>ruff check<\/th><th>ruff format<\/th><\/tr>\n  <\/thead>\n  <tbody>\n    <tr><td>\u4f5c\u7528<\/td><td>\u68c0\u67e5\u4ee3\u7801\u8d28\u91cf\u548c\u89c4\u8303<\/td><td>\u8c03\u6574\u4ee3\u7801\u5916\u89c2\u683c\u5f0f<\/td><\/tr>\n    <tr><td>\u662f\u5426\u4fee\u6539\u6587\u4ef6<\/td><td>\u9ed8\u8ba4\u4e0d\u4fee\u6539\uff08&#8211;fix \u53ef\u4fee\u590d\u90e8\u5206\uff09<\/td><td>\u76f4\u63a5\u4fee\u6539\u6587\u4ef6<\/td><\/tr>\n    <tr><td>\u5173\u6ce8\u70b9<\/td><td>\u903b\u8f91\u9519\u8bef\u3001\u672a\u4f7f\u7528\u53d8\u91cf\u3001\u5b89\u5168\u95ee\u9898<\/td><td>\u7f29\u8fdb\u3001\u7a7a\u683c\u3001\u6362\u884c\u3001\u5f15\u53f7<\/td><\/tr>\n    <tr><td>\u89c4\u5219\u6570\u91cf<\/td><td>800+ \u6761\u53ef\u9009\u89c4\u5219<\/td><td>\u7edf\u4e00\u7684\u683c\u5f0f\u5316\u98ce\u683c\uff08\u7c7b\u4f3c Black\uff09<\/td><\/tr>\n  <\/tbody>\n<\/table>\n<\/div>\n\n<!-- Section 7 -->\n<h2 id=\"zh-config\">\u4e03\u3001\u914d\u7f6e Ruff<\/h2>\n<p>Ruff \u7684\u914d\u7f6e\u5199\u5728\u9879\u76ee\u6839\u76ee\u5f55\u7684 <code>pyproject.toml<\/code> \u6587\u4ef6\u4e2d\uff08Python \u9879\u76ee\u7684\u6807\u51c6\u914d\u7f6e\u6587\u4ef6\uff09\u3002<\/p>\n\n<h3>7.1 \u5e38\u7528\u914d\u7f6e\u793a\u4f8b<\/h3>\n<pre class=\"code-block\">[tool.ruff]\n# \u76ee\u6807 Python \u7248\u672c\uff08\u5f71\u54cd\u5347\u7ea7\u5efa\u8bae\u7b49\u89c4\u5219\uff09\ntarget-version = \"py311\"\n\n# \u884c\u957f\u5ea6\u9650\u5236\uff08\u9ed8\u8ba4 88\uff0cBlack \u517c\u5bb9\uff09\nline-length = 88\n\n# \u542f\u7528\u7684\u89c4\u5219\u96c6\u5408\nselect = [\n    \"E\",   # PEP 8 \u9519\u8bef\n    \"W\",   # PEP 8 \u8b66\u544a\n    \"F\",   # Pyflakes \u903b\u8f91\u9519\u8bef\n    \"I\",   # isort import \u6392\u5e8f\n    \"N\",   # \u547d\u540d\u89c4\u8303\n    \"UP\",  # pyupgrade \u5347\u7ea7\u5efa\u8bae\n    \"B\",   # Bugbear\n    \"SIM\", # \u7b80\u5316\u4ee3\u7801\n]\n\n# \u5ffd\u7565\u67d0\u4e9b\u89c4\u5219\nignore = [\n    \"E501\",  # \u884c\u8fc7\u957f\uff08\u67d0\u4e9b\u60c5\u51b5\u4e0b\u592a\u4e25\u683c\uff09\n]\n\n# \u6392\u9664\u4e0d\u9700\u8981\u68c0\u67e5\u7684\u6587\u4ef6\/\u76ee\u5f55\nexclude = [\n    \".git\",\n    \"__pycache__\",\n    \"build\",\n    \"dist\",\n    \"*.egg-info\",\n    \"migrations\",  # Django \u8fc1\u79fb\u6587\u4ef6\n]\n\n[tool.ruff.format]\n# \u4f7f\u7528\u5355\u5f15\u53f7\u8fd8\u662f\u53cc\u5f15\u53f7\uff08\u9ed8\u8ba4\u53cc\u5f15\u53f7\uff0cBlack \u517c\u5bb9\uff09\nquote-style = \"double\"\n# \u7f29\u8fdb\u4f7f\u7528 Tab \u8fd8\u662f\u7a7a\u683c\nindent-style = \"space\"\n# \u662f\u5426\u4fdd\u7559\u5c3e\u968f\u9017\u53f7\nskip-magic-trailing-comma = false<\/pre>\n\n<h3>7.2 \u914d\u7f6e\u4f18\u5148\u7ea7<\/h3>\n<div class=\"flow-diagram\">\n  <div class=\"flow-row\">\n    <span class=\"flow-item\">\u547d\u4ee4\u884c\u53c2\u6570<\/span>\n    <span class=\"flow-arrow\">&gt;<\/span>\n    <span class=\"flow-item yellow\">pyproject.toml<\/span>\n    <span class=\"flow-arrow\">&gt;<\/span>\n    <span class=\"flow-item green\">\u9ed8\u8ba4\u914d\u7f6e<\/span>\n  <\/div>\n<\/div>\n<p style=\"text-align:center;color:var(--muted);font-size:.8rem;margin-top:.2rem\">\u547d\u4ee4\u884c\u53c2\u6570\u4f18\u5148\u7ea7\u6700\u9ad8\uff0c\u4f1a\u8986\u76d6\u914d\u7f6e\u6587\u4ef6\u4e2d\u7684\u8bbe\u7f6e<\/p>\n\n<!-- Section 8 -->\n<h2 id=\"zh-vscode\">\u516b\u3001\u4e0e VS Code \u96c6\u6210<\/h2>\n<p>\u6700\u63a8\u8350\u7684\u5f00\u53d1\u65b9\u5f0f\uff1a\u5b89\u88c5 VS Code \u7684 Ruff \u6269\u5c55\uff0c\u5b9e\u73b0<strong>\u4fdd\u5b58\u65f6\u81ea\u52a8\u68c0\u67e5\u548c\u683c\u5f0f\u5316<\/strong>\u3002<\/p>\n\n<ol class=\"steps\">\n  <li>\n    \u5b89\u88c5 Ruff \u6269\u5c55\n    <span class=\"note\">\u6253\u5f00 VS Code \u2192 \u6269\u5c55\u5546\u5e97 \u2192 \u641c\u7d22 &#8220;Ruff&#8221; \u2192 \u5b89\u88c5 <strong>Ruff<\/strong>\uff08\u7531 Astral \u5b98\u65b9\u63d0\u4f9b\uff09<\/span>\n  <\/li>\n  <li>\n    \u914d\u7f6e\u4fdd\u5b58\u65f6\u81ea\u52a8\u683c\u5f0f\u5316\n    <span class=\"cmd\">&#8220;editor.formatOnSave&#8221;: true,\n&#8220;[python]&#8221;: {\n    &#8220;editor.defaultFormatter&#8221;: &#8220;charliermarsh.ruff&#8221;,\n    &#8220;editor.codeActionsOnSave&#8221;: {\n        &#8220;source.fixAll.ruff&#8221;: &#8220;explicit&#8221;,\n        &#8220;source.organizeImports.ruff&#8221;: &#8220;explicit&#8221;\n    }\n}<\/span>\n    <span class=\"note\">\u5c06\u4ee5\u4e0a\u914d\u7f6e\u6dfb\u52a0\u5230 VS Code \u7684 <code>settings.json<\/code> \u4e2d\u3002\u4fdd\u5b58 Python \u6587\u4ef6\u65f6\uff0cRuff \u4f1a\u81ea\u52a8\u683c\u5f0f\u5316\u4ee3\u7801\u5e76\u4fee\u590d\u53ef\u81ea\u52a8\u4fee\u590d\u7684\u95ee\u9898\u3002<\/span>\n  <\/li>\n  <li>\n    \u4f53\u9a8c\u81ea\u52a8\u4fee\u590d\n    <span class=\"note\">\u6253\u5f00\u4e00\u4e2a\u6709\u95ee\u9898\u7684 Python \u6587\u4ef6\uff08\u5982\u672a\u4f7f\u7528\u7684\u5bfc\u5165\uff09\uff0c\u4fdd\u5b58\u540e Ruff \u4f1a\u81ea\u52a8\u79fb\u9664\u591a\u4f59\u7684\u5bfc\u5165\u5e76\u683c\u5f0f\u5316\u4ee3\u7801\u3002<\/span>\n  <\/li>\n<\/ol>\n\n<div class=\"info-box\">\n  <strong>\u914d\u7f6e\u8bf4\u660e\uff1a<\/strong><code>source.fixAll.ruff<\/code> \u8868\u793a\u4fdd\u5b58\u65f6\u81ea\u52a8\u4fee\u590d\u53ef\u4fee\u590d\u7684 lint \u9519\u8bef\uff1b<code>source.organizeImports.ruff<\/code> \u8868\u793a\u4fdd\u5b58\u65f6\u81ea\u52a8\u6574\u7406 import \u8bed\u53e5\u6392\u5e8f\u3002\n<\/div>\n\n<!-- Section 9 -->\n<h2 id=\"zh-workflow\">\u4e5d\u3001\u65e5\u5e38\u5f00\u53d1\u5de5\u4f5c\u6d41<\/h2>\n\n<div class=\"flow-diagram\">\n  <div class=\"flow-row\">\n    <span class=\"flow-item\">\u5199\u4ee3\u7801<\/span>\n    <span class=\"flow-arrow\">\u2192<\/span>\n    <span class=\"flow-item yellow\">Ctrl+S \u4fdd\u5b58<\/span>\n    <span class=\"flow-arrow\">\u2192<\/span>\n    <span class=\"flow-item green\">Ruff \u81ea\u52a8 Format + Fix<\/span>\n    <span class=\"flow-arrow\">\u2192<\/span>\n    <span class=\"flow-item\">\u7ee7\u7eed\u5f00\u53d1<\/span>\n  <\/div>\n<\/div>\n\n<h3>\u63d0\u4ea4\u524d\u7684\u68c0\u67e5\u6d41\u7a0b<\/h3>\n<ol class=\"steps\">\n  <li>\n    \u683c\u5f0f\u5316\u6240\u6709\u4ee3\u7801\n    <span class=\"cmd\">ruff format .<\/span>\n  <\/li>\n  <li>\n    \u68c0\u67e5\u5e76\u4fee\u590d\u95ee\u9898\n    <span class=\"cmd\">ruff check . &#8211;fix<\/span>\n  <\/li>\n  <li>\n    \u67e5\u770b\u5269\u4f59\u65e0\u6cd5\u81ea\u52a8\u4fee\u590d\u7684\u95ee\u9898\n    <span class=\"cmd\">ruff check .<\/span>\n    <span class=\"note\">\u624b\u52a8\u4fee\u590d\u5269\u4f59\u95ee\u9898\u540e\uff0c\u5373\u53ef\u63d0\u4ea4\u4ee3\u7801<\/span>\n  <\/li>\n<\/ol>\n\n<div class=\"info-box\">\n  <strong>\u63a8\u8350\u811a\u672c\uff1a<\/strong>\u53ef\u4ee5\u5728 <code>package.json<\/code> \u6216 <code>Makefile<\/code> \u4e2d\u6dfb\u52a0\u5feb\u6377\u547d\u4ee4\uff1a<br>\n  <code>ruff check . --fix && ruff format .<\/code> \u2014 \u4e00\u952e\u68c0\u67e5\u5e76\u683c\u5f0f\u5316\u6574\u4e2a\u9879\u76ee\u3002\n<\/div>\n\n<!-- Section 10 -->\n<h2 id=\"zh-cheat\">\u5341\u3001\u5e38\u7528\u547d\u4ee4\u901f\u67e5\u8868<\/h2>\n<div class=\"table-wrap\">\n<table>\n  <thead>\n    <tr><th>\u573a\u666f<\/th><th>\u547d\u4ee4<\/th><\/tr>\n  <\/thead>\n  <tbody>\n    <tr><td>\u68c0\u67e5\u9879\u76ee<\/td><td><code>ruff check .<\/code><\/td><\/tr>\n    <tr><td>\u68c0\u67e5\u5e76\u81ea\u52a8\u4fee\u590d<\/td><td><code>ruff check . --fix<\/code><\/td><\/tr>\n    <tr><td>\u683c\u5f0f\u5316\u9879\u76ee<\/td><td><code>ruff format .<\/code><\/td><\/tr>\n    <tr><td>\u9884\u89c8\u683c\u5f0f\u5316\u5dee\u5f02<\/td><td><code>ruff format . --diff<\/code><\/td><\/tr>\n    <tr><td>\u68c0\u67e5\u662f\u5426\u5df2\u683c\u5f0f\u5316\uff08CI\uff09<\/td><td><code>ruff format . --check<\/code><\/td><\/tr>\n    <tr><td>\u68c0\u67e5\u5355\u4e2a\u6587\u4ef6<\/td><td><code>ruff check main.py<\/code><\/td><\/tr>\n    <tr><td>\u67e5\u770b\u5e2e\u52a9<\/td><td><code>ruff --help<\/code><\/td><\/tr>\n    <tr><td>\u67e5\u770b\u7248\u672c<\/td><td><code>ruff --version<\/code><\/td><\/tr>\n  <\/tbody>\n<\/table>\n<\/div>\n\n<div class=\"info-box\">\n  <strong>\u603b\u7ed3\uff1a<\/strong>Ruff \u662f\u76ee\u524d Python \u751f\u6001\u4e2d<strong>\u6700\u63a8\u8350\u7684\u4ee3\u7801\u8d28\u91cf\u5de5\u5177<\/strong>\u3002\u5b83\u7528\u4e00\u4e2a\u5de5\u5177\u66ff\u4ee3\u4e86 Flake8 + Black + isort + pydocstyle \u7b49\u6574\u5957\u5de5\u5177\u94fe\uff0c\u901f\u5ea6\u5feb\u3001\u914d\u7f6e\u7b80\u5355\u3001\u4e0e VS Code \u65e0\u7f1d\u96c6\u6210\u3002\u65e5\u5e38\u53ea\u9700\u8bb0\u4f4f\u4e24\u6761\u547d\u4ee4\uff1a<code>ruff check . --fix<\/code> \u548c <code>ruff format .<\/code>\u3002\n<\/div>\n\n<\/div><!-- \/zh -->\n\n\n<!-- ==================== EN ==================== -->\n<div class=\"lang-section\" id=\"lang-en\">\n<div class=\"hero\">\n  <h1>Ruff Complete Guide<\/h1>\n  <p>For beginners: what Ruff is, why you need it, how to install, configure, and use it<\/p>\n<\/div>\n\n<div class=\"toc\">\n  <h3>Table of Contents<\/h3>\n  <ol>\n    <li><a href=\"#en-what\">What is Ruff<\/a><\/li>\n    <li><a href=\"#en-why\">Why Ruff<\/a><\/li>\n    <li><a href=\"#en-concepts\">Linter vs Formatter<\/a><\/li>\n    <li><a href=\"#en-install\">Installation<\/a><\/li>\n    <li><a href=\"#en-lint\">Code Checking (Lint)<\/a><\/li>\n    <li><a href=\"#en-format\">Code Formatting (Format)<\/a><\/li>\n    <li><a href=\"#en-config\">Configuration<\/a><\/li>\n    <li><a href=\"#en-vscode\">VS Code Integration<\/a><\/li>\n    <li><a href=\"#en-workflow\">Daily Workflow<\/a><\/li>\n    <li><a href=\"#en-cheat\">Command Cheat Sheet<\/a><\/li>\n  <\/ol>\n<\/div>\n\n<!-- Section 1 -->\n<h2 id=\"en-what\">1. What is Ruff<\/h2>\n<p>Ruff is a <strong>Python linter and formatter written in Rust<\/strong>, developed by <strong>Astral<\/strong> (the same company behind uv). It can lint and format entire projects in milliseconds.<\/p>\n\n<div class=\"info-box\">\n  <strong>In a nutshell:<\/strong> Ruff = one tool that replaces <code>Flake8 + Black + isort + pydocstyle + ...<\/code> for Python code quality.\n<\/div>\n\n<div class=\"card\">\n  <h4>Core Capabilities<\/h4>\n  <p><span class=\"tag tag-b\">Linter<\/span> Check code style and catch errors (800+ built-in rules)<\/p>\n  <p><span class=\"tag tag-g\">Formatter<\/span> Auto-format code (Black-compatible style)<\/p>\n  <p><span class=\"tag tag-y\">Auto-fix<\/span> Many issues can be fixed with one command<\/p>\n  <p><span class=\"tag tag-p\">Lightning fast<\/span> 10-100x faster than traditional tools<\/p>\n<\/div>\n\n<!-- Section 2 -->\n<h2 id=\"en-why\">2. Why Ruff<\/h2>\n\n<h3>2.1 The Traditional Python Toolchain Problem<\/h3>\n<p>Before Ruff, Python developers needed <strong>multiple separate tools<\/strong> for code quality:<\/p>\n\n<div class=\"table-wrap\">\n<table>\n  <thead>\n    <tr><th>Tool<\/th><th>Purpose<\/th><th>Config<\/th><\/tr>\n  <\/thead>\n  <tbody>\n    <tr><td><code>Flake8<\/code><\/td><td>Style checking (PEP 8)<\/td><td>Multiple plugins needed<\/td><\/tr>\n    <tr><td><code>Black<\/code><\/td><td>Code formatting<\/td><td>Separate install<\/td><\/tr>\n    <tr><td><code>isort<\/code><\/td><td>Import sorting<\/td><td>Separate config<\/td><\/tr>\n    <tr><td><code>pydocstyle<\/code><\/td><td>Docstring conventions<\/td><td>Separate config<\/td><\/tr>\n    <tr><td><code>pyupgrade<\/code><\/td><td>Upgrade suggestions<\/td><td>Separate install<\/td><\/tr>\n    <tr><td><code>bandit<\/code><\/td><td>Security checks<\/td><td>Separate install<\/td><\/tr>\n  <\/tbody>\n<\/table>\n<\/div>\n\n<div class=\"card\">\n  <h4>Three Pain Points of Traditional Tools<\/h4>\n  <p><strong>Tedious configuration:<\/strong> Each tool needs separate setup, and compatibility between them is often problematic.<\/p>\n  <p><strong>Slow execution:<\/strong> Running checks on large projects can take 30+ seconds \u2014 painful for daily development.<\/p>\n  <p><strong>Dependency bloat:<\/strong> Many tools bring in lots of dependencies, increasing environment maintenance cost.<\/p>\n<\/div>\n\n<h3>2.2 Ruff&#8217;s Advantages<\/h3>\n<div class=\"card\">\n  <h4><span class=\"tag tag-g\">All-in-One<\/span> One Tool to Rule Them All<\/h4>\n  <p>Ruff integrates linter and formatter into a single tool with 800+ built-in rules, replacing Flake8, Black, isort, pydocstyle, and more.<\/p>\n<\/div>\n<div class=\"card\">\n  <h4><span class=\"tag tag-y\">Blazing Fast<\/span> 10-100x Performance<\/h4>\n  <p>Written in Rust with parallel processing. A 30-second check on a large project might finish in 0.3 seconds with Ruff.<\/p>\n<\/div>\n<div class=\"card\">\n  <h4><span class=\"tag tag-p\">Black-Compatible<\/span> Consistent Formatting<\/h4>\n  <p>Ruff&#8217;s formatter produces identical output to Black, allowing seamless replacement without style changes.<\/p>\n<\/div>\n\n<!-- Section 3 -->\n<h2 id=\"en-concepts\">3. Linter vs Formatter<\/h2>\n\n<div class=\"two-col\">\n  <div class=\"col\">\n    <h4><span class=\"tag tag-b\">Linter<\/span> Code Analyzer<\/h4>\n    <p>A Linter is like a <strong>&#8220;code doctor&#8221;<\/strong> \u2014 it analyzes code and finds:<\/p>\n    <ul style=\"margin-left:1.2rem;margin-top:.4rem;\">\n      <li>Unused variables\/imports<\/li>\n      <li>Syntax errors<\/li>\n      <li>PEP 8 violations<\/li>\n      <li>Potential bugs<\/li>\n      <li>Security issues<\/li>\n    <\/ul>\n    <p style=\"margin-top:.4rem;\">A Linter <strong>reads only<\/strong>, it doesn&#8217;t modify code (unless auto-fix is used).<\/p>\n  <\/div>\n  <div class=\"col\">\n    <h4><span class=\"tag tag-g\">Formatter<\/span> Code Beautifier<\/h4>\n    <p>A Formatter is like a <strong>&#8220;code stylist&#8221;<\/strong> \u2014 it automatically adjusts:<\/p>\n    <ul style=\"margin-left:1.2rem;margin-top:.4rem;\">\n      <li>Indentation<\/li>\n      <li>Line length<\/li>\n      <li>Whitespace<\/li>\n      <li>Quote style<\/li>\n      <li>Import sorting<\/li>\n    <\/ul>\n    <p style=\"margin-top:.4rem;\">A Formatter <strong>directly modifies<\/strong> code to enforce consistent style.<\/p>\n  <\/div>\n<\/div>\n\n<div class=\"compare-box\">\n  <div class=\"compare-col bad\">\n    <h4>\u274c Before Format<\/h4>\n    <pre class=\"example\">import os,sys\n\ndef  hello(name):\n  if name==\"world\":\n    print(\"Hello,world!\")\n  else:\n    print(\"Hello,\"+name+\"!\")\n<\/pre>\n  <\/div>\n  <div class=\"compare-col good\">\n    <h4>\u2705 After Ruff Format<\/h4>\n    <pre class=\"example\">import os\nimport sys\n\n\ndef hello(name):\n    if name == \"world\":\n        print(\"Hello, world!\")\n    else:\n        print(\"Hello, \" + name + \"!\")\n<\/pre>\n  <\/div>\n<\/div>\n\n<!-- Section 4 -->\n<h2 id=\"en-install\">4. Installation<\/h2>\n\n<div class=\"cmd-grid\">\n  <div class=\"cmd-card\">\n    <h4><span class=\"tag tag-b\">pip (Recommended)<\/span><\/h4>\n    <div class=\"cmd\">pip install ruff<\/div>\n    <div class=\"desc\">Best installed in a virtual environment<\/div>\n  <\/div>\n  <div class=\"cmd-card\">\n    <h4><span class=\"tag tag-g\">uv (Fastest)<\/span><\/h4>\n    <div class=\"cmd\">uv add &#8211;dev ruff<\/div>\n    <div class=\"desc\">If using uv for dependency management<\/div>\n  <\/div>\n  <div class=\"cmd-card\">\n    <h4><span class=\"tag tag-y\">Verify Install<\/span><\/h4>\n    <div class=\"cmd\">ruff &#8211;version<\/div>\n    <div class=\"desc\">Shows version number if installed correctly<\/div>\n  <\/div>\n  <div class=\"cmd-card\">\n    <h4><span class=\"tag tag-p\">pyproject.toml<\/span><\/h4>\n    <div class=\"cmd\">[project.optional-dependencies]\ndev = [&#8220;ruff&#8221;]<\/div>\n    <div class=\"desc\">Add as a dev dependency in project config<\/div>\n  <\/div>\n<\/div>\n\n<!-- Section 5 -->\n<h2 id=\"en-lint\">5. Code Checking (Lint)<\/h2>\n\n<h3>5.1 Basic Checking<\/h3>\n<pre class=\"code-block\"># Check all Python files in current directory\nruff check .\n\n# Check a single file\nruff check main.py\n\n# Check and attempt auto-fix\nruff check . --fix\n\n# Detailed output (show affected lines)\nruff check . --output-format=concise<\/pre>\n\n<h3>5.2 Rule Prefix Reference<\/h3>\n<div class=\"table-wrap\">\n<table>\n  <thead>\n    <tr><th>Prefix<\/th><th>Category<\/th><th>Example<\/th><\/tr>\n  <\/thead>\n  <tbody>\n    <tr><td><code>E<\/code><\/td><td>PEP 8 Errors<\/td><td><code>E501<\/code> line too long<\/td><\/tr>\n    <tr><td><code>W<\/code><\/td><td>PEP 8 Warnings<\/td><td><code>W291<\/code> trailing whitespace<\/td><\/tr>\n    <tr><td><code>F<\/code><\/td><td>Pyflakes (logic)<\/td><td><code>F401<\/code> unused import<\/td><\/tr>\n    <tr><td><code>I<\/code><\/td><td>isort (imports)<\/td><td><code>I001<\/code> unsorted imports<\/td><\/tr>\n    <tr><td><code>N<\/code><\/td><td>Naming conventions<\/td><td><code>N802<\/code> function naming<\/td><\/tr>\n    <tr><td><code>UP<\/code><\/td><td>pyupgrade<\/td><td><code>UP009<\/code> use modern syntax<\/td><\/tr>\n    <tr><td><code>S<\/code><\/td><td>bandit (security)<\/td><td><code>S101<\/code> no assert in production<\/td><\/tr>\n    <tr><td><code>B<\/code><\/td><td>Bugbear<\/td><td><code>B008<\/code> mutable default arg<\/td><\/tr>\n  <\/tbody>\n<\/table>\n<\/div>\n\n<div class=\"info-box\">\n  <strong>Common usage:<\/strong><code>ruff check . --select E,W,F,I<\/code> checks only E (PEP8 errors), W (warnings), F (logic), and I (import sorting) rules.\n<\/div>\n\n<!-- Section 6 -->\n<h2 id=\"en-format\">6. Code Formatting (Format)<\/h2>\n\n<pre class=\"code-block\"># Format all Python files in current directory\nruff format .\n\n# Format a single file\nruff format main.py\n\n# Preview changes without modifying files\nruff format . --diff\n\n# Check if code is formatted (useful in CI)\nruff format . --check<\/pre>\n\n<div class=\"info-box warn\">\n  <strong>Warning:<\/strong><code>ruff format .<\/code> directly modifies files. Use <code>ruff format . --diff<\/code> to preview first.\n<\/div>\n\n<h3>check vs format Comparison<\/h3>\n<div class=\"table-wrap\">\n<table>\n  <thead>\n    <tr><th>Aspect<\/th><th>ruff check<\/th><th>ruff format<\/th><\/tr>\n  <\/thead>\n  <tbody>\n    <tr><td>Purpose<\/td><td>Check code quality &amp; standards<\/td><td>Adjust code appearance<\/td><\/tr>\n    <tr><td>Modifies files?<\/td><td>No by default (&#8211;fix for some)<\/td><td>Yes, directly<\/td><\/tr>\n    <tr><td>Focus<\/td><td>Logic errors, unused vars, security<\/td><td>Indentation, spaces, line breaks<\/td><\/tr>\n    <tr><td>Rules<\/td><td>800+ optional rules<\/td><td>Unified formatting style (Black-like)<\/td><\/tr>\n  <\/tbody>\n<\/table>\n<\/div>\n\n<!-- Section 7 -->\n<h2 id=\"en-config\">7. Configuration<\/h2>\n<p>Ruff configuration lives in the project&#8217;s <code>pyproject.toml<\/code> file (the standard Python project config file).<\/p>\n\n<h3>7.1 Common Configuration<\/h3>\n<pre class=\"code-block\">[tool.ruff]\n# Target Python version\ntarget-version = \"py311\"\n\n# Line length limit (default 88, Black-compatible)\nline-length = 88\n\n# Enabled rule sets\nselect = [\n    \"E\",   # PEP 8 errors\n    \"W\",   # PEP 8 warnings\n    \"F\",   # Pyflakes\n    \"I\",   # isort\n    \"N\",   # naming\n    \"UP\",  # pyupgrade\n    \"B\",   # bugbear\n    \"SIM\", # simplification\n]\n\n# Ignore specific rules\nignore = [\n    \"E501\",  # line too long (sometimes too strict)\n]\n\n# Exclude files\/directories\nexclude = [\n    \".git\",\n    \"__pycache__\",\n    \"build\",\n    \"dist\",\n    \"*.egg-info\",\n    \"migrations\",\n]\n\n[tool.ruff.format]\nquote-style = \"double\"\nindent-style = \"space\"\nskip-magic-trailing-comma = false<\/pre>\n\n<h3>7.2 Configuration Precedence<\/h3>\n<div class=\"flow-diagram\">\n  <div class=\"flow-row\">\n    <span class=\"flow-item\">CLI args<\/span>\n    <span class=\"flow-arrow\">&gt;<\/span>\n    <span class=\"flow-item yellow\">pyproject.toml<\/span>\n    <span class=\"flow-arrow\">&gt;<\/span>\n    <span class=\"flow-item green\">Defaults<\/span>\n  <\/div>\n<\/div>\n<p style=\"text-align:center;color:var(--muted);font-size:.8rem;margin-top:.2rem\">Command-line arguments have highest priority and override config file settings<\/p>\n\n<!-- Section 8 -->\n<h2 id=\"en-vscode\">8. VS Code Integration<\/h2>\n<p>Recommended workflow: install the Ruff VS Code extension for <strong>auto-format on save<\/strong>.<\/p>\n\n<ol class=\"steps\">\n  <li>\n    Install the Ruff Extension\n    <span class=\"note\">VS Code \u2192 Extensions \u2192 Search &#8220;Ruff&#8221; \u2192 Install <strong>Ruff<\/strong> by Astral<\/span>\n  <\/li>\n  <li>\n    Configure auto-format on save\n    <span class=\"cmd\">&#8220;editor.formatOnSave&#8221;: true,\n&#8220;[python]&#8221;: {\n    &#8220;editor.defaultFormatter&#8221;: &#8220;charliermarsh.ruff&#8221;,\n    &#8220;editor.codeActionsOnSave&#8221;: {\n        &#8220;source.fixAll.ruff&#8221;: &#8220;explicit&#8221;,\n        &#8220;source.organizeImports.ruff&#8221;: &#8220;explicit&#8221;\n    }\n}<\/span>\n    <span class=\"note\">Add to VS Code&#8217;s <code>settings.json<\/code>. Ruff auto-formats and fixes on save.<\/span>\n  <\/li>\n  <li>\n    Test auto-fixing\n    <span class=\"note\">Open a Python file with issues (e.g., unused imports). Save and watch Ruff clean it up automatically.<\/span>\n  <\/li>\n<\/ol>\n\n<div class=\"info-box\">\n  <strong>Config note:<\/strong><code>source.fixAll.ruff<\/code> auto-fixes lint errors on save; <code>source.organizeImports.ruff<\/code> sorts imports automatically.\n<\/div>\n\n<!-- Section 9 -->\n<h2 id=\"en-workflow\">9. Daily Workflow<\/h2>\n\n<div class=\"flow-diagram\">\n  <div class=\"flow-row\">\n    <span class=\"flow-item\">Write code<\/span>\n    <span class=\"flow-arrow\">\u2192<\/span>\n    <span class=\"flow-item yellow\">Ctrl+S<\/span>\n    <span class=\"flow-arrow\">\u2192<\/span>\n    <span class=\"flow-item green\">Ruff auto Format + Fix<\/span>\n    <span class=\"flow-arrow\">\u2192<\/span>\n    <span class=\"flow-item\">Continue<\/span>\n  <\/div>\n<\/div>\n\n<h3>Pre-Commit Check<\/h3>\n<ol class=\"steps\">\n  <li>\n    Format all code\n    <span class=\"cmd\">ruff format .<\/span>\n  <\/li>\n  <li>\n    Check and fix issues\n    <span class=\"cmd\">ruff check . &#8211;fix<\/span>\n  <\/li>\n  <li>\n    Review remaining issues\n    <span class=\"cmd\">ruff check .<\/span>\n    <span class=\"note\">Manually fix any remaining issues, then commit<\/span>\n  <\/li>\n<\/ol>\n\n<div class=\"info-box\">\n  <strong>Tip:<\/strong> Add a shortcut to <code>package.json<\/code> or <code>Makefile<\/code>:<br>\n  <code>ruff check . --fix && ruff format .<\/code> \u2014 one command to lint and format the entire project.\n<\/div>\n\n<!-- Section 10 -->\n<h2 id=\"en-cheat\">10. Command Cheat Sheet<\/h2>\n<div class=\"table-wrap\">\n<table>\n  <thead>\n    <tr><th>Scenario<\/th><th>Command<\/th><\/tr>\n  <\/thead>\n  <tbody>\n    <tr><td>Check project<\/td><td><code>ruff check .<\/code><\/td><\/tr>\n    <tr><td>Check and auto-fix<\/td><td><code>ruff check . --fix<\/code><\/td><\/tr>\n    <tr><td>Format project<\/td><td><code>ruff format .<\/code><\/td><\/tr>\n    <tr><td>Preview format changes<\/td><td><code>ruff format . --diff<\/code><\/td><\/tr>\n    <tr><td>Check formatting (CI)<\/td><td><code>ruff format . --check<\/code><\/td><\/tr>\n    <tr><td>Check single file<\/td><td><code>ruff check main.py<\/code><\/td><\/tr>\n    <tr><td>Help<\/td><td><code>ruff --help<\/code><\/td><\/tr>\n    <tr><td>Version<\/td><td><code>ruff --version<\/code><\/td><\/tr>\n  <\/tbody>\n<\/table>\n<\/div>\n\n<div class=\"info-box\">\n  <strong>Summary:<\/strong> Ruff is the <strong>most recommended Python code quality tool<\/strong> today. It replaces the entire Flake8 + Black + isort + pydocstyle toolchain with a single fast tool that integrates seamlessly with VS Code. Just remember two commands: <code>ruff check . --fix<\/code> and <code>ruff format .<\/code>.\n<\/div>\n\n<\/div><!-- \/en -->\n\n<\/main>\n\n<footer>\n  <div class=\"links\">\n    <a href=\"https:\/\/docs.astral.sh\/ruff\/\" target=\"_blank\" rel=\"noopener\">Ruff Official Docs<\/a>\n    <a href=\"https:\/\/github.com\/astral-sh\/ruff\" target=\"_blank\" rel=\"noopener\">GitHub<\/a>\n    <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=charliermarsh.ruff\" target=\"_blank\" rel=\"noopener\">VS Code Extension<\/a>\n    <a href=\"https:\/\/astral.sh\/\" target=\"_blank\" rel=\"noopener\">Astral<\/a>\n  <\/div>\n  <p>Ruff Complete Guide \u00b7 Ruff \u5b8c\u5168\u5165\u95e8<\/p>\n<\/footer>\n\n<script>\nfunction setLang(lang){\n  document.querySelectorAll('.lang-section').forEach(function(el){el.classList.remove('active')});\n  document.getElementById('lang-'+lang).classList.add('active');\n  document.querySelectorAll('.lang-switch button').forEach(function(btn){btn.classList.remove('active')});\n  document.getElementById('btn-'+lang).classList.add('active');\n  document.documentElement.lang=lang==='zh'?'zh-CN':'en';\n  var p=lang==='zh'?'zh':'en';\n  var h=window.location.hash.replace(\/^#(zh|en)-\/,p+'-');\n  if(h)window.location.hash=h;\n}\nfunction toggleTheme(){\n  var html=document.documentElement;\n  if(html.hasAttribute('data-theme')){html.removeAttribute('data-theme');localStorage.removeItem('theme')}\n  else{html.setAttribute('data-theme','dark');localStorage.setItem('theme','dark')}\n}\n(function(){\n  if(localStorage.getItem('theme')==='dark')document.documentElement.setAttribute('data-theme','dark');\n  var h=window.location.hash;\n  if(h){var t=document.querySelector(h);if(t)setTimeout(function(){t.scrollIntoView({behavior:'smooth'})},100)}\n})();\n<\/script>\n<\/body>\n<\/html>\n","protected":false},"excerpt":{"rendered":"<p>Ruff \u5b8c\u5168\u5165\u95e8 \u00b7 Ruff Complete Guide \u26a1 Ruff Complete Guide \u4e2d [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11,9],"tags":[],"class_list":["post-318","post","type-post","status-publish","format-standard","hentry","category-cad","category-ai"],"blocksy_meta":[],"_links":{"self":[{"href":"https:\/\/numsimlab.com\/index.php?rest_route=\/wp\/v2\/posts\/318","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/numsimlab.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/numsimlab.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/numsimlab.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/numsimlab.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=318"}],"version-history":[{"count":1,"href":"https:\/\/numsimlab.com\/index.php?rest_route=\/wp\/v2\/posts\/318\/revisions"}],"predecessor-version":[{"id":319,"href":"https:\/\/numsimlab.com\/index.php?rest_route=\/wp\/v2\/posts\/318\/revisions\/319"}],"wp:attachment":[{"href":"https:\/\/numsimlab.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=318"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/numsimlab.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=318"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/numsimlab.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=318"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}