mirror of
https://github.com/james-m-jordan/morphik-core.git
synced 2025-05-09 19:32:38 +00:00
3729 lines
237 KiB
HTML
3729 lines
237 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en-US">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
|
||
<!-- Begin Jekyll SEO tag v2.8.0 -->
|
||
<title>styleguide | Style guides for Google-originated open-source projects</title>
|
||
<meta name="generator" content="Jekyll v3.10.0" />
|
||
<meta property="og:title" content="styleguide" />
|
||
<meta property="og:locale" content="en_US" />
|
||
<meta name="description" content="Style guides for Google-originated open-source projects" />
|
||
<meta property="og:description" content="Style guides for Google-originated open-source projects" />
|
||
<link rel="canonical" href="https://google.github.io/styleguide/pyguide.html" />
|
||
<meta property="og:url" content="https://google.github.io/styleguide/pyguide.html" />
|
||
<meta property="og:site_name" content="styleguide" />
|
||
<meta property="og:type" content="website" />
|
||
<meta name="twitter:card" content="summary" />
|
||
<meta property="twitter:title" content="styleguide" />
|
||
<script type="application/ld+json">
|
||
{"@context":"https://schema.org","@type":"WebPage","description":"Style guides for Google-originated open-source projects","headline":"styleguide","url":"https://google.github.io/styleguide/pyguide.html"}</script>
|
||
<!-- End Jekyll SEO tag -->
|
||
|
||
<link rel="stylesheet" href="/styleguide/assets/css/style.css?v=7802b6521bf22d18eaa13c60bfa21663707c3c5d">
|
||
<link rel="shortcut icon" type="image/x-icon" href="/styleguide/favicon.ico">
|
||
|
||
</head>
|
||
<body>
|
||
<div class="container-lg px-3 my-5 markdown-body">
|
||
|
||
<h1><a href="https://google.github.io/styleguide/">styleguide</a></h1>
|
||
|
||
|
||
<!--
|
||
AUTHORS:
|
||
Prefer only GitHub-flavored Markdown in external text.
|
||
See README.md for details.
|
||
-->
|
||
|
||
<h1 id="google-python-style-guide">Google Python Style Guide</h1>
|
||
|
||
<!-- markdown="1" is required for GitHub Pages to render the TOC properly. -->
|
||
|
||
<details>
|
||
<summary>Table of Contents</summary>
|
||
|
||
<ul>
|
||
<li><a href="#s1-background">1 Background</a></li>
|
||
<li><a href="#s2-python-language-rules">2 Python Language Rules</a>
|
||
<ul>
|
||
<li><a href="#s2.1-lint">2.1 Lint</a></li>
|
||
<li><a href="#s2.2-imports">2.2 Imports</a></li>
|
||
<li><a href="#s2.3-packages">2.3 Packages</a></li>
|
||
<li><a href="#s2.4-exceptions">2.4 Exceptions</a></li>
|
||
<li><a href="#s2.5-global-variables">2.5 Mutable Global State</a></li>
|
||
<li><a href="#s2.6-nested">2.6 Nested/Local/Inner Classes and Functions</a></li>
|
||
<li><a href="#s2.7-comprehensions">2.7 Comprehensions & Generator Expressions</a></li>
|
||
<li><a href="#s2.8-default-iterators-and-operators">2.8 Default Iterators and Operators</a></li>
|
||
<li><a href="#s2.9-generators">2.9 Generators</a></li>
|
||
<li><a href="#s2.10-lambda-functions">2.10 Lambda Functions</a></li>
|
||
<li><a href="#s2.11-conditional-expressions">2.11 Conditional Expressions</a></li>
|
||
<li><a href="#s2.12-default-argument-values">2.12 Default Argument Values</a></li>
|
||
<li><a href="#s2.13-properties">2.13 Properties</a></li>
|
||
<li><a href="#s2.14-truefalse-evaluations">2.14 True/False Evaluations</a></li>
|
||
<li><a href="#s2.16-lexical-scoping">2.16 Lexical Scoping</a></li>
|
||
<li><a href="#s2.17-function-and-method-decorators">2.17 Function and Method Decorators</a></li>
|
||
<li><a href="#s2.18-threading">2.18 Threading</a></li>
|
||
<li><a href="#s2.19-power-features">2.19 Power Features</a></li>
|
||
<li><a href="#s2.20-modern-python">2.20 Modern Python: from __future__ imports</a></li>
|
||
<li><a href="#s2.21-type-annotated-code">2.21 Type Annotated Code</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#s3-python-style-rules">3 Python Style Rules</a>
|
||
<ul>
|
||
<li><a href="#s3.1-semicolons">3.1 Semicolons</a></li>
|
||
<li><a href="#s3.2-line-length">3.2 Line length</a></li>
|
||
<li><a href="#s3.3-parentheses">3.3 Parentheses</a></li>
|
||
<li><a href="#s3.4-indentation">3.4 Indentation</a>
|
||
<ul>
|
||
<li><a href="#s3.4.1-trailing-commas">3.4.1 Trailing commas in sequences of items?</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#s3.5-blank-lines">3.5 Blank Lines</a></li>
|
||
<li><a href="#s3.6-whitespace">3.6 Whitespace</a></li>
|
||
<li><a href="#s3.7-shebang-line">3.7 Shebang Line</a></li>
|
||
<li><a href="#s3.8-comments-and-docstrings">3.8 Comments and Docstrings</a>
|
||
<ul>
|
||
<li><a href="#s3.8.1-comments-in-doc-strings">3.8.1 Docstrings</a></li>
|
||
<li><a href="#s3.8.2-comments-in-modules">3.8.2 Modules</a></li>
|
||
<li><a href="#s3.8.2.1-test-modules">3.8.2.1 Test modules</a></li>
|
||
<li><a href="#s3.8.3-functions-and-methods">3.8.3 Functions and Methods</a></li>
|
||
<li><a href="#s3.8.3.1-overridden-methods">3.8.3.1 Overridden Methods</a></li>
|
||
<li><a href="#s3.8.4-comments-in-classes">3.8.4 Classes</a></li>
|
||
<li><a href="#s3.8.5-block-and-inline-comments">3.8.5 Block and Inline Comments</a></li>
|
||
<li><a href="#s3.8.6-punctuation-spelling-and-grammar">3.8.6 Punctuation, Spelling, and Grammar</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#s3.10-strings">3.10 Strings</a>
|
||
<ul>
|
||
<li><a href="#s3.10.1-logging">3.10.1 Logging</a></li>
|
||
<li><a href="#s3.10.2-error-messages">3.10.2 Error Messages</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#s3.11-files-sockets-closeables">3.11 Files, Sockets, and similar Stateful Resources</a></li>
|
||
<li><a href="#s3.12-todo-comments">3.12 TODO Comments</a></li>
|
||
<li><a href="#s3.13-imports-formatting">3.13 Imports formatting</a></li>
|
||
<li><a href="#s3.14-statements">3.14 Statements</a></li>
|
||
<li><a href="#s3.15-accessors">3.15 Accessors</a></li>
|
||
<li><a href="#s3.16-naming">3.16 Naming</a>
|
||
<ul>
|
||
<li><a href="#s3.16.1-names-to-avoid">3.16.1 Names to Avoid</a></li>
|
||
<li><a href="#s3.16.2-naming-conventions">3.16.2 Naming Conventions</a></li>
|
||
<li><a href="#s3.16.3-file-naming">3.16.3 File Naming</a></li>
|
||
<li><a href="#s3.16.4-guidelines-derived-from-guidos-recommendations">3.16.4 Guidelines derived from Guido’s Recommendations</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#s3.17-main">3.17 Main</a></li>
|
||
<li><a href="#s3.18-function-length">3.18 Function length</a></li>
|
||
<li><a href="#s3.19-type-annotations">3.19 Type Annotations</a>
|
||
<ul>
|
||
<li><a href="#s3.19.1-general-rules">3.19.1 General Rules</a></li>
|
||
<li><a href="#s3.19.2-line-breaking">3.19.2 Line Breaking</a></li>
|
||
<li><a href="#s3.19.3-forward-declarations">3.19.3 Forward Declarations</a></li>
|
||
<li><a href="#s3.19.4-default-values">3.19.4 Default Values</a></li>
|
||
<li><a href="#s3.19.5-nonetype">3.19.5 NoneType</a></li>
|
||
<li><a href="#s3.19.6-type-aliases">3.19.6 Type Aliases</a></li>
|
||
<li><a href="#s3.19.7-ignoring-types">3.19.7 Ignoring Types</a></li>
|
||
<li><a href="#s3.19.8-typing-variables">3.19.8 Typing Variables</a></li>
|
||
<li><a href="#s3.19.9-tuples-vs-lists">3.19.9 Tuples vs Lists</a></li>
|
||
<li><a href="#s3.19.10-typevars">3.19.10 Type variables</a></li>
|
||
<li><a href="#s3.19.11-string-types">3.19.11 String types</a></li>
|
||
<li><a href="#s3.19.12-imports-for-typing">3.19.12 Imports For Typing</a></li>
|
||
<li><a href="#s3.19.13-conditional-imports">3.19.13 Conditional Imports</a></li>
|
||
<li><a href="#s3.19.14-circular-dependencies">3.19.14 Circular Dependencies</a></li>
|
||
<li><a href="#s3.19.15-generics">3.19.15 Generics</a></li>
|
||
<li><a href="#s3.19.16-build-dependencies">3.19.16 Build Dependencies</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#4-parting-words">4 Parting Words</a></li>
|
||
</ul>
|
||
|
||
</details>
|
||
|
||
<p><a id="s1-background"></a>
|
||
<a id="1-background"></a></p>
|
||
|
||
<p><a id="background"></a></p>
|
||
<h2 id="1-background">1 Background</h2>
|
||
|
||
<p>Python is the main dynamic language used at Google. This style guide is a list
|
||
of <em>dos and don’ts</em> for Python programs.</p>
|
||
|
||
<p>To help you format code correctly, we’ve created a <a href="/styleguide/google_python_style.vim">settings file for Vim</a>. For Emacs, the default settings should be fine.</p>
|
||
|
||
<p>Many teams use the <a href="https://github.com/psf/black">Black</a> or <a href="https://github.com/google/pyink">Pyink</a>
|
||
auto-formatter to avoid arguing over formatting.</p>
|
||
|
||
<p><a id="s2-python-language-rules"></a>
|
||
<a id="2-python-language-rules"></a></p>
|
||
|
||
<p><a id="python-language-rules"></a></p>
|
||
<h2 id="2-python-language-rules">2 Python Language Rules</h2>
|
||
|
||
<p><a id="s2.1-lint"></a>
|
||
<a id="21-lint"></a></p>
|
||
|
||
<p><a id="lint"></a></p>
|
||
<h3 id="21-lint">2.1 Lint</h3>
|
||
|
||
<p>Run <code class="language-plaintext highlighter-rouge">pylint</code> over your code using this <a href="https://google.github.io/styleguide/pylintrc">pylintrc</a>.</p>
|
||
|
||
<p><a id="s2.1.1-definition"></a>
|
||
<a id="211-definition"></a></p>
|
||
|
||
<p><a id="lint-definition"></a></p>
|
||
<h4 id="211-definition">2.1.1 Definition</h4>
|
||
|
||
<p><code class="language-plaintext highlighter-rouge">pylint</code>
|
||
is a tool for finding bugs and style problems in Python source code. It finds
|
||
problems that are typically caught by a compiler for less dynamic languages like
|
||
C and C++. Because of the dynamic nature of Python, some
|
||
warnings may be incorrect; however, spurious warnings should be fairly
|
||
infrequent.</p>
|
||
|
||
<p><a id="s2.1.2-pros"></a>
|
||
<a id="212-pros"></a></p>
|
||
|
||
<p><a id="lint-pros"></a></p>
|
||
<h4 id="212-pros">2.1.2 Pros</h4>
|
||
|
||
<p>Catches easy-to-miss errors like typos, using-vars-before-assignment, etc.</p>
|
||
|
||
<p><a id="s2.1.3-cons"></a>
|
||
<a id="213-cons"></a></p>
|
||
|
||
<p><a id="lint-cons"></a></p>
|
||
<h4 id="213-cons">2.1.3 Cons</h4>
|
||
|
||
<p><code class="language-plaintext highlighter-rouge">pylint</code>
|
||
isn’t perfect. To take advantage of it, sometimes we’ll need to write around it,
|
||
suppress its warnings or fix it.</p>
|
||
|
||
<p><a id="s2.1.4-decision"></a>
|
||
<a id="214-decision"></a></p>
|
||
|
||
<p><a id="lint-decision"></a></p>
|
||
<h4 id="214-decision">2.1.4 Decision</h4>
|
||
|
||
<p>Make sure you run
|
||
<code class="language-plaintext highlighter-rouge">pylint</code>
|
||
on your code.</p>
|
||
|
||
<p>Suppress warnings if they are inappropriate so that other issues are not hidden.
|
||
To suppress warnings, you can set a line-level comment:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">do_PUT</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="c1"># WSGI name, so pylint: disable=invalid-name
|
||
</span> <span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><code class="language-plaintext highlighter-rouge">pylint</code>
|
||
warnings are each identified by symbolic name (<code class="language-plaintext highlighter-rouge">empty-docstring</code>)
|
||
Google-specific warnings start with <code class="language-plaintext highlighter-rouge">g-</code>.</p>
|
||
|
||
<p>If the reason for the suppression is not clear from the symbolic name, add an
|
||
explanation.</p>
|
||
|
||
<p>Suppressing in this way has the advantage that we can easily search for
|
||
suppressions and revisit them.</p>
|
||
|
||
<p>You can get a list of
|
||
<code class="language-plaintext highlighter-rouge">pylint</code>
|
||
warnings by doing:</p>
|
||
|
||
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pylint <span class="nt">--list-msgs</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>To get more information on a particular message, use:</p>
|
||
|
||
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pylint <span class="nt">--help-msg</span><span class="o">=</span>invalid-name
|
||
</code></pre></div></div>
|
||
|
||
<p>Prefer <code class="language-plaintext highlighter-rouge">pylint: disable</code> to the deprecated older form <code class="language-plaintext highlighter-rouge">pylint: disable-msg</code>.</p>
|
||
|
||
<p>Unused argument warnings can be suppressed by deleting the variables at the
|
||
beginning of the function. Always include a comment explaining why you are
|
||
deleting it. “Unused.” is sufficient. For example:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">viking_cafe_order</span><span class="p">(</span><span class="n">spam</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">beans</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">eggs</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="bp">None</span> <span class="o">=</span> <span class="bp">None</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
||
<span class="k">del</span> <span class="n">beans</span><span class="p">,</span> <span class="n">eggs</span> <span class="c1"># Unused by vikings.
|
||
</span> <span class="k">return</span> <span class="n">spam</span> <span class="o">+</span> <span class="n">spam</span> <span class="o">+</span> <span class="n">spam</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>Other common forms of suppressing this warning include using ‘<code class="language-plaintext highlighter-rouge">_</code>’ as the
|
||
identifier for the unused argument or prefixing the argument name with
|
||
‘<code class="language-plaintext highlighter-rouge">unused_</code>’, or assigning them to ‘<code class="language-plaintext highlighter-rouge">_</code>’. These forms are allowed but no longer
|
||
encouraged. These break callers that pass arguments by name and do not enforce
|
||
that the arguments are actually unused.</p>
|
||
|
||
<p><a id="s2.2-imports"></a>
|
||
<a id="22-imports"></a></p>
|
||
|
||
<p><a id="imports"></a></p>
|
||
<h3 id="22-imports">2.2 Imports</h3>
|
||
|
||
<p>Use <code class="language-plaintext highlighter-rouge">import</code> statements for packages and modules only, not for individual types,
|
||
classes, or functions.</p>
|
||
|
||
<p><a id="s2.2.1-definition"></a>
|
||
<a id="221-definition"></a></p>
|
||
|
||
<p><a id="imports-definition"></a></p>
|
||
<h4 id="221-definition">2.2.1 Definition</h4>
|
||
|
||
<p>Reusability mechanism for sharing code from one module to another.</p>
|
||
|
||
<p><a id="s2.2.2-pros"></a>
|
||
<a id="222-pros"></a></p>
|
||
|
||
<p><a id="imports-pros"></a></p>
|
||
<h4 id="222-pros">2.2.2 Pros</h4>
|
||
|
||
<p>The namespace management convention is simple. The source of each identifier is
|
||
indicated in a consistent way; <code class="language-plaintext highlighter-rouge">x.Obj</code> says that object <code class="language-plaintext highlighter-rouge">Obj</code> is defined in
|
||
module <code class="language-plaintext highlighter-rouge">x</code>.</p>
|
||
|
||
<p><a id="s2.2.3-cons"></a>
|
||
<a id="223-cons"></a></p>
|
||
|
||
<p><a id="imports-cons"></a></p>
|
||
<h4 id="223-cons">2.2.3 Cons</h4>
|
||
|
||
<p>Module names can still collide. Some module names are inconveniently long.</p>
|
||
|
||
<p><a id="s2.2.4-decision"></a>
|
||
<a id="224-decision"></a></p>
|
||
|
||
<p><a id="imports-decision"></a></p>
|
||
<h4 id="224-decision">2.2.4 Decision</h4>
|
||
|
||
<ul>
|
||
<li>Use <code class="language-plaintext highlighter-rouge">import x</code> for importing packages and modules.</li>
|
||
<li>Use <code class="language-plaintext highlighter-rouge">from x import y</code> where <code class="language-plaintext highlighter-rouge">x</code> is the package prefix and <code class="language-plaintext highlighter-rouge">y</code> is the module
|
||
name with no prefix.</li>
|
||
<li>Use <code class="language-plaintext highlighter-rouge">from x import y as z</code> in any of the following circumstances:
|
||
<ul>
|
||
<li>Two modules named <code class="language-plaintext highlighter-rouge">y</code> are to be imported.</li>
|
||
<li><code class="language-plaintext highlighter-rouge">y</code> conflicts with a top-level name defined in the current module.</li>
|
||
<li><code class="language-plaintext highlighter-rouge">y</code> conflicts with a common parameter name that is part of the public
|
||
API (e.g., <code class="language-plaintext highlighter-rouge">features</code>).</li>
|
||
<li><code class="language-plaintext highlighter-rouge">y</code> is an inconveniently long name.</li>
|
||
<li><code class="language-plaintext highlighter-rouge">y</code> is too generic in the context of your code (e.g., <code class="language-plaintext highlighter-rouge">from
|
||
storage.file_system import options as fs_options</code>).</li>
|
||
</ul>
|
||
</li>
|
||
<li>Use <code class="language-plaintext highlighter-rouge">import y as z</code> only when <code class="language-plaintext highlighter-rouge">z</code> is a standard abbreviation (e.g., <code class="language-plaintext highlighter-rouge">import
|
||
numpy as np</code>).</li>
|
||
</ul>
|
||
|
||
<p>For example the module <code class="language-plaintext highlighter-rouge">sound.effects.echo</code> may be imported as follows:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">sound.effects</span> <span class="kn">import</span> <span class="n">echo</span>
|
||
<span class="p">...</span>
|
||
<span class="n">echo</span><span class="p">.</span><span class="n">EchoFilter</span><span class="p">(</span><span class="nb">input</span><span class="p">,</span> <span class="n">output</span><span class="p">,</span> <span class="n">delay</span><span class="o">=</span><span class="mf">0.7</span><span class="p">,</span> <span class="n">atten</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>Do not use relative names in imports. Even if the module is in the same package,
|
||
use the full package name. This helps prevent unintentionally importing a
|
||
package twice.</p>
|
||
|
||
<p><a id="imports-exemptions"></a></p>
|
||
<h5 id="2241-exemptions">2.2.4.1 Exemptions</h5>
|
||
|
||
<p>Exemptions from this rule:</p>
|
||
|
||
<ul>
|
||
<li>Symbols from the following modules are used to support static analysis and
|
||
type checking:
|
||
<ul>
|
||
<li><a href="#typing-imports"><code class="language-plaintext highlighter-rouge">typing</code> module</a></li>
|
||
<li><a href="#typing-imports"><code class="language-plaintext highlighter-rouge">collections.abc</code> module</a></li>
|
||
<li><a href="https://github.com/python/typing_extensions/blob/main/README.md"><code class="language-plaintext highlighter-rouge">typing_extensions</code> module</a></li>
|
||
</ul>
|
||
</li>
|
||
<li>Redirects from the
|
||
<a href="https://six.readthedocs.io/#module-six.moves">six.moves module</a>.</li>
|
||
</ul>
|
||
|
||
<p><a id="s2.3-packages"></a>
|
||
<a id="23-packages"></a></p>
|
||
|
||
<p><a id="packages"></a></p>
|
||
<h3 id="23-packages">2.3 Packages</h3>
|
||
|
||
<p>Import each module using the full pathname location of the module.</p>
|
||
|
||
<p><a id="s2.3.1-pros"></a>
|
||
<a id="231-pros"></a></p>
|
||
|
||
<p><a id="packages-pros"></a></p>
|
||
<h4 id="231-pros">2.3.1 Pros</h4>
|
||
|
||
<p>Avoids conflicts in module names or incorrect imports due to the module search
|
||
path not being what the author expected. Makes it easier to find modules.</p>
|
||
|
||
<p><a id="s2.3.2-cons"></a>
|
||
<a id="232-cons"></a></p>
|
||
|
||
<p><a id="packages-cons"></a></p>
|
||
<h4 id="232-cons">2.3.2 Cons</h4>
|
||
|
||
<p>Makes it harder to deploy code because you have to replicate the package
|
||
hierarchy. Not really a problem with modern deployment mechanisms.</p>
|
||
|
||
<p><a id="s2.3.3-decision"></a>
|
||
<a id="233-decision"></a></p>
|
||
|
||
<p><a id="packages-decision"></a></p>
|
||
<h4 id="233-decision">2.3.3 Decision</h4>
|
||
|
||
<p>All new code should import each module by its full package name.</p>
|
||
|
||
<p>Imports should be as follows:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span>
|
||
<span class="c1"># Reference absl.flags in code with the complete name (verbose).
|
||
</span> <span class="kn">import</span> <span class="nn">absl.flags</span>
|
||
<span class="kn">from</span> <span class="nn">doctor.who</span> <span class="kn">import</span> <span class="n">jodie</span>
|
||
|
||
<span class="n">_FOO</span> <span class="o">=</span> <span class="n">absl</span><span class="p">.</span><span class="n">flags</span><span class="p">.</span><span class="n">DEFINE_string</span><span class="p">(...)</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span>
|
||
<span class="c1"># Reference flags in code with just the module name (common).
|
||
</span> <span class="kn">from</span> <span class="nn">absl</span> <span class="kn">import</span> <span class="n">flags</span>
|
||
<span class="kn">from</span> <span class="nn">doctor.who</span> <span class="kn">import</span> <span class="n">jodie</span>
|
||
|
||
<span class="n">_FOO</span> <span class="o">=</span> <span class="n">flags</span><span class="p">.</span><span class="n">DEFINE_string</span><span class="p">(...)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><em>(assume this file lives in <code class="language-plaintext highlighter-rouge">doctor/who/</code> where <code class="language-plaintext highlighter-rouge">jodie.py</code> also exists)</em></p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span>
|
||
<span class="c1"># Unclear what module the author wanted and what will be imported. The actual
|
||
</span> <span class="c1"># import behavior depends on external factors controlling sys.path.
|
||
</span> <span class="c1"># Which possible jodie module did the author intend to import?
|
||
</span> <span class="kn">import</span> <span class="nn">jodie</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>The directory the main binary is located in should not be assumed to be in
|
||
<code class="language-plaintext highlighter-rouge">sys.path</code> despite that happening in some environments. This being the case,
|
||
code should assume that <code class="language-plaintext highlighter-rouge">import jodie</code> refers to a third-party or top-level
|
||
package named <code class="language-plaintext highlighter-rouge">jodie</code>, not a local <code class="language-plaintext highlighter-rouge">jodie.py</code>.</p>
|
||
|
||
<p><a id="s2.4-exceptions"></a>
|
||
<a id="24-exceptions"></a></p>
|
||
|
||
<p><a id="exceptions"></a></p>
|
||
<h3 id="24-exceptions">2.4 Exceptions</h3>
|
||
|
||
<p>Exceptions are allowed but must be used carefully.</p>
|
||
|
||
<p><a id="s2.4.1-definition"></a>
|
||
<a id="241-definition"></a></p>
|
||
|
||
<p><a id="exceptions-definition"></a></p>
|
||
<h4 id="241-definition">2.4.1 Definition</h4>
|
||
|
||
<p>Exceptions are a means of breaking out of normal control flow to handle errors
|
||
or other exceptional conditions.</p>
|
||
|
||
<p><a id="s2.4.2-pros"></a>
|
||
<a id="242-pros"></a></p>
|
||
|
||
<p><a id="exceptions-pros"></a></p>
|
||
<h4 id="242-pros">2.4.2 Pros</h4>
|
||
|
||
<p>The control flow of normal operation code is not cluttered by error-handling
|
||
code. It also allows the control flow to skip multiple frames when a certain
|
||
condition occurs, e.g., returning from N nested functions in one step instead of
|
||
having to plumb error codes through.</p>
|
||
|
||
<p><a id="s2.4.3-cons"></a>
|
||
<a id="243-cons"></a></p>
|
||
|
||
<p><a id="exceptions-cons"></a></p>
|
||
<h4 id="243-cons">2.4.3 Cons</h4>
|
||
|
||
<p>May cause the control flow to be confusing. Easy to miss error cases when making
|
||
library calls.</p>
|
||
|
||
<p><a id="s2.4.4-decision"></a>
|
||
<a id="244-decision"></a></p>
|
||
|
||
<p><a id="exceptions-decision"></a></p>
|
||
<h4 id="244-decision">2.4.4 Decision</h4>
|
||
|
||
<p>Exceptions must follow certain conditions:</p>
|
||
|
||
<ul>
|
||
<li>
|
||
<p>Make use of built-in exception classes when it makes sense. For example,
|
||
raise a <code class="language-plaintext highlighter-rouge">ValueError</code> to indicate a programming mistake like a violated
|
||
precondition, such as may happen when validating function arguments.</p>
|
||
</li>
|
||
<li>
|
||
<p>Do not use <code class="language-plaintext highlighter-rouge">assert</code> statements in place of conditionals or validating
|
||
preconditions. They must not be critical to the application logic. A litmus
|
||
test would be that the <code class="language-plaintext highlighter-rouge">assert</code> could be removed without breaking the code.
|
||
<code class="language-plaintext highlighter-rouge">assert</code> conditionals are
|
||
<a href="https://docs.python.org/3/reference/simple_stmts.html#the-assert-statement">not guaranteed</a>
|
||
to be evaluated. For <a href="https://pytest.org">pytest</a> based tests, <code class="language-plaintext highlighter-rouge">assert</code> is
|
||
okay and expected to verify expectations. For
|
||
example:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">connect_to_next_port</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">minimum</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
|
||
<span class="s">"""Connects to the next available port.
|
||
|
||
Args:
|
||
minimum: A port value greater or equal to 1024.
|
||
|
||
Returns:
|
||
The new minimum port.
|
||
|
||
Raises:
|
||
ConnectionError: If no available port is found.
|
||
"""</span>
|
||
<span class="k">if</span> <span class="n">minimum</span> <span class="o"><</span> <span class="mi">1024</span><span class="p">:</span>
|
||
<span class="c1"># Note that this raising of ValueError is not mentioned in the doc
|
||
</span> <span class="c1"># string's "Raises:" section because it is not appropriate to
|
||
</span> <span class="c1"># guarantee this specific behavioral reaction to API misuse.
|
||
</span> <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s">'Min. port must be at least 1024, not </span><span class="si">{</span><span class="n">minimum</span><span class="si">}</span><span class="s">.'</span><span class="p">)</span>
|
||
<span class="n">port</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">_find_next_open_port</span><span class="p">(</span><span class="n">minimum</span><span class="p">)</span>
|
||
<span class="k">if</span> <span class="n">port</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
|
||
<span class="k">raise</span> <span class="nb">ConnectionError</span><span class="p">(</span>
|
||
<span class="sa">f</span><span class="s">'Could not connect to service on port </span><span class="si">{</span><span class="n">minimum</span><span class="si">}</span><span class="s"> or higher.'</span><span class="p">)</span>
|
||
<span class="c1"># The code does not depend on the result of this assert.
|
||
</span> <span class="k">assert</span> <span class="n">port</span> <span class="o">>=</span> <span class="n">minimum</span><span class="p">,</span> <span class="p">(</span>
|
||
<span class="sa">f</span><span class="s">'Unexpected port </span><span class="si">{</span><span class="n">port</span><span class="si">}</span><span class="s"> when minimum was </span><span class="si">{</span><span class="n">minimum</span><span class="si">}</span><span class="s">.'</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="n">port</span>
|
||
</code></pre></div> </div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">connect_to_next_port</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">minimum</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
|
||
<span class="s">"""Connects to the next available port.
|
||
|
||
Args:
|
||
minimum: A port value greater or equal to 1024.
|
||
|
||
Returns:
|
||
The new minimum port.
|
||
"""</span>
|
||
<span class="k">assert</span> <span class="n">minimum</span> <span class="o">>=</span> <span class="mi">1024</span><span class="p">,</span> <span class="s">'Minimum port must be at least 1024.'</span>
|
||
<span class="c1"># The following code depends on the previous assert.
|
||
</span> <span class="n">port</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">_find_next_open_port</span><span class="p">(</span><span class="n">minimum</span><span class="p">)</span>
|
||
<span class="k">assert</span> <span class="n">port</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span>
|
||
<span class="c1"># The type checking of the return statement relies on the assert.
|
||
</span> <span class="k">return</span> <span class="n">port</span>
|
||
</code></pre></div> </div>
|
||
</li>
|
||
<li>
|
||
<p>Libraries or packages may define their own exceptions. When doing so they
|
||
must inherit from an existing exception class. Exception names should end in
|
||
<code class="language-plaintext highlighter-rouge">Error</code> and should not introduce repetition (<code class="language-plaintext highlighter-rouge">foo.FooError</code>).</p>
|
||
</li>
|
||
<li>
|
||
<p>Never use catch-all <code class="language-plaintext highlighter-rouge">except:</code> statements, or catch <code class="language-plaintext highlighter-rouge">Exception</code> or
|
||
<code class="language-plaintext highlighter-rouge">StandardError</code>, unless you are</p>
|
||
|
||
<ul>
|
||
<li>re-raising the exception, or</li>
|
||
<li>creating an isolation point in the program where exceptions are not
|
||
propagated but are recorded and suppressed instead, such as protecting a
|
||
thread from crashing by guarding its outermost block.</li>
|
||
</ul>
|
||
|
||
<p>Python is very tolerant in this regard and <code class="language-plaintext highlighter-rouge">except:</code> will really catch
|
||
everything including misspelled names, sys.exit() calls, Ctrl+C interrupts,
|
||
unittest failures and all kinds of other exceptions that you simply don’t
|
||
want to catch.</p>
|
||
</li>
|
||
<li>
|
||
<p>Minimize the amount of code in a <code class="language-plaintext highlighter-rouge">try</code>/<code class="language-plaintext highlighter-rouge">except</code> block. The larger the body
|
||
of the <code class="language-plaintext highlighter-rouge">try</code>, the more likely that an exception will be raised by a line of
|
||
code that you didn’t expect to raise an exception. In those cases, the
|
||
<code class="language-plaintext highlighter-rouge">try</code>/<code class="language-plaintext highlighter-rouge">except</code> block hides a real error.</p>
|
||
</li>
|
||
<li>
|
||
<p>Use the <code class="language-plaintext highlighter-rouge">finally</code> clause to execute code whether or not an exception is
|
||
raised in the <code class="language-plaintext highlighter-rouge">try</code> block. This is often useful for cleanup, i.e., closing a
|
||
file.</p>
|
||
</li>
|
||
</ul>
|
||
|
||
<p><a id="s2.5-global-variables"></a>
|
||
<a id="25-global-variables"></a>
|
||
<a id="s2.5-global-state"></a>
|
||
<a id="25-global-state"></a></p>
|
||
|
||
<p><a id="global-variables"></a></p>
|
||
<h3 id="25-mutable-global-state">2.5 Mutable Global State</h3>
|
||
|
||
<p>Avoid mutable global state.</p>
|
||
|
||
<p><a id="s2.5.1-definition"></a>
|
||
<a id="251-definition"></a></p>
|
||
|
||
<p><a id="global-variables-definition"></a></p>
|
||
<h4 id="251-definition">2.5.1 Definition</h4>
|
||
|
||
<p>Module-level values or class attributes that can get mutated during program
|
||
execution.</p>
|
||
|
||
<p><a id="s2.5.2-pros"></a>
|
||
<a id="252-pros"></a></p>
|
||
|
||
<p><a id="global-variables-pros"></a></p>
|
||
<h4 id="252-pros">2.5.2 Pros</h4>
|
||
|
||
<p>Occasionally useful.</p>
|
||
|
||
<p><a id="s2.5.3-cons"></a>
|
||
<a id="253-cons"></a></p>
|
||
|
||
<p><a id="global-variables-cons"></a></p>
|
||
<h4 id="253-cons">2.5.3 Cons</h4>
|
||
|
||
<ul>
|
||
<li>
|
||
<p>Breaks encapsulation: Such design can make it hard to achieve valid
|
||
objectives. For example, if global state is used to manage a database
|
||
connection, then connecting to two different databases at the same time
|
||
(such as for computing differences during a migration) becomes difficult.
|
||
Similar problems easily arise with global registries.</p>
|
||
</li>
|
||
<li>
|
||
<p>Has the potential to change module behavior during the import, because
|
||
assignments to global variables are done when the module is first imported.</p>
|
||
</li>
|
||
</ul>
|
||
|
||
<p><a id="s2.5.4-decision"></a>
|
||
<a id="254-decision"></a></p>
|
||
|
||
<p><a id="global-variables-decision"></a></p>
|
||
<h4 id="254-decision">2.5.4 Decision</h4>
|
||
|
||
<p>Avoid mutable global state.</p>
|
||
|
||
<p>In those rare cases where using global state is warranted, mutable global
|
||
entities should be declared at the module level or as a class attribute and made
|
||
internal by prepending an <code class="language-plaintext highlighter-rouge">_</code> to the name. If necessary, external access to
|
||
mutable global state must be done through public functions or class methods. See
|
||
<a href="#s3.16-naming">Naming</a> below. Please explain the design reasons why mutable
|
||
global state is being used in a comment or a doc linked to from a comment.</p>
|
||
|
||
<p>Module-level constants are permitted and encouraged. For example:
|
||
<code class="language-plaintext highlighter-rouge">_MAX_HOLY_HANDGRENADE_COUNT = 3</code> for an internal use constant or
|
||
<code class="language-plaintext highlighter-rouge">SIR_LANCELOTS_FAVORITE_COLOR = "blue"</code> for a public API constant. Constants
|
||
must be named using all caps with underscores. See <a href="#s3.16-naming">Naming</a>
|
||
below.</p>
|
||
|
||
<p><a id="s2.6-nested"></a>
|
||
<a id="26-nested"></a></p>
|
||
|
||
<p><a id="nested-classes-functions"></a></p>
|
||
<h3 id="26-nestedlocalinner-classes-and-functions">2.6 Nested/Local/Inner Classes and Functions</h3>
|
||
|
||
<p>Nested local functions or classes are fine when used to close over a local
|
||
variable. Inner classes are fine.</p>
|
||
|
||
<p><a id="s2.6.1-definition"></a>
|
||
<a id="261-definition"></a></p>
|
||
|
||
<p><a id="nested-classes-functions-definition"></a></p>
|
||
<h4 id="261-definition">2.6.1 Definition</h4>
|
||
|
||
<p>A class can be defined inside of a method, function, or class. A function can be
|
||
defined inside a method or function. Nested functions have read-only access to
|
||
variables defined in enclosing scopes.</p>
|
||
|
||
<p><a id="s2.6.2-pros"></a>
|
||
<a id="262-pros"></a></p>
|
||
|
||
<p><a id="nested-classes-functions-pros"></a></p>
|
||
<h4 id="262-pros">2.6.2 Pros</h4>
|
||
|
||
<p>Allows definition of utility classes and functions that are only used inside of
|
||
a very limited scope. Very
|
||
<a href="https://en.wikipedia.org/wiki/Abstract_data_type">ADT</a>-y. Commonly used for
|
||
implementing decorators.</p>
|
||
|
||
<p><a id="s2.6.3-cons"></a>
|
||
<a id="263-cons"></a></p>
|
||
|
||
<p><a id="nested-classes-functions-cons"></a></p>
|
||
<h4 id="263-cons">2.6.3 Cons</h4>
|
||
|
||
<p>Nested functions and classes cannot be directly tested. Nesting can make the
|
||
outer function longer and less readable.</p>
|
||
|
||
<p><a id="s2.6.4-decision"></a>
|
||
<a id="264-decision"></a></p>
|
||
|
||
<p><a id="nested-classes-functions-decision"></a></p>
|
||
<h4 id="264-decision">2.6.4 Decision</h4>
|
||
|
||
<p>They are fine with some caveats. Avoid nested functions or classes except when
|
||
closing over a local value other than <code class="language-plaintext highlighter-rouge">self</code> or <code class="language-plaintext highlighter-rouge">cls</code>. Do not nest a function
|
||
just to hide it from users of a module. Instead, prefix its name with an _ at
|
||
the module level so that it can still be accessed by tests.</p>
|
||
|
||
<p><a id="s2.7-comprehensions"></a>
|
||
<a id="s2.7-list_comprehensions"></a>
|
||
<a id="27-list_comprehensions"></a>
|
||
<a id="list_comprehensions"></a>
|
||
<a id="list-comprehensions"></a></p>
|
||
|
||
<p><a id="comprehensions"></a></p>
|
||
<h3 id="27-comprehensions--generator-expressions">2.7 Comprehensions & Generator Expressions</h3>
|
||
|
||
<p>Okay to use for simple cases.</p>
|
||
|
||
<p><a id="s2.7.1-definition"></a>
|
||
<a id="271-definition"></a></p>
|
||
|
||
<p><a id="comprehensions-definition"></a></p>
|
||
<h4 id="271-definition">2.7.1 Definition</h4>
|
||
|
||
<p>List, Dict, and Set comprehensions as well as generator expressions provide a
|
||
concise and efficient way to create container types and iterators without
|
||
resorting to the use of traditional loops, <code class="language-plaintext highlighter-rouge">map()</code>, <code class="language-plaintext highlighter-rouge">filter()</code>, or <code class="language-plaintext highlighter-rouge">lambda</code>.</p>
|
||
|
||
<p><a id="s2.7.2-pros"></a>
|
||
<a id="272-pros"></a></p>
|
||
|
||
<p><a id="comprehensions-pros"></a></p>
|
||
<h4 id="272-pros">2.7.2 Pros</h4>
|
||
|
||
<p>Simple comprehensions can be clearer and simpler than other dict, list, or set
|
||
creation techniques. Generator expressions can be very efficient, since they
|
||
avoid the creation of a list entirely.</p>
|
||
|
||
<p><a id="s2.7.3-cons"></a>
|
||
<a id="273-cons"></a></p>
|
||
|
||
<p><a id="comprehensions-cons"></a></p>
|
||
<h4 id="273-cons">2.7.3 Cons</h4>
|
||
|
||
<p>Complicated comprehensions or generator expressions can be hard to read.</p>
|
||
|
||
<p><a id="s2.7.4-decision"></a>
|
||
<a id="274-decision"></a></p>
|
||
|
||
<p><a id="comprehensions-decision"></a></p>
|
||
<h4 id="274-decision">2.7.4 Decision</h4>
|
||
|
||
<p>Comprehensions are allowed, however multiple <code class="language-plaintext highlighter-rouge">for</code> clauses or filter expressions
|
||
are not permitted. Optimize for readability, not conciseness.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span>
|
||
<span class="n">result</span> <span class="o">=</span> <span class="p">[</span><span class="n">mapping_expr</span> <span class="k">for</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">iterable</span> <span class="k">if</span> <span class="n">filter_expr</span><span class="p">]</span>
|
||
|
||
<span class="n">result</span> <span class="o">=</span> <span class="p">[</span>
|
||
<span class="n">is_valid</span><span class="p">(</span><span class="n">metric</span><span class="o">=</span><span class="p">{</span><span class="s">'key'</span><span class="p">:</span> <span class="n">value</span><span class="p">})</span>
|
||
<span class="k">for</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">interesting_iterable</span>
|
||
<span class="k">if</span> <span class="n">a_longer_filter_expression</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
|
||
<span class="p">]</span>
|
||
|
||
<span class="n">descriptive_name</span> <span class="o">=</span> <span class="p">[</span>
|
||
<span class="n">transform</span><span class="p">({</span><span class="s">'key'</span><span class="p">:</span> <span class="n">key</span><span class="p">,</span> <span class="s">'value'</span><span class="p">:</span> <span class="n">value</span><span class="p">},</span> <span class="n">color</span><span class="o">=</span><span class="s">'black'</span><span class="p">)</span>
|
||
<span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">generate_iterable</span><span class="p">(</span><span class="n">some_input</span><span class="p">)</span>
|
||
<span class="k">if</span> <span class="n">complicated_condition_is_met</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
|
||
<span class="p">]</span>
|
||
|
||
<span class="n">result</span> <span class="o">=</span> <span class="p">[]</span>
|
||
<span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>
|
||
<span class="k">for</span> <span class="n">y</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
|
||
<span class="k">if</span> <span class="n">x</span> <span class="o">*</span> <span class="n">y</span> <span class="o">></span> <span class="mi">10</span><span class="p">:</span>
|
||
<span class="n">result</span><span class="p">.</span><span class="n">append</span><span class="p">((</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">))</span>
|
||
|
||
<span class="k">return</span> <span class="p">{</span>
|
||
<span class="n">x</span><span class="p">:</span> <span class="n">complicated_transform</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
|
||
<span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">long_generator_function</span><span class="p">(</span><span class="n">parameter</span><span class="p">)</span>
|
||
<span class="k">if</span> <span class="n">x</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="k">return</span> <span class="p">(</span><span class="n">x</span><span class="o">**</span><span class="mi">2</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span>
|
||
|
||
<span class="n">unique_names</span> <span class="o">=</span> <span class="p">{</span><span class="n">user</span><span class="p">.</span><span class="n">name</span> <span class="k">for</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">users</span> <span class="k">if</span> <span class="n">user</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">}</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span>
|
||
<span class="n">result</span> <span class="o">=</span> <span class="p">[(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="k">for</span> <span class="n">y</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> <span class="k">if</span> <span class="n">x</span> <span class="o">*</span> <span class="n">y</span> <span class="o">></span> <span class="mi">10</span><span class="p">]</span>
|
||
|
||
<span class="k">return</span> <span class="p">(</span>
|
||
<span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">)</span>
|
||
<span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
|
||
<span class="k">for</span> <span class="n">y</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
|
||
<span class="k">if</span> <span class="n">x</span> <span class="o">!=</span> <span class="n">y</span>
|
||
<span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
|
||
<span class="k">if</span> <span class="n">y</span> <span class="o">!=</span> <span class="n">z</span>
|
||
<span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s2.8-default-iterators-and-operators"></a></p>
|
||
|
||
<p><a id="default-iterators-operators"></a></p>
|
||
<h3 id="28-default-iterators-and-operators">2.8 Default Iterators and Operators</h3>
|
||
|
||
<p>Use default iterators and operators for types that support them, like lists,
|
||
dictionaries, and files.</p>
|
||
|
||
<p><a id="s2.8.1-definition"></a>
|
||
<a id="281-definition"></a></p>
|
||
|
||
<p><a id="default-iterators-operators-definition"></a></p>
|
||
<h4 id="281-definition">2.8.1 Definition</h4>
|
||
|
||
<p>Container types, like dictionaries and lists, define default iterators and
|
||
membership test operators (“in” and “not in”).</p>
|
||
|
||
<p><a id="s2.8.2-pros"></a>
|
||
<a id="282-pros"></a></p>
|
||
|
||
<p><a id="default-iterators-operators-pros"></a></p>
|
||
<h4 id="282-pros">2.8.2 Pros</h4>
|
||
|
||
<p>The default iterators and operators are simple and efficient. They express the
|
||
operation directly, without extra method calls. A function that uses default
|
||
operators is generic. It can be used with any type that supports the operation.</p>
|
||
|
||
<p><a id="s2.8.3-cons"></a>
|
||
<a id="283-cons"></a></p>
|
||
|
||
<p><a id="default-iterators-operators-cons"></a></p>
|
||
<h4 id="283-cons">2.8.3 Cons</h4>
|
||
|
||
<p>You can’t tell the type of objects by reading the method names (unless the
|
||
variable has type annotations). This is also an advantage.</p>
|
||
|
||
<p><a id="s2.8.4-decision"></a>
|
||
<a id="284-decision"></a></p>
|
||
|
||
<p><a id="default-iterators-operators-decision"></a></p>
|
||
<h4 id="284-decision">2.8.4 Decision</h4>
|
||
|
||
<p>Use default iterators and operators for types that support them, like lists,
|
||
dictionaries, and files. The built-in types define iterator methods, too. Prefer
|
||
these methods to methods that return lists, except that you should not mutate a
|
||
container while iterating over it.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span> <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">adict</span><span class="p">:</span> <span class="p">...</span>
|
||
<span class="k">if</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">alist</span><span class="p">:</span> <span class="p">...</span>
|
||
<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">afile</span><span class="p">:</span> <span class="p">...</span>
|
||
<span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">adict</span><span class="p">.</span><span class="n">items</span><span class="p">():</span> <span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span> <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">adict</span><span class="p">.</span><span class="n">keys</span><span class="p">():</span> <span class="p">...</span>
|
||
<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">afile</span><span class="p">.</span><span class="n">readlines</span><span class="p">():</span> <span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s2.9-generators"></a>
|
||
<a id="29-generators"></a></p>
|
||
|
||
<p><a id="generators"></a></p>
|
||
<h3 id="29-generators">2.9 Generators</h3>
|
||
|
||
<p>Use generators as needed.</p>
|
||
|
||
<p><a id="s2.9.1-definition"></a>
|
||
<a id="291-definition"></a></p>
|
||
|
||
<p><a id="generators-definition"></a></p>
|
||
<h4 id="291-definition">2.9.1 Definition</h4>
|
||
|
||
<p>A generator function returns an iterator that yields a value each time it
|
||
executes a yield statement. After it yields a value, the runtime state of the
|
||
generator function is suspended until the next value is needed.</p>
|
||
|
||
<p><a id="s2.9.2-pros"></a>
|
||
<a id="292-pros"></a></p>
|
||
|
||
<p><a id="generators-pros"></a></p>
|
||
<h4 id="292-pros">2.9.2 Pros</h4>
|
||
|
||
<p>Simpler code, because the state of local variables and control flow are
|
||
preserved for each call. A generator uses less memory than a function that
|
||
creates an entire list of values at once.</p>
|
||
|
||
<p><a id="s2.9.3-cons"></a>
|
||
<a id="293-cons"></a></p>
|
||
|
||
<p><a id="generators-cons"></a></p>
|
||
<h4 id="293-cons">2.9.3 Cons</h4>
|
||
|
||
<p>Local variables in the generator will not be garbage collected until the
|
||
generator is either consumed to exhaustion or itself garbage collected.</p>
|
||
|
||
<p><a id="s2.9.4-decision"></a>
|
||
<a id="294-decision"></a></p>
|
||
|
||
<p><a id="generators-decision"></a></p>
|
||
<h4 id="294-decision">2.9.4 Decision</h4>
|
||
|
||
<p>Fine. Use “Yields:” rather than “Returns:” in the docstring for generator
|
||
functions.</p>
|
||
|
||
<p>If the generator manages an expensive resource, make sure to force the clean up.</p>
|
||
|
||
<p>A good way to do the clean up is by wrapping the generator with a context
|
||
manager <a href="https://peps.python.org/pep-0533/">PEP-0533</a>.</p>
|
||
|
||
<p><a id="s2.10-lambda-functions"></a>
|
||
<a id="210-lambda-functions"></a></p>
|
||
|
||
<p><a id="lambdas"></a></p>
|
||
<h3 id="210-lambda-functions">2.10 Lambda Functions</h3>
|
||
|
||
<p>Okay for one-liners. Prefer generator expressions over <code class="language-plaintext highlighter-rouge">map()</code> or <code class="language-plaintext highlighter-rouge">filter()</code>
|
||
with a <code class="language-plaintext highlighter-rouge">lambda</code>.</p>
|
||
|
||
<p><a id="s2.10.1-definition"></a>
|
||
<a id="2101-definition"></a></p>
|
||
|
||
<p><a id="lambdas-definition"></a></p>
|
||
<h4 id="2101-definition">2.10.1 Definition</h4>
|
||
|
||
<p>Lambdas define anonymous functions in an expression, as opposed to a statement.</p>
|
||
|
||
<p><a id="s2.10.2-pros"></a>
|
||
<a id="2102-pros"></a></p>
|
||
|
||
<p><a id="lambdas-pros"></a></p>
|
||
<h4 id="2102-pros">2.10.2 Pros</h4>
|
||
|
||
<p>Convenient.</p>
|
||
|
||
<p><a id="s2.10.3-cons"></a>
|
||
<a id="2103-cons"></a></p>
|
||
|
||
<p><a id="lambdas-cons"></a></p>
|
||
<h4 id="2103-cons">2.10.3 Cons</h4>
|
||
|
||
<p>Harder to read and debug than local functions. The lack of names means stack
|
||
traces are more difficult to understand. Expressiveness is limited because the
|
||
function may only contain an expression.</p>
|
||
|
||
<p><a id="s2.10.4-decision"></a>
|
||
<a id="2104-decision"></a></p>
|
||
|
||
<p><a id="lambdas-decision"></a></p>
|
||
<h4 id="2104-decision">2.10.4 Decision</h4>
|
||
|
||
<p>Lambdas are allowed. If the code inside the lambda function spans multiple lines
|
||
or is longer than 60-80 chars, it might be better to define it as a regular
|
||
<a href="#lexical-scoping">nested function</a>.</p>
|
||
|
||
<p>For common operations like multiplication, use the functions from the <code class="language-plaintext highlighter-rouge">operator</code>
|
||
module instead of lambda functions. For example, prefer <code class="language-plaintext highlighter-rouge">operator.mul</code> to
|
||
<code class="language-plaintext highlighter-rouge">lambda x, y: x * y</code>.</p>
|
||
|
||
<p><a id="s2.11-conditional-expressions"></a>
|
||
<a id="211-conditional-expressions"></a></p>
|
||
|
||
<p><a id="conditional-expressions"></a></p>
|
||
<h3 id="211-conditional-expressions">2.11 Conditional Expressions</h3>
|
||
|
||
<p>Okay for simple cases.</p>
|
||
|
||
<p><a id="s2.11.1-definition"></a>
|
||
<a id="2111-definition"></a></p>
|
||
|
||
<p><a id="conditional-expressions-definition"></a></p>
|
||
<h4 id="2111-definition">2.11.1 Definition</h4>
|
||
|
||
<p>Conditional expressions (sometimes called a “ternary operator”) are mechanisms
|
||
that provide a shorter syntax for if statements. For example: <code class="language-plaintext highlighter-rouge">x = 1 if cond
|
||
else 2</code>.</p>
|
||
|
||
<p><a id="s2.11.2-pros"></a>
|
||
<a id="2112-pros"></a></p>
|
||
|
||
<p><a id="conditional-expressions-pros"></a></p>
|
||
<h4 id="2112-pros">2.11.2 Pros</h4>
|
||
|
||
<p>Shorter and more convenient than an if statement.</p>
|
||
|
||
<p><a id="s2.11.3-cons"></a>
|
||
<a id="2113-cons"></a></p>
|
||
|
||
<p><a id="conditional-expressions-cons"></a></p>
|
||
<h4 id="2113-cons">2.11.3 Cons</h4>
|
||
|
||
<p>May be harder to read than an if statement. The condition may be difficult to
|
||
locate if the expression is long.</p>
|
||
|
||
<p><a id="s2.11.4-decision"></a>
|
||
<a id="2114-decision"></a></p>
|
||
|
||
<p><a id="conditional-expressions-decision"></a></p>
|
||
<h4 id="2114-decision">2.11.4 Decision</h4>
|
||
|
||
<p>Okay to use for simple cases. Each portion must fit on one line:
|
||
true-expression, if-expression, else-expression. Use a complete if statement
|
||
when things get more complicated.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span>
|
||
<span class="n">one_line</span> <span class="o">=</span> <span class="s">'yes'</span> <span class="k">if</span> <span class="n">predicate</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="k">else</span> <span class="s">'no'</span>
|
||
<span class="n">slightly_split</span> <span class="o">=</span> <span class="p">(</span><span class="s">'yes'</span> <span class="k">if</span> <span class="n">predicate</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
|
||
<span class="k">else</span> <span class="s">'no, nein, nyet'</span><span class="p">)</span>
|
||
<span class="n">the_longest_ternary_style_that_can_be_done</span> <span class="o">=</span> <span class="p">(</span>
|
||
<span class="s">'yes, true, affirmative, confirmed, correct'</span>
|
||
<span class="k">if</span> <span class="n">predicate</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
|
||
<span class="k">else</span> <span class="s">'no, false, negative, nay'</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span>
|
||
<span class="n">bad_line_breaking</span> <span class="o">=</span> <span class="p">(</span><span class="s">'yes'</span> <span class="k">if</span> <span class="n">predicate</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="k">else</span>
|
||
<span class="s">'no'</span><span class="p">)</span>
|
||
<span class="n">portion_too_long</span> <span class="o">=</span> <span class="p">(</span><span class="s">'yes'</span>
|
||
<span class="k">if</span> <span class="n">some_long_module</span><span class="p">.</span><span class="n">some_long_predicate_function</span><span class="p">(</span>
|
||
<span class="n">really_long_variable_name</span><span class="p">)</span>
|
||
<span class="k">else</span> <span class="s">'no, false, negative, nay'</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s2.12-default-argument-values"></a>
|
||
<a id="212-default-argument-values"></a></p>
|
||
|
||
<p><a id="default-arguments"></a></p>
|
||
<h3 id="212-default-argument-values">2.12 Default Argument Values</h3>
|
||
|
||
<p>Okay in most cases.</p>
|
||
|
||
<p><a id="s2.12.1-definition"></a>
|
||
<a id="2121-definition"></a></p>
|
||
|
||
<p><a id="default-arguments-definition"></a></p>
|
||
<h4 id="2121-definition">2.12.1 Definition</h4>
|
||
|
||
<p>You can specify values for variables at the end of a function’s parameter list,
|
||
e.g., <code class="language-plaintext highlighter-rouge">def foo(a, b=0):</code>. If <code class="language-plaintext highlighter-rouge">foo</code> is called with only one argument, <code class="language-plaintext highlighter-rouge">b</code> is set
|
||
to 0. If it is called with two arguments, <code class="language-plaintext highlighter-rouge">b</code> has the value of the second
|
||
argument.</p>
|
||
|
||
<p><a id="s2.12.2-pros"></a>
|
||
<a id="2122-pros"></a></p>
|
||
|
||
<p><a id="default-arguments-pros"></a></p>
|
||
<h4 id="2122-pros">2.12.2 Pros</h4>
|
||
|
||
<p>Often you have a function that uses lots of default values, but on rare
|
||
occasions you want to override the defaults. Default argument values provide an
|
||
easy way to do this, without having to define lots of functions for the rare
|
||
exceptions. As Python does not support overloaded methods/functions, default
|
||
arguments are an easy way of “faking” the overloading behavior.</p>
|
||
|
||
<p><a id="s2.12.3-cons"></a>
|
||
<a id="2123-cons"></a></p>
|
||
|
||
<p><a id="default-arguments-cons"></a></p>
|
||
<h4 id="2123-cons">2.12.3 Cons</h4>
|
||
|
||
<p>Default arguments are evaluated once at module load time. This may cause
|
||
problems if the argument is a mutable object such as a list or a dictionary. If
|
||
the function modifies the object (e.g., by appending an item to a list), the
|
||
default value is modified.</p>
|
||
|
||
<p><a id="s2.12.4-decision"></a>
|
||
<a id="2124-decision"></a></p>
|
||
|
||
<p><a id="default-arguments-decision"></a></p>
|
||
<h4 id="2124-decision">2.12.4 Decision</h4>
|
||
|
||
<p>Okay to use with the following caveat:</p>
|
||
|
||
<p>Do not use mutable objects as default values in the function or method
|
||
definition.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span> <span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
|
||
<span class="k">if</span> <span class="n">b</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
|
||
<span class="n">b</span> <span class="o">=</span> <span class="p">[]</span>
|
||
<span class="n">Yes</span><span class="p">:</span> <span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="n">Sequence</span> <span class="o">|</span> <span class="bp">None</span> <span class="o">=</span> <span class="bp">None</span><span class="p">):</span>
|
||
<span class="k">if</span> <span class="n">b</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
|
||
<span class="n">b</span> <span class="o">=</span> <span class="p">[]</span>
|
||
<span class="n">Yes</span><span class="p">:</span> <span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="n">Sequence</span> <span class="o">=</span> <span class="p">()):</span> <span class="c1"># Empty tuple OK since tuples are immutable.
|
||
</span> <span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">absl</span> <span class="kn">import</span> <span class="n">flags</span>
|
||
<span class="n">_FOO</span> <span class="o">=</span> <span class="n">flags</span><span class="p">.</span><span class="n">DEFINE_string</span><span class="p">(...)</span>
|
||
|
||
<span class="n">No</span><span class="p">:</span> <span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="o">=</span><span class="p">[]):</span>
|
||
<span class="p">...</span>
|
||
<span class="n">No</span><span class="p">:</span> <span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="o">=</span><span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()):</span> <span class="c1"># Is `b` supposed to represent when this module was loaded?
|
||
</span> <span class="p">...</span>
|
||
<span class="n">No</span><span class="p">:</span> <span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="o">=</span><span class="n">_FOO</span><span class="p">.</span><span class="n">value</span><span class="p">):</span> <span class="c1"># sys.argv has not yet been parsed...
|
||
</span> <span class="p">...</span>
|
||
<span class="n">No</span><span class="p">:</span> <span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="n">Mapping</span> <span class="o">=</span> <span class="p">{}):</span> <span class="c1"># Could still get passed to unchecked code.
|
||
</span> <span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s2.13-properties"></a>
|
||
<a id="213-properties"></a></p>
|
||
|
||
<p><a id="properties"></a></p>
|
||
<h3 id="213-properties">2.13 Properties</h3>
|
||
|
||
<p>Properties may be used to control getting or setting attributes that require
|
||
trivial computations or logic. Property implementations must match the general
|
||
expectations of regular attribute access: that they are cheap, straightforward,
|
||
and unsurprising.</p>
|
||
|
||
<p><a id="s2.13.1-definition"></a>
|
||
<a id="2131-definition"></a></p>
|
||
|
||
<p><a id="properties-definition"></a></p>
|
||
<h4 id="2131-definition">2.13.1 Definition</h4>
|
||
|
||
<p>A way to wrap method calls for getting and setting an attribute as a standard
|
||
attribute access.</p>
|
||
|
||
<p><a id="s2.13.2-pros"></a>
|
||
<a id="2132-pros"></a></p>
|
||
|
||
<p><a id="properties-pros"></a></p>
|
||
<h4 id="2132-pros">2.13.2 Pros</h4>
|
||
|
||
<ul>
|
||
<li>Allows for an attribute access and assignment API rather than
|
||
<a href="#getters-and-setters">getter and setter</a> method calls.</li>
|
||
<li>Can be used to make an attribute read-only.</li>
|
||
<li>Allows calculations to be lazy.</li>
|
||
<li>Provides a way to maintain the public interface of a class when the
|
||
internals evolve independently of class users.</li>
|
||
</ul>
|
||
|
||
<p><a id="s2.13.3-cons"></a>
|
||
<a id="2133-cons"></a></p>
|
||
|
||
<p><a id="properties-cons"></a></p>
|
||
<h4 id="2133-cons">2.13.3 Cons</h4>
|
||
|
||
<ul>
|
||
<li>Can hide side-effects much like operator overloading.</li>
|
||
<li>Can be confusing for subclasses.</li>
|
||
</ul>
|
||
|
||
<p><a id="s2.13.4-decision"></a>
|
||
<a id="2134-decision"></a></p>
|
||
|
||
<p><a id="properties-decision"></a></p>
|
||
<h4 id="2134-decision">2.13.4 Decision</h4>
|
||
|
||
<p>Properties are allowed, but, like operator overloading, should only be used when
|
||
necessary and match the expectations of typical attribute access; follow the
|
||
<a href="#getters-and-setters">getters and setters</a> rules otherwise.</p>
|
||
|
||
<p>For example, using a property to simply both get and set an internal attribute
|
||
isn’t allowed: there is no computation occurring, so the property is unnecessary
|
||
(<a href="#getters-and-setters">make the attribute public instead</a>). In comparison,
|
||
using a property to control attribute access or to calculate a <em>trivially</em>
|
||
derived value is allowed: the logic is simple and unsurprising.</p>
|
||
|
||
<p>Properties should be created with the <code class="language-plaintext highlighter-rouge">@property</code>
|
||
<a href="#s2.17-function-and-method-decorators">decorator</a>. Manually implementing a
|
||
property descriptor is considered a <a href="#power-features">power feature</a>.</p>
|
||
|
||
<p>Inheritance with properties can be non-obvious. Do not use properties to
|
||
implement computations a subclass may ever want to override and extend.</p>
|
||
|
||
<p><a id="s2.14-truefalse-evaluations"></a>
|
||
<a id="214-truefalse-evaluations"></a></p>
|
||
|
||
<p><a id="truefalse-evaluations"></a></p>
|
||
<h3 id="214-truefalse-evaluations">2.14 True/False Evaluations</h3>
|
||
|
||
<p>Use the “implicit” false if at all possible (with a few caveats).</p>
|
||
|
||
<p><a id="s2.14.1-definition"></a>
|
||
<a id="2141-definition"></a></p>
|
||
|
||
<p><a id="truefalse-evaluations-definition"></a></p>
|
||
<h4 id="2141-definition">2.14.1 Definition</h4>
|
||
|
||
<p>Python evaluates certain values as <code class="language-plaintext highlighter-rouge">False</code> when in a boolean context. A quick
|
||
“rule of thumb” is that all “empty” values are considered false, so <code class="language-plaintext highlighter-rouge">0, None,
|
||
[], {}, ''</code> all evaluate as false in a boolean context.</p>
|
||
|
||
<p><a id="s2.14.2-pros"></a>
|
||
<a id="2142-pros"></a></p>
|
||
|
||
<p><a id="truefalse-evaluations-pros"></a></p>
|
||
<h4 id="2142-pros">2.14.2 Pros</h4>
|
||
|
||
<p>Conditions using Python booleans are easier to read and less error-prone. In
|
||
most cases, they’re also faster.</p>
|
||
|
||
<p><a id="s2.14.3-cons"></a>
|
||
<a id="2143-cons"></a></p>
|
||
|
||
<p><a id="truefalse-evaluations-cons"></a></p>
|
||
<h4 id="2143-cons">2.14.3 Cons</h4>
|
||
|
||
<p>May look strange to C/C++ developers.</p>
|
||
|
||
<p><a id="s2.14.4-decision"></a>
|
||
<a id="2144-decision"></a></p>
|
||
|
||
<p><a id="truefalse-evaluations-decision"></a></p>
|
||
<h4 id="2144-decision">2.14.4 Decision</h4>
|
||
|
||
<p>Use the “implicit” false if possible, e.g., <code class="language-plaintext highlighter-rouge">if foo:</code> rather than <code class="language-plaintext highlighter-rouge">if foo !=
|
||
[]:</code>. There are a few caveats that you should keep in mind though:</p>
|
||
|
||
<ul>
|
||
<li>
|
||
<p>Always use <code class="language-plaintext highlighter-rouge">if foo is None:</code> (or <code class="language-plaintext highlighter-rouge">is not None</code>) to check for a <code class="language-plaintext highlighter-rouge">None</code> value.
|
||
E.g., when testing whether a variable or argument that defaults to <code class="language-plaintext highlighter-rouge">None</code>
|
||
was set to some other value. The other value might be a value that’s false
|
||
in a boolean context!</p>
|
||
</li>
|
||
<li>
|
||
<p>Never compare a boolean variable to <code class="language-plaintext highlighter-rouge">False</code> using <code class="language-plaintext highlighter-rouge">==</code>. Use <code class="language-plaintext highlighter-rouge">if not x:</code>
|
||
instead. If you need to distinguish <code class="language-plaintext highlighter-rouge">False</code> from <code class="language-plaintext highlighter-rouge">None</code> then chain the
|
||
expressions, such as <code class="language-plaintext highlighter-rouge">if not x and x is not None:</code>.</p>
|
||
</li>
|
||
<li>
|
||
<p>For sequences (strings, lists, tuples), use the fact that empty sequences
|
||
are false, so <code class="language-plaintext highlighter-rouge">if seq:</code> and <code class="language-plaintext highlighter-rouge">if not seq:</code> are preferable to <code class="language-plaintext highlighter-rouge">if len(seq):</code>
|
||
and <code class="language-plaintext highlighter-rouge">if not len(seq):</code> respectively.</p>
|
||
</li>
|
||
<li>
|
||
<p>When handling integers, implicit false may involve more risk than benefit
|
||
(i.e., accidentally handling <code class="language-plaintext highlighter-rouge">None</code> as 0). You may compare a value which is
|
||
known to be an integer (and is not the result of <code class="language-plaintext highlighter-rouge">len()</code>) against the
|
||
integer 0.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">users</span><span class="p">:</span>
|
||
<span class="k">print</span><span class="p">(</span><span class="s">'no users'</span><span class="p">)</span>
|
||
|
||
<span class="k">if</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">10</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
|
||
<span class="bp">self</span><span class="p">.</span><span class="n">handle_multiple_of_ten</span><span class="p">()</span>
|
||
|
||
<span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
|
||
<span class="k">if</span> <span class="n">x</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
|
||
<span class="n">x</span> <span class="o">=</span> <span class="p">[]</span>
|
||
</code></pre></div> </div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">users</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
|
||
<span class="k">print</span><span class="p">(</span><span class="s">'no users'</span><span class="p">)</span>
|
||
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">10</span><span class="p">:</span>
|
||
<span class="bp">self</span><span class="p">.</span><span class="n">handle_multiple_of_ten</span><span class="p">()</span>
|
||
|
||
<span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
|
||
<span class="n">x</span> <span class="o">=</span> <span class="n">x</span> <span class="ow">or</span> <span class="p">[]</span>
|
||
</code></pre></div> </div>
|
||
</li>
|
||
<li>
|
||
<p>Note that <code class="language-plaintext highlighter-rouge">'0'</code> (i.e., <code class="language-plaintext highlighter-rouge">0</code> as string) evaluates to true.</p>
|
||
</li>
|
||
<li>
|
||
<p>Note that Numpy arrays may raise an exception in an implicit boolean
|
||
context. Prefer the <code class="language-plaintext highlighter-rouge">.size</code> attribute when testing emptiness of a <code class="language-plaintext highlighter-rouge">np.array</code>
|
||
(e.g. <code class="language-plaintext highlighter-rouge">if not users.size</code>).</p>
|
||
</li>
|
||
</ul>
|
||
|
||
<p><a id="s2.16-lexical-scoping"></a>
|
||
<a id="216-lexical-scoping"></a></p>
|
||
|
||
<p><a id="lexical-scoping"></a></p>
|
||
<h3 id="216-lexical-scoping">2.16 Lexical Scoping</h3>
|
||
|
||
<p>Okay to use.</p>
|
||
|
||
<p><a id="s2.16.1-definition"></a>
|
||
<a id="2161-definition"></a></p>
|
||
|
||
<p><a id="lexical-scoping-definition"></a></p>
|
||
<h4 id="2161-definition">2.16.1 Definition</h4>
|
||
|
||
<p>A nested Python function can refer to variables defined in enclosing functions,
|
||
but cannot assign to them. Variable bindings are resolved using lexical scoping,
|
||
that is, based on the static program text. Any assignment to a name in a block
|
||
will cause Python to treat all references to that name as a local variable, even
|
||
if the use precedes the assignment. If a global declaration occurs, the name is
|
||
treated as a global variable.</p>
|
||
|
||
<p>An example of the use of this feature is:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">get_adder</span><span class="p">(</span><span class="n">summand1</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-></span> <span class="n">Callable</span><span class="p">[[</span><span class="nb">float</span><span class="p">],</span> <span class="nb">float</span><span class="p">]:</span>
|
||
<span class="s">"""Returns a function that adds numbers to a given number."""</span>
|
||
<span class="k">def</span> <span class="nf">adder</span><span class="p">(</span><span class="n">summand2</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-></span> <span class="nb">float</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="n">summand1</span> <span class="o">+</span> <span class="n">summand2</span>
|
||
|
||
<span class="k">return</span> <span class="n">adder</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s2.16.2-pros"></a>
|
||
<a id="2162-pros"></a></p>
|
||
|
||
<p><a id="lexical-scoping-pros"></a></p>
|
||
<h4 id="2162-pros">2.16.2 Pros</h4>
|
||
|
||
<p>Often results in clearer, more elegant code. Especially comforting to
|
||
experienced Lisp and Scheme (and Haskell and ML and …) programmers.</p>
|
||
|
||
<p><a id="s2.16.3-cons"></a>
|
||
<a id="2163-cons"></a></p>
|
||
|
||
<p><a id="lexical-scoping-cons"></a></p>
|
||
<h4 id="2163-cons">2.16.3 Cons</h4>
|
||
|
||
<p>Can lead to confusing bugs, such as this example based on
|
||
<a href="https://peps.python.org/pep-0227/">PEP-0227</a>:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">i</span> <span class="o">=</span> <span class="mi">4</span>
|
||
<span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">[</span><span class="nb">int</span><span class="p">]):</span>
|
||
<span class="k">def</span> <span class="nf">bar</span><span class="p">():</span>
|
||
<span class="k">print</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s">''</span><span class="p">)</span>
|
||
<span class="c1"># ...
|
||
</span> <span class="c1"># A bunch of code here
|
||
</span> <span class="c1"># ...
|
||
</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">x</span><span class="p">:</span> <span class="c1"># Ah, i *is* local to foo, so this is what bar sees
|
||
</span> <span class="k">print</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s">''</span><span class="p">)</span>
|
||
<span class="n">bar</span><span class="p">()</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>So <code class="language-plaintext highlighter-rouge">foo([1, 2, 3])</code> will print <code class="language-plaintext highlighter-rouge">1 2 3 3</code>,
|
||
not <code class="language-plaintext highlighter-rouge">1 2 3 4</code>.</p>
|
||
|
||
<p><a id="s2.16.4-decision"></a>
|
||
<a id="2164-decision"></a></p>
|
||
|
||
<p><a id="lexical-scoping-decision"></a></p>
|
||
<h4 id="2164-decision">2.16.4 Decision</h4>
|
||
|
||
<p>Okay to use.</p>
|
||
|
||
<p><a id="s2.17-function-and-method-decorators"></a>
|
||
<a id="217-function-and-method-decorators"></a>
|
||
<a id="function-and-method-decorators"></a></p>
|
||
|
||
<p><a id="decorators"></a></p>
|
||
<h3 id="217-function-and-method-decorators">2.17 Function and Method Decorators</h3>
|
||
|
||
<p>Use decorators judiciously when there is a clear advantage. Avoid <code class="language-plaintext highlighter-rouge">staticmethod</code>
|
||
and limit use of <code class="language-plaintext highlighter-rouge">classmethod</code>.</p>
|
||
|
||
<p><a id="s2.17.1-definition"></a>
|
||
<a id="2171-definition"></a></p>
|
||
|
||
<p><a id="decorators-definition"></a></p>
|
||
<h4 id="2171-definition">2.17.1 Definition</h4>
|
||
|
||
<p><a href="https://docs.python.org/3/glossary.html#term-decorator">Decorators for Functions and Methods</a>
|
||
(a.k.a “the <code class="language-plaintext highlighter-rouge">@</code> notation”). One common decorator is <code class="language-plaintext highlighter-rouge">@property</code>, used for
|
||
converting ordinary methods into dynamically computed attributes. However, the
|
||
decorator syntax allows for user-defined decorators as well. Specifically, for
|
||
some function <code class="language-plaintext highlighter-rouge">my_decorator</code>, this:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">C</span><span class="p">:</span>
|
||
<span class="o">@</span><span class="n">my_decorator</span>
|
||
<span class="k">def</span> <span class="nf">method</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="c1"># method body ...
|
||
</span></code></pre></div></div>
|
||
|
||
<p>is equivalent to:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">C</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">method</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="c1"># method body ...
|
||
</span> <span class="n">method</span> <span class="o">=</span> <span class="n">my_decorator</span><span class="p">(</span><span class="n">method</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s2.17.2-pros"></a>
|
||
<a id="2172-pros"></a></p>
|
||
|
||
<p><a id="decorators-pros"></a></p>
|
||
<h4 id="2172-pros">2.17.2 Pros</h4>
|
||
|
||
<p>Elegantly specifies some transformation on a method; the transformation might
|
||
eliminate some repetitive code, enforce invariants, etc.</p>
|
||
|
||
<p><a id="s2.17.3-cons"></a>
|
||
<a id="2173-cons"></a></p>
|
||
|
||
<p><a id="decorators-cons"></a></p>
|
||
<h4 id="2173-cons">2.17.3 Cons</h4>
|
||
|
||
<p>Decorators can perform arbitrary operations on a function’s arguments or return
|
||
values, resulting in surprising implicit behavior. Additionally, decorators
|
||
execute at object definition time. For module-level objects (classes, module
|
||
functions, …) this happens at import time. Failures in decorator code are
|
||
pretty much impossible to recover from.</p>
|
||
|
||
<p><a id="s2.17.4-decision"></a>
|
||
<a id="2174-decision"></a></p>
|
||
|
||
<p><a id="decorators-decision"></a></p>
|
||
<h4 id="2174-decision">2.17.4 Decision</h4>
|
||
|
||
<p>Use decorators judiciously when there is a clear advantage. Decorators should
|
||
follow the same import and naming guidelines as functions. A decorator docstring
|
||
should clearly state that the function is a decorator. Write unit tests for
|
||
decorators.</p>
|
||
|
||
<p>Avoid external dependencies in the decorator itself (e.g. don’t rely on files,
|
||
sockets, database connections, etc.), since they might not be available when the
|
||
decorator runs (at import time, perhaps from <code class="language-plaintext highlighter-rouge">pydoc</code> or other tools). A
|
||
decorator that is called with valid parameters should (as much as possible) be
|
||
guaranteed to succeed in all cases.</p>
|
||
|
||
<p>Decorators are a special case of “top-level code” - see <a href="#s3.17-main">main</a> for
|
||
more discussion.</p>
|
||
|
||
<p>Never use <code class="language-plaintext highlighter-rouge">staticmethod</code> unless forced to in order to integrate with an API
|
||
defined in an existing library. Write a module-level function instead.</p>
|
||
|
||
<p>Use <code class="language-plaintext highlighter-rouge">classmethod</code> only when writing a named constructor, or a class-specific
|
||
routine that modifies necessary global state such as a process-wide cache.</p>
|
||
|
||
<p><a id="s2.18-threading"></a>
|
||
<a id="218-threading"></a></p>
|
||
|
||
<p><a id="threading"></a></p>
|
||
<h3 id="218-threading">2.18 Threading</h3>
|
||
|
||
<p>Do not rely on the atomicity of built-in types.</p>
|
||
|
||
<p>While Python’s built-in data types such as dictionaries appear to have atomic
|
||
operations, there are corner cases where they aren’t atomic (e.g. if <code class="language-plaintext highlighter-rouge">__hash__</code>
|
||
or <code class="language-plaintext highlighter-rouge">__eq__</code> are implemented as Python methods) and their atomicity should not be
|
||
relied upon. Neither should you rely on atomic variable assignment (since this
|
||
in turn depends on dictionaries).</p>
|
||
|
||
<p>Use the <code class="language-plaintext highlighter-rouge">queue</code> module’s <code class="language-plaintext highlighter-rouge">Queue</code> data type as the preferred way to communicate
|
||
data between threads. Otherwise, use the <code class="language-plaintext highlighter-rouge">threading</code> module and its locking
|
||
primitives. Prefer condition variables and <code class="language-plaintext highlighter-rouge">threading.Condition</code> instead of
|
||
using lower-level locks.</p>
|
||
|
||
<p><a id="s2.19-power-features"></a>
|
||
<a id="219-power-features"></a></p>
|
||
|
||
<p><a id="power-features"></a></p>
|
||
<h3 id="219-power-features">2.19 Power Features</h3>
|
||
|
||
<p>Avoid these features.</p>
|
||
|
||
<p><a id="s2.19.1-definition"></a>
|
||
<a id="2191-definition"></a></p>
|
||
|
||
<p><a id="power-features-definition"></a></p>
|
||
<h4 id="2191-definition">2.19.1 Definition</h4>
|
||
|
||
<p>Python is an extremely flexible language and gives you many fancy features such
|
||
as custom metaclasses, access to bytecode, on-the-fly compilation, dynamic
|
||
inheritance, object reparenting, import hacks, reflection (e.g. some uses of
|
||
<code class="language-plaintext highlighter-rouge">getattr()</code>), modification of system internals, <code class="language-plaintext highlighter-rouge">__del__</code> methods implementing
|
||
customized cleanup, etc.</p>
|
||
|
||
<p><a id="s2.19.2-pros"></a>
|
||
<a id="2192-pros"></a></p>
|
||
|
||
<p><a id="power-features-pros"></a></p>
|
||
<h4 id="2192-pros">2.19.2 Pros</h4>
|
||
|
||
<p>These are powerful language features. They can make your code more compact.</p>
|
||
|
||
<p><a id="s2.19.3-cons"></a>
|
||
<a id="2193-cons"></a></p>
|
||
|
||
<p><a id="power-features-cons"></a></p>
|
||
<h4 id="2193-cons">2.19.3 Cons</h4>
|
||
|
||
<p>It’s very tempting to use these “cool” features when they’re not absolutely
|
||
necessary. It’s harder to read, understand, and debug code that’s using unusual
|
||
features underneath. It doesn’t seem that way at first (to the original author),
|
||
but when revisiting the code, it tends to be more difficult than code that is
|
||
longer but is straightforward.</p>
|
||
|
||
<p><a id="s2.19.4-decision"></a>
|
||
<a id="2194-decision"></a></p>
|
||
|
||
<p><a id="power-features-decision"></a></p>
|
||
<h4 id="2194-decision">2.19.4 Decision</h4>
|
||
|
||
<p>Avoid these features in your code.</p>
|
||
|
||
<p>Standard library modules and classes that internally use these features are okay
|
||
to use (for example, <code class="language-plaintext highlighter-rouge">abc.ABCMeta</code>, <code class="language-plaintext highlighter-rouge">dataclasses</code>, and <code class="language-plaintext highlighter-rouge">enum</code>).</p>
|
||
|
||
<p><a id="s2.20-modern-python"></a>
|
||
<a id="220-modern-python"></a></p>
|
||
|
||
<p><a id="modern-python"></a></p>
|
||
<h3 id="220-modern-python-from-__future__-imports">2.20 Modern Python: from __future__ imports</h3>
|
||
|
||
<p>New language version semantic changes may be gated behind a special future
|
||
import to enable them on a per-file basis within earlier runtimes.</p>
|
||
|
||
<p><a id="s2.20.1-definition"></a>
|
||
<a id="2201-definition"></a></p>
|
||
|
||
<p><a id="modern-python-definition"></a></p>
|
||
<h4 id="2201-definition">2.20.1 Definition</h4>
|
||
|
||
<p>Being able to turn on some of the more modern features via <code class="language-plaintext highlighter-rouge">from __future__
|
||
import</code> statements allows early use of features from expected future Python
|
||
versions.</p>
|
||
|
||
<p><a id="s2.20.2-pros"></a>
|
||
<a id="2202-pros"></a></p>
|
||
|
||
<p><a id="modern-python-pros"></a></p>
|
||
<h4 id="2202-pros">2.20.2 Pros</h4>
|
||
|
||
<p>This has proven to make runtime version upgrades smoother as changes can be made
|
||
on a per-file basis while declaring compatibility and preventing regressions
|
||
within those files. Modern code is more maintainable as it is less likely to
|
||
accumulate technical debt that will be problematic during future runtime
|
||
upgrades.</p>
|
||
|
||
<p><a id="s2.20.3-cons"></a>
|
||
<a id="2203-cons"></a></p>
|
||
|
||
<p><a id="modern-python-cons"></a></p>
|
||
<h4 id="2203-cons">2.20.3 Cons</h4>
|
||
|
||
<p>Such code may not work on very old interpreter versions prior to the
|
||
introduction of the needed future statement. The need for this is more common in
|
||
projects supporting an extremely wide variety of environments.</p>
|
||
|
||
<p><a id="s2.20.4-decision"></a>
|
||
<a id="2204-decision"></a></p>
|
||
|
||
<p><a id="modern-python-decision"></a></p>
|
||
<h4 id="2204-decision">2.20.4 Decision</h4>
|
||
|
||
<h5 id="from-__future__-imports">from __future__ imports</h5>
|
||
|
||
<p>Use of <code class="language-plaintext highlighter-rouge">from __future__ import</code> statements is encouraged. It allows a given
|
||
source file to start using more modern Python syntax features today. Once you no
|
||
longer need to run on a version where the features are hidden behind a
|
||
<code class="language-plaintext highlighter-rouge">__future__</code> import, feel free to remove those lines.</p>
|
||
|
||
<p>In code that may execute on versions as old as 3.5 rather than >= 3.7, import:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">generator_stop</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>For more information read the
|
||
<a href="https://docs.python.org/3/library/__future__.html">Python future statement definitions</a>
|
||
documentation.</p>
|
||
|
||
<p>Please don’t remove these imports until you are confident the code is only ever
|
||
used in a sufficiently modern environment. Even if you do not currently use the
|
||
feature a specific future import enables in your code today, keeping it in place
|
||
in the file prevents later modifications of the code from inadvertently
|
||
depending on the older behavior.</p>
|
||
|
||
<p>Use other <code class="language-plaintext highlighter-rouge">from __future__</code> import statements as you see fit.</p>
|
||
|
||
<p><a id="s2.21-type-annotated-code"></a>
|
||
<a id="s2.21-typed-code"></a>
|
||
<a id="221-type-annotated-code"></a>
|
||
<a id="typed-code"></a></p>
|
||
|
||
<p><a id="typed-code"></a></p>
|
||
<h3 id="221-type-annotated-code">2.21 Type Annotated Code</h3>
|
||
|
||
<p>You can annotate Python code with
|
||
<a href="https://docs.python.org/3/library/typing.html">type hints</a>. Type-check the code
|
||
at build time with a type checking tool like <a href="https://github.com/google/pytype">pytype</a>.
|
||
In most cases, when feasible, type annotations are in source files. For
|
||
third-party or extension modules, annotations can be in
|
||
<a href="https://peps.python.org/pep-0484/#stub-files">stub <code class="language-plaintext highlighter-rouge">.pyi</code> files</a>.</p>
|
||
|
||
<p><a id="s2.21.1-definition"></a>
|
||
<a id="2211-definition"></a></p>
|
||
|
||
<p><a id="typed-code-definition"></a></p>
|
||
<h4 id="2211-definition">2.21.1 Definition</h4>
|
||
|
||
<p>Type annotations (or “type hints”) are for function or method arguments and
|
||
return values:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="nb">list</span><span class="p">[</span><span class="nb">int</span><span class="p">]:</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>You can also declare the type of a variable using similar syntax:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">a</span><span class="p">:</span> <span class="n">SomeType</span> <span class="o">=</span> <span class="n">some_func</span><span class="p">()</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s2.21.2-pros"></a>
|
||
<a id="2212-pros"></a></p>
|
||
|
||
<p><a id="typed-code-pros"></a></p>
|
||
<h4 id="2212-pros">2.21.2 Pros</h4>
|
||
|
||
<p>Type annotations improve the readability and maintainability of your code. The
|
||
type checker will convert many runtime errors to build-time errors, and reduce
|
||
your ability to use <a href="#power-features">Power Features</a>.</p>
|
||
|
||
<p><a id="s2.21.3-cons"></a>
|
||
<a id="2213-cons"></a></p>
|
||
|
||
<p><a id="typed-code-cons"></a></p>
|
||
<h4 id="2213-cons">2.21.3 Cons</h4>
|
||
|
||
<p>You will have to keep the type declarations up to date.
|
||
You might see type errors that you think are
|
||
valid code. Use of a
|
||
<a href="https://github.com/google/pytype">type checker</a>
|
||
may reduce your ability to use <a href="#power-features">Power Features</a>.</p>
|
||
|
||
<p><a id="s2.21.4-decision"></a>
|
||
<a id="2214-decision"></a></p>
|
||
|
||
<p><a id="typed-code-decision"></a></p>
|
||
<h4 id="2214-decision">2.21.4 Decision</h4>
|
||
|
||
<p>You are strongly encouraged to enable Python type analysis when updating code.
|
||
When adding or modifying public APIs, include type annotations and enable
|
||
checking via pytype in the build system. As static analysis is relatively new to
|
||
Python, we acknowledge that undesired side-effects (such as
|
||
wrongly
|
||
inferred types) may prevent adoption by some projects. In those situations,
|
||
authors are encouraged to add a comment with a TODO or link to a bug describing
|
||
the issue(s) currently preventing type annotation adoption in the BUILD file or
|
||
in the code itself as appropriate.</p>
|
||
|
||
<p><a id="s3-python-style-rules"></a>
|
||
<a id="3-python-style-rules"></a></p>
|
||
|
||
<p><a id="python-style-rules"></a></p>
|
||
<h2 id="3-python-style-rules">3 Python Style Rules</h2>
|
||
|
||
<p><a id="s3.1-semicolons"></a>
|
||
<a id="31-semicolons"></a></p>
|
||
|
||
<p><a id="semicolons"></a></p>
|
||
<h3 id="31-semicolons">3.1 Semicolons</h3>
|
||
|
||
<p>Do not terminate your lines with semicolons, and do not use semicolons to put
|
||
two statements on the same line.</p>
|
||
|
||
<p><a id="s3.2-line-length"></a>
|
||
<a id="32-line-length"></a></p>
|
||
|
||
<p><a id="line-length"></a></p>
|
||
<h3 id="32-line-length">3.2 Line length</h3>
|
||
|
||
<p>Maximum line length is <em>80 characters</em>.</p>
|
||
|
||
<p>Explicit exceptions to the 80 character limit:</p>
|
||
|
||
<ul>
|
||
<li>Long import statements.</li>
|
||
<li>URLs, pathnames, or long flags in comments.</li>
|
||
<li>Long string module-level constants not containing whitespace that would be
|
||
inconvenient to split across lines such as URLs or pathnames.
|
||
<ul>
|
||
<li>Pylint disable comments. (e.g.: <code class="language-plaintext highlighter-rouge"># pylint: disable=invalid-name</code>)</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<p>Do not use a backslash for
|
||
<a href="https://docs.python.org/3/reference/lexical_analysis.html#explicit-line-joining">explicit line continuation</a>.</p>
|
||
|
||
<p>Instead, make use of Python’s
|
||
<a href="http://docs.python.org/reference/lexical_analysis.html#implicit-line-joining">implicit line joining inside parentheses, brackets and braces</a>.
|
||
If necessary, you can add an extra pair of parentheses around an expression.</p>
|
||
|
||
<p>Note that this rule doesn’t prohibit backslash-escaped newlines within strings
|
||
(see <a href="#strings">below</a>).</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span> <span class="n">foo_bar</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">'black'</span><span class="p">,</span> <span class="n">design</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">x</span><span class="o">=</span><span class="s">'foo'</span><span class="p">,</span>
|
||
<span class="n">emphasis</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">highlight</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
|
||
<span class="n">Yes</span><span class="p">:</span> <span class="k">if</span> <span class="p">(</span><span class="n">width</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">height</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span>
|
||
<span class="n">color</span> <span class="o">==</span> <span class="s">'red'</span> <span class="ow">and</span> <span class="n">emphasis</span> <span class="o">==</span> <span class="s">'strong'</span><span class="p">):</span>
|
||
|
||
<span class="p">(</span><span class="n">bridge_questions</span><span class="p">.</span><span class="n">clarification_on</span>
|
||
<span class="p">.</span><span class="n">average_airspeed_of</span><span class="p">.</span><span class="n">unladen_swallow</span><span class="p">)</span> <span class="o">=</span> <span class="s">'African or European?'</span>
|
||
|
||
<span class="k">with</span> <span class="p">(</span>
|
||
<span class="n">very_long_first_expression_function</span><span class="p">()</span> <span class="k">as</span> <span class="n">spam</span><span class="p">,</span>
|
||
<span class="n">very_long_second_expression_function</span><span class="p">()</span> <span class="k">as</span> <span class="n">beans</span><span class="p">,</span>
|
||
<span class="n">third_thing</span><span class="p">()</span> <span class="k">as</span> <span class="n">eggs</span><span class="p">,</span>
|
||
<span class="p">):</span>
|
||
<span class="n">place_order</span><span class="p">(</span><span class="n">eggs</span><span class="p">,</span> <span class="n">beans</span><span class="p">,</span> <span class="n">spam</span><span class="p">,</span> <span class="n">beans</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
|
||
<span class="n">No</span><span class="p">:</span> <span class="k">if</span> <span class="n">width</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">height</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> \
|
||
<span class="n">color</span> <span class="o">==</span> <span class="s">'red'</span> <span class="ow">and</span> <span class="n">emphasis</span> <span class="o">==</span> <span class="s">'strong'</span><span class="p">:</span>
|
||
|
||
<span class="n">bridge_questions</span><span class="p">.</span><span class="n">clarification_on</span> \
|
||
<span class="p">.</span><span class="n">average_airspeed_of</span><span class="p">.</span><span class="n">unladen_swallow</span> <span class="o">=</span> <span class="s">'African or European?'</span>
|
||
|
||
<span class="k">with</span> <span class="n">very_long_first_expression_function</span><span class="p">()</span> <span class="k">as</span> <span class="n">spam</span><span class="p">,</span> \
|
||
<span class="n">very_long_second_expression_function</span><span class="p">()</span> <span class="k">as</span> <span class="n">beans</span><span class="p">,</span> \
|
||
<span class="n">third_thing</span><span class="p">()</span> <span class="k">as</span> <span class="n">eggs</span><span class="p">:</span>
|
||
<span class="n">place_order</span><span class="p">(</span><span class="n">eggs</span><span class="p">,</span> <span class="n">beans</span><span class="p">,</span> <span class="n">spam</span><span class="p">,</span> <span class="n">beans</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>When a literal string won’t fit on a single line, use parentheses for implicit
|
||
line joining.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">x</span> <span class="o">=</span> <span class="p">(</span><span class="s">'This will build a very long long '</span>
|
||
<span class="s">'long long long long long long string'</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>Prefer to break lines at the highest possible syntactic level. If you must break
|
||
a line twice, break it at the same syntactic level both times.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span> <span class="n">bridgekeeper</span><span class="p">.</span><span class="n">answer</span><span class="p">(</span>
|
||
<span class="n">name</span><span class="o">=</span><span class="s">"Arthur"</span><span class="p">,</span> <span class="n">quest</span><span class="o">=</span><span class="n">questlib</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="n">owner</span><span class="o">=</span><span class="s">"Arthur"</span><span class="p">,</span> <span class="n">perilous</span><span class="o">=</span><span class="bp">True</span><span class="p">))</span>
|
||
|
||
<span class="n">answer</span> <span class="o">=</span> <span class="p">(</span><span class="n">a_long_line</span><span class="p">().</span><span class="n">of_chained_methods</span><span class="p">()</span>
|
||
<span class="p">.</span><span class="n">that_eventually_provides</span><span class="p">().</span><span class="n">an_answer</span><span class="p">())</span>
|
||
|
||
<span class="k">if</span> <span class="p">(</span>
|
||
<span class="n">config</span> <span class="ow">is</span> <span class="bp">None</span>
|
||
<span class="ow">or</span> <span class="s">'editor.language'</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">config</span>
|
||
<span class="ow">or</span> <span class="n">config</span><span class="p">[</span><span class="s">'editor.language'</span><span class="p">].</span><span class="n">use_spaces</span> <span class="ow">is</span> <span class="bp">False</span>
|
||
<span class="p">):</span>
|
||
<span class="n">use_tabs</span><span class="p">()</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span> <span class="n">bridgekeeper</span><span class="p">.</span><span class="n">answer</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s">"Arthur"</span><span class="p">,</span> <span class="n">quest</span><span class="o">=</span><span class="n">questlib</span><span class="p">.</span><span class="n">find</span><span class="p">(</span>
|
||
<span class="n">owner</span><span class="o">=</span><span class="s">"Arthur"</span><span class="p">,</span> <span class="n">perilous</span><span class="o">=</span><span class="bp">True</span><span class="p">))</span>
|
||
|
||
<span class="n">answer</span> <span class="o">=</span> <span class="n">a_long_line</span><span class="p">().</span><span class="n">of_chained_methods</span><span class="p">().</span><span class="n">that_eventually_provides</span><span class="p">(</span>
|
||
<span class="p">).</span><span class="n">an_answer</span><span class="p">()</span>
|
||
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">config</span> <span class="ow">is</span> <span class="bp">None</span> <span class="ow">or</span> <span class="s">'editor.language'</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">config</span> <span class="ow">or</span> <span class="n">config</span><span class="p">[</span>
|
||
<span class="s">'editor.language'</span><span class="p">].</span><span class="n">use_spaces</span> <span class="ow">is</span> <span class="bp">False</span><span class="p">):</span>
|
||
<span class="n">use_tabs</span><span class="p">()</span>
|
||
|
||
</code></pre></div></div>
|
||
|
||
<p>Within comments, put long URLs on their own line if necessary.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span> <span class="c1"># See details at
|
||
</span> <span class="c1"># http://www.example.com/us/developer/documentation/api/content/v2.0/csv_file_name_extension_full_specification.html
|
||
</span></code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span> <span class="c1"># See details at
|
||
</span> <span class="c1"># http://www.example.com/us/developer/documentation/api/content/\
|
||
</span> <span class="c1"># v2.0/csv_file_name_extension_full_specification.html
|
||
</span></code></pre></div></div>
|
||
|
||
<p>Make note of the indentation of the elements in the line continuation examples
|
||
above; see the <a href="#s3.4-indentation">indentation</a> section for explanation.</p>
|
||
|
||
<p><a href="#docstrings">Docstring</a> summary lines must remain within the 80 character
|
||
limit.</p>
|
||
|
||
<p>In all other cases where a line exceeds 80 characters, and the
|
||
<a href="https://github.com/psf/black">Black</a> or <a href="https://github.com/google/pyink">Pyink</a>
|
||
auto-formatter does not help bring the line below the limit, the line is allowed
|
||
to exceed this maximum. Authors are encouraged to manually break the line up per
|
||
the notes above when it is sensible.</p>
|
||
|
||
<p><a id="s3.3-parentheses"></a>
|
||
<a id="33-parentheses"></a></p>
|
||
|
||
<p><a id="parentheses"></a></p>
|
||
<h3 id="33-parentheses">3.3 Parentheses</h3>
|
||
|
||
<p>Use parentheses sparingly.</p>
|
||
|
||
<p>It is fine, though not required, to use parentheses around tuples. Do not use
|
||
them in return statements or conditional statements unless using parentheses for
|
||
implied line continuation or to indicate a tuple.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span> <span class="k">if</span> <span class="n">foo</span><span class="p">:</span>
|
||
<span class="n">bar</span><span class="p">()</span>
|
||
<span class="k">while</span> <span class="n">x</span><span class="p">:</span>
|
||
<span class="n">x</span> <span class="o">=</span> <span class="n">bar</span><span class="p">()</span>
|
||
<span class="k">if</span> <span class="n">x</span> <span class="ow">and</span> <span class="n">y</span><span class="p">:</span>
|
||
<span class="n">bar</span><span class="p">()</span>
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="n">x</span><span class="p">:</span>
|
||
<span class="n">bar</span><span class="p">()</span>
|
||
<span class="c1"># For a 1 item tuple the ()s are more visually obvious than the comma.
|
||
</span> <span class="n">onesie</span> <span class="o">=</span> <span class="p">(</span><span class="n">foo</span><span class="p">,)</span>
|
||
<span class="k">return</span> <span class="n">foo</span>
|
||
<span class="k">return</span> <span class="n">spam</span><span class="p">,</span> <span class="n">beans</span>
|
||
<span class="k">return</span> <span class="p">(</span><span class="n">spam</span><span class="p">,</span> <span class="n">beans</span><span class="p">)</span>
|
||
<span class="k">for</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">dict</span><span class="p">.</span><span class="n">items</span><span class="p">():</span> <span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span> <span class="k">if</span> <span class="p">(</span><span class="n">x</span><span class="p">):</span>
|
||
<span class="n">bar</span><span class="p">()</span>
|
||
<span class="k">if</span> <span class="ow">not</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
|
||
<span class="n">bar</span><span class="p">()</span>
|
||
<span class="k">return</span> <span class="p">(</span><span class="n">foo</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s3.4-indentation"></a>
|
||
<a id="34-indentation"></a></p>
|
||
|
||
<p><a id="indentation"></a></p>
|
||
<h3 id="34-indentation">3.4 Indentation</h3>
|
||
|
||
<p>Indent your code blocks with <em>4 spaces</em>.</p>
|
||
|
||
<p>Never use tabs. Implied line continuation should align wrapped elements
|
||
vertically (see <a href="#s3.2-line-length">line length examples</a>), or use a hanging
|
||
4-space indent. Closing (round, square or curly) brackets can be placed at the
|
||
end of the expression, or on separate lines, but then should be indented the
|
||
same as the line with the corresponding opening bracket.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span> <span class="c1"># Aligned with opening delimiter.
|
||
</span> <span class="n">foo</span> <span class="o">=</span> <span class="n">long_function_name</span><span class="p">(</span><span class="n">var_one</span><span class="p">,</span> <span class="n">var_two</span><span class="p">,</span>
|
||
<span class="n">var_three</span><span class="p">,</span> <span class="n">var_four</span><span class="p">)</span>
|
||
<span class="n">meal</span> <span class="o">=</span> <span class="p">(</span><span class="n">spam</span><span class="p">,</span>
|
||
<span class="n">beans</span><span class="p">)</span>
|
||
|
||
<span class="c1"># Aligned with opening delimiter in a dictionary.
|
||
</span> <span class="n">foo</span> <span class="o">=</span> <span class="p">{</span>
|
||
<span class="s">'long_dictionary_key'</span><span class="p">:</span> <span class="n">value1</span> <span class="o">+</span>
|
||
<span class="n">value2</span><span class="p">,</span>
|
||
<span class="p">...</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="c1"># 4-space hanging indent; nothing on first line.
|
||
</span> <span class="n">foo</span> <span class="o">=</span> <span class="n">long_function_name</span><span class="p">(</span>
|
||
<span class="n">var_one</span><span class="p">,</span> <span class="n">var_two</span><span class="p">,</span> <span class="n">var_three</span><span class="p">,</span>
|
||
<span class="n">var_four</span><span class="p">)</span>
|
||
<span class="n">meal</span> <span class="o">=</span> <span class="p">(</span>
|
||
<span class="n">spam</span><span class="p">,</span>
|
||
<span class="n">beans</span><span class="p">)</span>
|
||
|
||
<span class="c1"># 4-space hanging indent; nothing on first line,
|
||
</span> <span class="c1"># closing parenthesis on a new line.
|
||
</span> <span class="n">foo</span> <span class="o">=</span> <span class="n">long_function_name</span><span class="p">(</span>
|
||
<span class="n">var_one</span><span class="p">,</span> <span class="n">var_two</span><span class="p">,</span> <span class="n">var_three</span><span class="p">,</span>
|
||
<span class="n">var_four</span>
|
||
<span class="p">)</span>
|
||
<span class="n">meal</span> <span class="o">=</span> <span class="p">(</span>
|
||
<span class="n">spam</span><span class="p">,</span>
|
||
<span class="n">beans</span><span class="p">,</span>
|
||
<span class="p">)</span>
|
||
|
||
<span class="c1"># 4-space hanging indent in a dictionary.
|
||
</span> <span class="n">foo</span> <span class="o">=</span> <span class="p">{</span>
|
||
<span class="s">'long_dictionary_key'</span><span class="p">:</span>
|
||
<span class="n">long_dictionary_value</span><span class="p">,</span>
|
||
<span class="p">...</span>
|
||
<span class="p">}</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span> <span class="c1"># Stuff on first line forbidden.
|
||
</span> <span class="n">foo</span> <span class="o">=</span> <span class="n">long_function_name</span><span class="p">(</span><span class="n">var_one</span><span class="p">,</span> <span class="n">var_two</span><span class="p">,</span>
|
||
<span class="n">var_three</span><span class="p">,</span> <span class="n">var_four</span><span class="p">)</span>
|
||
<span class="n">meal</span> <span class="o">=</span> <span class="p">(</span><span class="n">spam</span><span class="p">,</span>
|
||
<span class="n">beans</span><span class="p">)</span>
|
||
|
||
<span class="c1"># 2-space hanging indent forbidden.
|
||
</span> <span class="n">foo</span> <span class="o">=</span> <span class="n">long_function_name</span><span class="p">(</span>
|
||
<span class="n">var_one</span><span class="p">,</span> <span class="n">var_two</span><span class="p">,</span> <span class="n">var_three</span><span class="p">,</span>
|
||
<span class="n">var_four</span><span class="p">)</span>
|
||
|
||
<span class="c1"># No hanging indent in a dictionary.
|
||
</span> <span class="n">foo</span> <span class="o">=</span> <span class="p">{</span>
|
||
<span class="s">'long_dictionary_key'</span><span class="p">:</span>
|
||
<span class="n">long_dictionary_value</span><span class="p">,</span>
|
||
<span class="p">...</span>
|
||
<span class="p">}</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s3.4.1-trailing-comma"></a>
|
||
<a id="s3.4.1-trailing-commas"></a>
|
||
<a id="s3.4.1-trailing_comma"></a>
|
||
<a id="s3.4.1-trailing_commas"></a>
|
||
<a id="341-trailing_comma"></a>
|
||
<a id="341-trailing_commas"></a>
|
||
<a id="trailing_comma"></a>
|
||
<a id="trailing_commas"></a></p>
|
||
|
||
<p><a id="trailing-comma"></a></p>
|
||
<h4 id="341-trailing-commas-in-sequences-of-items">3.4.1 Trailing commas in sequences of items?</h4>
|
||
|
||
<p>Trailing commas in sequences of items are recommended only when the closing
|
||
container token <code class="language-plaintext highlighter-rouge">]</code>, <code class="language-plaintext highlighter-rouge">)</code>, or <code class="language-plaintext highlighter-rouge">}</code> does not appear on the same line as the final
|
||
element, as well as for tuples with a single element. The presence of a trailing
|
||
comma is also used as a hint to our Python code auto-formatter
|
||
<a href="https://github.com/psf/black">Black</a> or <a href="https://github.com/google/pyink">Pyink</a>
|
||
to direct it to auto-format the container of items to one item per line when the
|
||
<code class="language-plaintext highlighter-rouge">,</code> after the final element is present.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span> <span class="n">golomb3</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>
|
||
<span class="n">golomb4</span> <span class="o">=</span> <span class="p">[</span>
|
||
<span class="mi">0</span><span class="p">,</span>
|
||
<span class="mi">1</span><span class="p">,</span>
|
||
<span class="mi">4</span><span class="p">,</span>
|
||
<span class="mi">6</span><span class="p">,</span>
|
||
<span class="p">]</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span> <span class="n">golomb4</span> <span class="o">=</span> <span class="p">[</span>
|
||
<span class="mi">0</span><span class="p">,</span>
|
||
<span class="mi">1</span><span class="p">,</span>
|
||
<span class="mi">4</span><span class="p">,</span>
|
||
<span class="mi">6</span><span class="p">,]</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s3.5-blank-lines"></a>
|
||
<a id="35-blank-lines"></a></p>
|
||
|
||
<p><a id="blank-lines"></a></p>
|
||
<h3 id="35-blank-lines">3.5 Blank Lines</h3>
|
||
|
||
<p>Two blank lines between top-level definitions, be they function or class
|
||
definitions. One blank line between method definitions and between the docstring
|
||
of a <code class="language-plaintext highlighter-rouge">class</code> and the first method. No blank line following a <code class="language-plaintext highlighter-rouge">def</code> line. Use
|
||
single blank lines as you judge appropriate within functions or methods.</p>
|
||
|
||
<p>Blank lines need not be anchored to the definition. For example, related
|
||
comments immediately preceding function, class, and method definitions can make
|
||
sense. Consider if your comment might be more useful as part of the docstring.</p>
|
||
|
||
<p><a id="s3.6-whitespace"></a>
|
||
<a id="36-whitespace"></a></p>
|
||
|
||
<p><a id="whitespace"></a></p>
|
||
<h3 id="36-whitespace">3.6 Whitespace</h3>
|
||
|
||
<p>Follow standard typographic rules for the use of spaces around punctuation.</p>
|
||
|
||
<p>No whitespace inside parentheses, brackets or braces.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span> <span class="n">spam</span><span class="p">(</span><span class="n">ham</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="p">{</span><span class="s">'eggs'</span><span class="p">:</span> <span class="mi">2</span><span class="p">},</span> <span class="p">[])</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span> <span class="n">spam</span><span class="p">(</span> <span class="n">ham</span><span class="p">[</span> <span class="mi">1</span> <span class="p">],</span> <span class="p">{</span> <span class="s">'eggs'</span><span class="p">:</span> <span class="mi">2</span> <span class="p">},</span> <span class="p">[</span> <span class="p">]</span> <span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>No whitespace before a comma, semicolon, or colon. Do use whitespace after a
|
||
comma, semicolon, or colon, except at the end of the line.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span> <span class="k">if</span> <span class="n">x</span> <span class="o">==</span> <span class="mi">4</span><span class="p">:</span>
|
||
<span class="k">print</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span>
|
||
<span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">y</span><span class="p">,</span> <span class="n">x</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span> <span class="k">if</span> <span class="n">x</span> <span class="o">==</span> <span class="mi">4</span> <span class="p">:</span>
|
||
<span class="k">print</span><span class="p">(</span><span class="n">x</span> <span class="p">,</span> <span class="n">y</span><span class="p">)</span>
|
||
<span class="n">x</span> <span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">y</span> <span class="p">,</span> <span class="n">x</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>No whitespace before the open paren/bracket that starts an argument list,
|
||
indexing or slicing.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span> <span class="n">spam</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span> <span class="n">spam</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="s">'key'</span><span class="p">]</span> <span class="o">=</span> <span class="nb">list</span><span class="p">[</span><span class="n">index</span><span class="p">]</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span> <span class="nb">dict</span> <span class="p">[</span><span class="s">'key'</span><span class="p">]</span> <span class="o">=</span> <span class="nb">list</span> <span class="p">[</span><span class="n">index</span><span class="p">]</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>No trailing whitespace.</p>
|
||
|
||
<p>Surround binary operators with a single space on either side for assignment
|
||
(<code class="language-plaintext highlighter-rouge">=</code>), comparisons (<code class="language-plaintext highlighter-rouge">==, <, >, !=, <>, <=, >=, in, not in, is, is not</code>), and
|
||
Booleans (<code class="language-plaintext highlighter-rouge">and, or, not</code>). Use your better judgment for the insertion of spaces
|
||
around arithmetic operators (<code class="language-plaintext highlighter-rouge">+</code>, <code class="language-plaintext highlighter-rouge">-</code>, <code class="language-plaintext highlighter-rouge">*</code>, <code class="language-plaintext highlighter-rouge">/</code>, <code class="language-plaintext highlighter-rouge">//</code>, <code class="language-plaintext highlighter-rouge">%</code>, <code class="language-plaintext highlighter-rouge">**</code>, <code class="language-plaintext highlighter-rouge">@</code>).</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span> <span class="n">x</span> <span class="o">==</span> <span class="mi">1</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span> <span class="n">x</span><span class="o"><</span><span class="mi">1</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>Never use spaces around <code class="language-plaintext highlighter-rouge">=</code> when passing keyword arguments or defining a default
|
||
parameter value, with one exception:
|
||
<a href="#typing-default-values">when a type annotation is present</a>, <em>do</em> use spaces
|
||
around the <code class="language-plaintext highlighter-rouge">=</code> for the default parameter value.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span> <span class="k">def</span> <span class="nf">complex</span><span class="p">(</span><span class="n">real</span><span class="p">,</span> <span class="n">imag</span><span class="o">=</span><span class="mf">0.0</span><span class="p">):</span> <span class="k">return</span> <span class="n">Magic</span><span class="p">(</span><span class="n">r</span><span class="o">=</span><span class="n">real</span><span class="p">,</span> <span class="n">i</span><span class="o">=</span><span class="n">imag</span><span class="p">)</span>
|
||
<span class="n">Yes</span><span class="p">:</span> <span class="k">def</span> <span class="nf">complex</span><span class="p">(</span><span class="n">real</span><span class="p">,</span> <span class="n">imag</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="mf">0.0</span><span class="p">):</span> <span class="k">return</span> <span class="n">Magic</span><span class="p">(</span><span class="n">r</span><span class="o">=</span><span class="n">real</span><span class="p">,</span> <span class="n">i</span><span class="o">=</span><span class="n">imag</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span> <span class="k">def</span> <span class="nf">complex</span><span class="p">(</span><span class="n">real</span><span class="p">,</span> <span class="n">imag</span> <span class="o">=</span> <span class="mf">0.0</span><span class="p">):</span> <span class="k">return</span> <span class="n">Magic</span><span class="p">(</span><span class="n">r</span> <span class="o">=</span> <span class="n">real</span><span class="p">,</span> <span class="n">i</span> <span class="o">=</span> <span class="n">imag</span><span class="p">)</span>
|
||
<span class="n">No</span><span class="p">:</span> <span class="k">def</span> <span class="nf">complex</span><span class="p">(</span><span class="n">real</span><span class="p">,</span> <span class="n">imag</span><span class="p">:</span> <span class="nb">float</span><span class="o">=</span><span class="mf">0.0</span><span class="p">):</span> <span class="k">return</span> <span class="n">Magic</span><span class="p">(</span><span class="n">r</span> <span class="o">=</span> <span class="n">real</span><span class="p">,</span> <span class="n">i</span> <span class="o">=</span> <span class="n">imag</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>Don’t use spaces to vertically align tokens on consecutive lines, since it
|
||
becomes a maintenance burden (applies to <code class="language-plaintext highlighter-rouge">:</code>, <code class="language-plaintext highlighter-rouge">#</code>, <code class="language-plaintext highlighter-rouge">=</code>, etc.):</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span>
|
||
<span class="n">foo</span> <span class="o">=</span> <span class="mi">1000</span> <span class="c1"># comment
|
||
</span> <span class="n">long_name</span> <span class="o">=</span> <span class="mi">2</span> <span class="c1"># comment that should not be aligned
|
||
</span>
|
||
<span class="n">dictionary</span> <span class="o">=</span> <span class="p">{</span>
|
||
<span class="s">'foo'</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
|
||
<span class="s">'long_name'</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
|
||
<span class="p">}</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span>
|
||
<span class="n">foo</span> <span class="o">=</span> <span class="mi">1000</span> <span class="c1"># comment
|
||
</span> <span class="n">long_name</span> <span class="o">=</span> <span class="mi">2</span> <span class="c1"># comment that should not be aligned
|
||
</span>
|
||
<span class="n">dictionary</span> <span class="o">=</span> <span class="p">{</span>
|
||
<span class="s">'foo'</span> <span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
|
||
<span class="s">'long_name'</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
|
||
<span class="p">}</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="Python_Interpreter"></a>
|
||
<a id="s3.7-shebang-line"></a>
|
||
<a id="37-shebang-line"></a></p>
|
||
|
||
<p><a id="shebang-line"></a></p>
|
||
<h3 id="37-shebang-line">3.7 Shebang Line</h3>
|
||
|
||
<p>Most <code class="language-plaintext highlighter-rouge">.py</code> files do not need to start with a <code class="language-plaintext highlighter-rouge">#!</code> line. Start the main file of a
|
||
program with
|
||
<code class="language-plaintext highlighter-rouge">#!/usr/bin/env python3</code> (to support virtualenvs) or <code class="language-plaintext highlighter-rouge">#!/usr/bin/python3</code> per
|
||
<a href="https://peps.python.org/pep-0394/">PEP-394</a>.</p>
|
||
|
||
<p>This line is used by the kernel to find the Python interpreter, but is ignored by Python when importing modules. It is only necessary on a file intended to be executed directly.</p>
|
||
|
||
<p><a id="s3.8-comments-and-docstrings"></a>
|
||
<a id="s3.8-comments"></a>
|
||
<a id="38-comments-and-docstrings"></a></p>
|
||
|
||
<p><a id="documentation"></a></p>
|
||
<h3 id="38-comments-and-docstrings">3.8 Comments and Docstrings</h3>
|
||
|
||
<p>Be sure to use the right style for module, function, method docstrings and
|
||
inline comments.</p>
|
||
|
||
<p><a id="s3.8.1-comments-in-doc-strings"></a>
|
||
<a id="381-docstrings"></a>
|
||
<a id="comments-in-doc-strings"></a></p>
|
||
|
||
<p><a id="docstrings"></a></p>
|
||
<h4 id="381-docstrings">3.8.1 Docstrings</h4>
|
||
|
||
<p>Python uses <em>docstrings</em> to document code. A docstring is a string that is the
|
||
first statement in a package, module, class or function. These strings can be
|
||
extracted automatically through the <code class="language-plaintext highlighter-rouge">__doc__</code> member of the object and are used
|
||
by <code class="language-plaintext highlighter-rouge">pydoc</code>.
|
||
(Try running <code class="language-plaintext highlighter-rouge">pydoc</code> on your module to see how it looks.) Always use the
|
||
three-double-quote <code class="language-plaintext highlighter-rouge">"""</code> format for docstrings (per
|
||
<a href="https://peps.python.org/pep-0257/">PEP 257</a>). A docstring should be organized
|
||
as a summary line (one physical line not exceeding 80 characters) terminated by
|
||
a period, question mark, or exclamation point. When writing more (encouraged),
|
||
this must be followed by a blank line, followed by the rest of the docstring
|
||
starting at the same cursor position as the first quote of the first line. There
|
||
are more formatting guidelines for docstrings below.</p>
|
||
|
||
<p><a id="s3.8.2-comments-in-modules"></a>
|
||
<a id="382-modules"></a>
|
||
<a id="comments-in-modules"></a></p>
|
||
|
||
<p><a id="module-docs"></a></p>
|
||
<h4 id="382-modules">3.8.2 Modules</h4>
|
||
|
||
<p>Every file should contain license boilerplate. Choose the appropriate boilerplate for the license used by the project (for example, Apache 2.0, BSD, LGPL, GPL).</p>
|
||
|
||
<p>Files should start with a docstring describing the contents and usage of the
|
||
module.</p>
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s">"""A one-line summary of the module or program, terminated by a period.
|
||
|
||
Leave one blank line. The rest of this docstring should contain an
|
||
overall description of the module or program. Optionally, it may also
|
||
contain a brief description of exported classes and functions and/or usage
|
||
examples.
|
||
|
||
Typical usage example:
|
||
|
||
foo = ClassFoo()
|
||
bar = foo.function_bar()
|
||
"""</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s3.8.2.1-test-modules"></a></p>
|
||
|
||
<p><a id="test-docs"></a></p>
|
||
<h5 id="3821-test-modules">3.8.2.1 Test modules</h5>
|
||
|
||
<p>Module-level docstrings for test files are not required. They should be included
|
||
only when there is additional information that can be provided.</p>
|
||
|
||
<p>Examples include some specifics on how the test should be run, an explanation of
|
||
an unusual setup pattern, dependency on the external environment, and so on.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s">"""This blaze test uses golden files.
|
||
|
||
You can update those files by running
|
||
`blaze run //foo/bar:foo_test -- --update_golden_files` from the `google3`
|
||
directory.
|
||
"""</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>Docstrings that do not provide any new information should not be used.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s">"""Tests for foo.bar."""</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s3.8.3-functions-and-methods"></a>
|
||
<a id="383-functions-and-methods"></a>
|
||
<a id="functions-and-methods"></a></p>
|
||
|
||
<p><a id="function-docs"></a></p>
|
||
<h4 id="383-functions-and-methods">3.8.3 Functions and Methods</h4>
|
||
|
||
<p>In this section, “function” means a method, function, generator, or property.</p>
|
||
|
||
<p>A docstring is mandatory for every function that has one or more of the
|
||
following properties:</p>
|
||
|
||
<ul>
|
||
<li>being part of the public API</li>
|
||
<li>nontrivial size</li>
|
||
<li>non-obvious logic</li>
|
||
</ul>
|
||
|
||
<p>A docstring should give enough information to write a call to the function
|
||
without reading the function’s code. The docstring should describe the
|
||
function’s calling syntax and its semantics, but generally not its
|
||
implementation details, unless those details are relevant to how the function is
|
||
to be used. For example, a function that mutates one of its arguments as a side
|
||
effect should note that in its docstring. Otherwise, subtle but important
|
||
details of a function’s implementation that are not relevant to the caller are
|
||
better expressed as comments alongside the code than within the function’s
|
||
docstring.</p>
|
||
|
||
<p>The docstring may be descriptive-style (<code class="language-plaintext highlighter-rouge">"""Fetches rows from a Bigtable."""</code>)
|
||
or imperative-style (<code class="language-plaintext highlighter-rouge">"""Fetch rows from a Bigtable."""</code>), but the style should
|
||
be consistent within a file. The docstring for a <code class="language-plaintext highlighter-rouge">@property</code> data descriptor
|
||
should use the same style as the docstring for an attribute or a
|
||
<a href="#doc-function-args">function argument</a> (<code class="language-plaintext highlighter-rouge">"""The Bigtable path."""</code>,
|
||
rather than <code class="language-plaintext highlighter-rouge">"""Returns the Bigtable path."""</code>).</p>
|
||
|
||
<p>Certain aspects of a function should be documented in special sections, listed
|
||
below. Each section begins with a heading line, which ends with a colon. All
|
||
sections other than the heading should maintain a hanging indent of two or four
|
||
spaces (be consistent within a file). These sections can be omitted in cases
|
||
where the function’s name and signature are informative enough that it can be
|
||
aptly described using a one-line docstring.</p>
|
||
|
||
<dl>
|
||
<dt><a id="doc-function-args"></a></dt>
|
||
<dt><a href="#doc-function-args"><em>Args:</em></a></dt>
|
||
<dd>List each parameter by name. A description should follow the name, and be
|
||
separated by a colon followed by either a space or newline. If the
|
||
description is too long to fit on a single 80-character line, use a hanging
|
||
indent of 2 or 4 spaces more than the parameter name (be consistent with the
|
||
rest of the docstrings in the file). The description should include required
|
||
type(s) if the code does not contain a corresponding type annotation. If a
|
||
function accepts <code class="language-plaintext highlighter-rouge">*foo</code> (variable length argument lists) and/or <code class="language-plaintext highlighter-rouge">**bar</code>
|
||
(arbitrary keyword arguments), they should be listed as <code class="language-plaintext highlighter-rouge">*foo</code> and <code class="language-plaintext highlighter-rouge">**bar</code>.</dd>
|
||
<dt><a id="doc-function-returns"></a></dt>
|
||
<dt><a href="#doc-function-returns"><em>Returns:</em> (or <em>Yields:</em> for generators)</a></dt>
|
||
<dd>Describe the semantics of the return value, including any type information
|
||
that the type annotation does not provide. If the function only returns
|
||
None, this section is not required. It may also be omitted if the docstring
|
||
starts with “Return”, “Returns”, “Yield”, or “Yields” (e.g. <code class="language-plaintext highlighter-rouge">"""Returns row
|
||
from Bigtable as a tuple of strings."""</code>) <em>and</em> the opening sentence is
|
||
sufficient to describe the return value. Do not imitate older ‘NumPy style’
|
||
(<a href="https://numpy.org/doc/1.24/reference/generated/numpy.linalg.qr.html">example</a>),
|
||
which frequently documented a tuple return value as if it were multiple
|
||
return values with individual names (never mentioning the tuple). Instead,
|
||
describe such a return value as: “Returns: A tuple (mat_a, mat_b), where
|
||
mat_a is …, and …”. The auxiliary names in the docstring need not
|
||
necessarily correspond to any internal names used in the function body (as
|
||
those are not part of the API). If the function uses <code class="language-plaintext highlighter-rouge">yield</code> (is a
|
||
generator), the <code class="language-plaintext highlighter-rouge">Yields:</code> section should document the object returned by
|
||
<code class="language-plaintext highlighter-rouge">next()</code>, instead of the generator object itself that the call evaluates to.</dd>
|
||
<dt><a id="doc-function-raises"></a></dt>
|
||
<dt><a href="#doc-function-raises"><em>Raises:</em></a></dt>
|
||
<dd>List all exceptions that are relevant to the interface followed by a
|
||
description. Use a similar exception name + colon + space or newline and
|
||
hanging indent style as described in <em>Args:</em>. You should not document
|
||
exceptions that get raised if the API specified in the docstring is violated
|
||
(because this would paradoxically make behavior under violation of the API
|
||
part of the API).</dd>
|
||
</dl>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">fetch_smalltable_rows</span><span class="p">(</span>
|
||
<span class="n">table_handle</span><span class="p">:</span> <span class="n">smalltable</span><span class="p">.</span><span class="n">Table</span><span class="p">,</span>
|
||
<span class="n">keys</span><span class="p">:</span> <span class="n">Sequence</span><span class="p">[</span><span class="nb">bytes</span> <span class="o">|</span> <span class="nb">str</span><span class="p">],</span>
|
||
<span class="n">require_all_keys</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="bp">False</span><span class="p">,</span>
|
||
<span class="p">)</span> <span class="o">-></span> <span class="n">Mapping</span><span class="p">[</span><span class="nb">bytes</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="p">...]]:</span>
|
||
<span class="s">"""Fetches rows from a Smalltable.
|
||
|
||
Retrieves rows pertaining to the given keys from the Table instance
|
||
represented by table_handle. String keys will be UTF-8 encoded.
|
||
|
||
Args:
|
||
table_handle: An open smalltable.Table instance.
|
||
keys: A sequence of strings representing the key of each table
|
||
row to fetch. String keys will be UTF-8 encoded.
|
||
require_all_keys: If True only rows with values set for all keys will be
|
||
returned.
|
||
|
||
Returns:
|
||
A dict mapping keys to the corresponding table row data
|
||
fetched. Each row is represented as a tuple of strings. For
|
||
example:
|
||
|
||
{b'Serak': ('Rigel VII', 'Preparer'),
|
||
b'Zim': ('Irk', 'Invader'),
|
||
b'Lrrr': ('Omicron Persei 8', 'Emperor')}
|
||
|
||
Returned keys are always bytes. If a key from the keys argument is
|
||
missing from the dictionary, then that row was not found in the
|
||
table (and require_all_keys must have been False).
|
||
|
||
Raises:
|
||
IOError: An error occurred accessing the smalltable.
|
||
"""</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>Similarly, this variation on <code class="language-plaintext highlighter-rouge">Args:</code> with a line break is also allowed:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">fetch_smalltable_rows</span><span class="p">(</span>
|
||
<span class="n">table_handle</span><span class="p">:</span> <span class="n">smalltable</span><span class="p">.</span><span class="n">Table</span><span class="p">,</span>
|
||
<span class="n">keys</span><span class="p">:</span> <span class="n">Sequence</span><span class="p">[</span><span class="nb">bytes</span> <span class="o">|</span> <span class="nb">str</span><span class="p">],</span>
|
||
<span class="n">require_all_keys</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="bp">False</span><span class="p">,</span>
|
||
<span class="p">)</span> <span class="o">-></span> <span class="n">Mapping</span><span class="p">[</span><span class="nb">bytes</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="p">...]]:</span>
|
||
<span class="s">"""Fetches rows from a Smalltable.
|
||
|
||
Retrieves rows pertaining to the given keys from the Table instance
|
||
represented by table_handle. String keys will be UTF-8 encoded.
|
||
|
||
Args:
|
||
table_handle:
|
||
An open smalltable.Table instance.
|
||
keys:
|
||
A sequence of strings representing the key of each table row to
|
||
fetch. String keys will be UTF-8 encoded.
|
||
require_all_keys:
|
||
If True only rows with values set for all keys will be returned.
|
||
|
||
Returns:
|
||
A dict mapping keys to the corresponding table row data
|
||
fetched. Each row is represented as a tuple of strings. For
|
||
example:
|
||
|
||
{b'Serak': ('Rigel VII', 'Preparer'),
|
||
b'Zim': ('Irk', 'Invader'),
|
||
b'Lrrr': ('Omicron Persei 8', 'Emperor')}
|
||
|
||
Returned keys are always bytes. If a key from the keys argument is
|
||
missing from the dictionary, then that row was not found in the
|
||
table (and require_all_keys must have been False).
|
||
|
||
Raises:
|
||
IOError: An error occurred accessing the smalltable.
|
||
"""</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s3.8.3.1-overridden-methods"></a></p>
|
||
|
||
<p><a id="overridden-method-docs"></a></p>
|
||
<h5 id="3831-overridden-methods">3.8.3.1 Overridden Methods</h5>
|
||
|
||
<p>A method that overrides a method from a base class does not need a docstring if
|
||
it is explicitly decorated with
|
||
<a href="https://typing-extensions.readthedocs.io/en/latest/#override"><code class="language-plaintext highlighter-rouge">@override</code></a>
|
||
(from <code class="language-plaintext highlighter-rouge">typing_extensions</code> or <code class="language-plaintext highlighter-rouge">typing</code> modules), unless the overriding method’s
|
||
behavior materially refines the base method’s contract, or details need to be
|
||
provided (e.g., documenting additional side effects), in which case a docstring
|
||
with at least those differences is required on the overriding method.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">typing_extensions</span> <span class="kn">import</span> <span class="n">override</span>
|
||
|
||
<span class="k">class</span> <span class="nc">Parent</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">do_something</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="s">"""Parent method, includes docstring."""</span>
|
||
|
||
<span class="c1"># Child class, method annotated with override.
|
||
</span><span class="k">class</span> <span class="nc">Child</span><span class="p">(</span><span class="n">Parent</span><span class="p">):</span>
|
||
<span class="o">@</span><span class="n">override</span>
|
||
<span class="k">def</span> <span class="nf">do_something</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="k">pass</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Child class, but without @override decorator, a docstring is required.
|
||
</span><span class="k">class</span> <span class="nc">Child</span><span class="p">(</span><span class="n">Parent</span><span class="p">):</span>
|
||
<span class="k">def</span> <span class="nf">do_something</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="k">pass</span>
|
||
|
||
<span class="c1"># Docstring is trivial, @override is sufficient to indicate that docs can be
|
||
# found in the base class.
|
||
</span><span class="k">class</span> <span class="nc">Child</span><span class="p">(</span><span class="n">Parent</span><span class="p">):</span>
|
||
<span class="o">@</span><span class="n">override</span>
|
||
<span class="k">def</span> <span class="nf">do_something</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="s">"""See base class."""</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s3.8.4-comments-in-classes"></a>
|
||
<a id="384-classes"></a>
|
||
<a id="comments-in-classes"></a></p>
|
||
|
||
<p><a id="class-docs"></a></p>
|
||
<h4 id="384-classes">3.8.4 Classes</h4>
|
||
|
||
<p>Classes should have a docstring below the class definition describing the class.
|
||
Public attributes, excluding <a href="#properties">properties</a>, should be documented
|
||
here in an <code class="language-plaintext highlighter-rouge">Attributes</code> section and follow the same formatting as a
|
||
<a href="#doc-function-args">function’s <code class="language-plaintext highlighter-rouge">Args</code></a> section.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">SampleClass</span><span class="p">:</span>
|
||
<span class="s">"""Summary of class here.
|
||
|
||
Longer class information...
|
||
Longer class information...
|
||
|
||
Attributes:
|
||
likes_spam: A boolean indicating if we like SPAM or not.
|
||
eggs: An integer count of the eggs we have laid.
|
||
"""</span>
|
||
|
||
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">likes_spam</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="bp">False</span><span class="p">):</span>
|
||
<span class="s">"""Initializes the instance based on spam preference.
|
||
|
||
Args:
|
||
likes_spam: Defines if instance exhibits this preference.
|
||
"""</span>
|
||
<span class="bp">self</span><span class="p">.</span><span class="n">likes_spam</span> <span class="o">=</span> <span class="n">likes_spam</span>
|
||
<span class="bp">self</span><span class="p">.</span><span class="n">eggs</span> <span class="o">=</span> <span class="mi">0</span>
|
||
|
||
<span class="o">@</span><span class="nb">property</span>
|
||
<span class="k">def</span> <span class="nf">butter_sticks</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
|
||
<span class="s">"""The number of butter sticks we have."""</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>All class docstrings should start with a one-line summary that describes what
|
||
the class instance represents. This implies that subclasses of <code class="language-plaintext highlighter-rouge">Exception</code>
|
||
should also describe what the exception represents, and not the context in which
|
||
it might occur. The class docstring should not repeat unnecessary information,
|
||
such as that the class is a class.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Yes:
|
||
</span><span class="k">class</span> <span class="nc">CheeseShopAddress</span><span class="p">:</span>
|
||
<span class="s">"""The address of a cheese shop.
|
||
|
||
...
|
||
"""</span>
|
||
|
||
<span class="k">class</span> <span class="nc">OutOfCheeseError</span><span class="p">(</span><span class="nb">Exception</span><span class="p">):</span>
|
||
<span class="s">"""No more cheese is available."""</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># No:
|
||
</span><span class="k">class</span> <span class="nc">CheeseShopAddress</span><span class="p">:</span>
|
||
<span class="s">"""Class that describes the address of a cheese shop.
|
||
|
||
...
|
||
"""</span>
|
||
|
||
<span class="k">class</span> <span class="nc">OutOfCheeseError</span><span class="p">(</span><span class="nb">Exception</span><span class="p">):</span>
|
||
<span class="s">"""Raised when no more cheese is available."""</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s3.8.5-block-and-inline-comments"></a>
|
||
<a id="comments-in-block-and-inline"></a>
|
||
<a id="s3.8.5-comments-in-block-and-inline"></a>
|
||
<a id="385-block-and-inline-comments"></a></p>
|
||
|
||
<p><a id="comments"></a></p>
|
||
<h4 id="385-block-and-inline-comments">3.8.5 Block and Inline Comments</h4>
|
||
|
||
<p>The final place to have comments is in tricky parts of the code. If you’re going
|
||
to have to explain it at the next <a href="http://en.wikipedia.org/wiki/Code_review">code review</a>,
|
||
you should comment it now. Complicated operations get a few lines of comments
|
||
before the operations commence. Non-obvious ones get comments at the end of the
|
||
line.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># We use a weighted dictionary search to find out where i is in
|
||
# the array. We extrapolate position based on the largest num
|
||
# in the array and the array size and then do binary search to
|
||
# get the exact number.
|
||
</span>
|
||
<span class="k">if</span> <span class="n">i</span> <span class="o">&</span> <span class="p">(</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span> <span class="c1"># True if i is 0 or a power of 2.
|
||
</span></code></pre></div></div>
|
||
|
||
<p>To improve legibility, these comments should start at least 2 spaces away from
|
||
the code with the comment character <code class="language-plaintext highlighter-rouge">#</code>, followed by at least one space before
|
||
the text of the comment itself.</p>
|
||
|
||
<p>On the other hand, never describe the code. Assume the person reading the code
|
||
knows Python (though not what you’re trying to do) better than you do.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># BAD COMMENT: Now go through the b array and make sure whenever i occurs
|
||
# the next element is i+1
|
||
</span></code></pre></div></div>
|
||
|
||
<!-- The next section is copied from the C++ style guide. -->
|
||
|
||
<p><a id="s3.8.6-punctuation-spelling-and-grammar"></a>
|
||
<a id="386-punctuation-spelling-and-grammar"></a>
|
||
<a id="spelling"></a>
|
||
<a id="punctuation"></a>
|
||
<a id="grammar"></a></p>
|
||
|
||
<p><a id="punctuation-spelling-grammar"></a></p>
|
||
<h4 id="386-punctuation-spelling-and-grammar">3.8.6 Punctuation, Spelling, and Grammar</h4>
|
||
|
||
<p>Pay attention to punctuation, spelling, and grammar; it is easier to read
|
||
well-written comments than badly written ones.</p>
|
||
|
||
<p>Comments should be as readable as narrative text, with proper capitalization and
|
||
punctuation. In many cases, complete sentences are more readable than sentence
|
||
fragments. Shorter comments, such as comments at the end of a line of code, can
|
||
sometimes be less formal, but you should be consistent with your style.</p>
|
||
|
||
<p>Although it can be frustrating to have a code reviewer point out that you are
|
||
using a comma when you should be using a semicolon, it is very important that
|
||
source code maintain a high level of clarity and readability. Proper
|
||
punctuation, spelling, and grammar help with that goal.</p>
|
||
|
||
<p><a id="s3.10-strings"></a>
|
||
<a id="310-strings"></a></p>
|
||
|
||
<p><a id="strings"></a></p>
|
||
<h3 id="310-strings">3.10 Strings</h3>
|
||
|
||
<p>Use an
|
||
<a href="https://docs.python.org/3/reference/lexical_analysis.html#f-strings">f-string</a>,
|
||
the <code class="language-plaintext highlighter-rouge">%</code> operator, or the <code class="language-plaintext highlighter-rouge">format</code> method for formatting strings, even when the
|
||
parameters are all strings. Use your best judgment to decide between string
|
||
formatting options. A single join with <code class="language-plaintext highlighter-rouge">+</code> is okay but do not format with <code class="language-plaintext highlighter-rouge">+</code>.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span> <span class="n">x</span> <span class="o">=</span> <span class="sa">f</span><span class="s">'name: </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s">; score: </span><span class="si">{</span><span class="n">n</span><span class="si">}</span><span class="s">'</span>
|
||
<span class="n">x</span> <span class="o">=</span> <span class="s">'%s, %s!'</span> <span class="o">%</span> <span class="p">(</span><span class="n">imperative</span><span class="p">,</span> <span class="n">expletive</span><span class="p">)</span>
|
||
<span class="n">x</span> <span class="o">=</span> <span class="s">'{}, {}'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">first</span><span class="p">,</span> <span class="n">second</span><span class="p">)</span>
|
||
<span class="n">x</span> <span class="o">=</span> <span class="s">'name: %s; score: %d'</span> <span class="o">%</span> <span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span>
|
||
<span class="n">x</span> <span class="o">=</span> <span class="s">'name: %(name)s; score: %(score)d'</span> <span class="o">%</span> <span class="p">{</span><span class="s">'name'</span><span class="p">:</span><span class="n">name</span><span class="p">,</span> <span class="s">'score'</span><span class="p">:</span><span class="n">n</span><span class="p">}</span>
|
||
<span class="n">x</span> <span class="o">=</span> <span class="s">'name: {}; score: {}'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span>
|
||
<span class="n">x</span> <span class="o">=</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span> <span class="n">x</span> <span class="o">=</span> <span class="n">first</span> <span class="o">+</span> <span class="s">', '</span> <span class="o">+</span> <span class="n">second</span>
|
||
<span class="n">x</span> <span class="o">=</span> <span class="s">'name: '</span> <span class="o">+</span> <span class="n">name</span> <span class="o">+</span> <span class="s">'; score: '</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>Avoid using the <code class="language-plaintext highlighter-rouge">+</code> and <code class="language-plaintext highlighter-rouge">+=</code> operators to accumulate a string within a loop. In
|
||
some conditions, accumulating a string with addition can lead to quadratic
|
||
rather than linear running time. Although common accumulations of this sort may
|
||
be optimized on CPython, that is an implementation detail. The conditions under
|
||
which an optimization applies are not easy to predict and may change. Instead,
|
||
add each substring to a list and <code class="language-plaintext highlighter-rouge">''.join</code> the list after the loop terminates,
|
||
or write each substring to an <code class="language-plaintext highlighter-rouge">io.StringIO</code> buffer. These techniques
|
||
consistently have amortized-linear run-time complexity.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span> <span class="n">items</span> <span class="o">=</span> <span class="p">[</span><span class="s">'<table>'</span><span class="p">]</span>
|
||
<span class="k">for</span> <span class="n">last_name</span><span class="p">,</span> <span class="n">first_name</span> <span class="ow">in</span> <span class="n">employee_list</span><span class="p">:</span>
|
||
<span class="n">items</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="s">'<tr><td>%s, %s</td></tr>'</span> <span class="o">%</span> <span class="p">(</span><span class="n">last_name</span><span class="p">,</span> <span class="n">first_name</span><span class="p">))</span>
|
||
<span class="n">items</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="s">'</table>'</span><span class="p">)</span>
|
||
<span class="n">employee_table</span> <span class="o">=</span> <span class="s">''</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">items</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span> <span class="n">employee_table</span> <span class="o">=</span> <span class="s">'<table>'</span>
|
||
<span class="k">for</span> <span class="n">last_name</span><span class="p">,</span> <span class="n">first_name</span> <span class="ow">in</span> <span class="n">employee_list</span><span class="p">:</span>
|
||
<span class="n">employee_table</span> <span class="o">+=</span> <span class="s">'<tr><td>%s, %s</td></tr>'</span> <span class="o">%</span> <span class="p">(</span><span class="n">last_name</span><span class="p">,</span> <span class="n">first_name</span><span class="p">)</span>
|
||
<span class="n">employee_table</span> <span class="o">+=</span> <span class="s">'</table>'</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>Be consistent with your choice of string quote character within a file. Pick <code class="language-plaintext highlighter-rouge">'</code>
|
||
or <code class="language-plaintext highlighter-rouge">"</code> and stick with it. It is okay to use the other quote character on a
|
||
string to avoid the need to backslash-escape quote characters within the string.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span>
|
||
<span class="n">Python</span><span class="p">(</span><span class="s">'Why are you hiding your eyes?'</span><span class="p">)</span>
|
||
<span class="n">Gollum</span><span class="p">(</span><span class="s">"I'm scared of lint errors."</span><span class="p">)</span>
|
||
<span class="n">Narrator</span><span class="p">(</span><span class="s">'"Good!" thought a happy Python reviewer.'</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span>
|
||
<span class="n">Python</span><span class="p">(</span><span class="s">"Why are you hiding your eyes?"</span><span class="p">)</span>
|
||
<span class="n">Gollum</span><span class="p">(</span><span class="s">'The lint. It burns. It burns us.'</span><span class="p">)</span>
|
||
<span class="n">Gollum</span><span class="p">(</span><span class="s">"Always the great lint. Watching. Watching."</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>Prefer <code class="language-plaintext highlighter-rouge">"""</code> for multi-line strings rather than <code class="language-plaintext highlighter-rouge">'''</code>. Projects may choose to
|
||
use <code class="language-plaintext highlighter-rouge">'''</code> for all non-docstring multi-line strings if and only if they also use
|
||
<code class="language-plaintext highlighter-rouge">'</code> for regular strings. Docstrings must use <code class="language-plaintext highlighter-rouge">"""</code> regardless.</p>
|
||
|
||
<p>Multi-line strings do not flow with the indentation of the rest of the program.
|
||
If you need to avoid embedding extra space in the string, use either
|
||
concatenated single-line strings or a multi-line string with
|
||
<a href="https://docs.python.org/3/library/textwrap.html#textwrap.dedent"><code class="language-plaintext highlighter-rouge">textwrap.dedent()</code></a>
|
||
to remove the initial space on each line:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">No</span><span class="p">:</span>
|
||
<span class="n">long_string</span> <span class="o">=</span> <span class="s">"""This is pretty ugly.
|
||
Don't do this.
|
||
"""</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">Yes</span><span class="p">:</span>
|
||
<span class="n">long_string</span> <span class="o">=</span> <span class="s">"""This is fine if your use case can accept
|
||
extraneous leading spaces."""</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">Yes</span><span class="p">:</span>
|
||
<span class="n">long_string</span> <span class="o">=</span> <span class="p">(</span><span class="s">"And this is fine if you cannot accept</span><span class="se">\n</span><span class="s">"</span> <span class="o">+</span>
|
||
<span class="s">"extraneous leading spaces."</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">Yes</span><span class="p">:</span>
|
||
<span class="n">long_string</span> <span class="o">=</span> <span class="p">(</span><span class="s">"And this too is fine if you cannot accept</span><span class="se">\n</span><span class="s">"</span>
|
||
<span class="s">"extraneous leading spaces."</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">Yes</span><span class="p">:</span>
|
||
<span class="kn">import</span> <span class="nn">textwrap</span>
|
||
|
||
<span class="n">long_string</span> <span class="o">=</span> <span class="n">textwrap</span><span class="p">.</span><span class="n">dedent</span><span class="p">(</span><span class="s">"""</span><span class="se">\
|
||
</span><span class="s"> This is also fine, because textwrap.dedent()
|
||
will collapse common leading spaces in each line."""</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>Note that using a backslash here does not violate the prohibition against
|
||
<a href="#line-length">explicit line continuation</a>; in this case, the backslash is
|
||
<a href="https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals">escaping a newline</a>
|
||
in a string literal.</p>
|
||
|
||
<p><a id="s3.10.1-logging"></a>
|
||
<a id="3101-logging"></a>
|
||
<a id="logging"></a></p>
|
||
|
||
<p><a id="logging"></a></p>
|
||
<h4 id="3101-logging">3.10.1 Logging</h4>
|
||
|
||
<p>For logging functions that expect a pattern-string (with %-placeholders) as
|
||
their first argument: Always call them with a string literal (not an f-string!)
|
||
as their first argument with pattern-parameters as subsequent arguments. Some
|
||
logging implementations collect the unexpanded pattern-string as a queryable
|
||
field. It also prevents spending time rendering a message that no logger is
|
||
configured to output.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">Yes</span><span class="p">:</span>
|
||
<span class="kn">import</span> <span class="nn">tensorflow</span> <span class="k">as</span> <span class="n">tf</span>
|
||
<span class="n">logger</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">get_logger</span><span class="p">()</span>
|
||
<span class="n">logger</span><span class="p">.</span><span class="n">info</span><span class="p">(</span><span class="s">'TensorFlow Version is: %s'</span><span class="p">,</span> <span class="n">tf</span><span class="p">.</span><span class="n">__version__</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">Yes</span><span class="p">:</span>
|
||
<span class="kn">import</span> <span class="nn">os</span>
|
||
<span class="kn">from</span> <span class="nn">absl</span> <span class="kn">import</span> <span class="n">logging</span>
|
||
|
||
<span class="n">logging</span><span class="p">.</span><span class="n">info</span><span class="p">(</span><span class="s">'Current $PAGER is: %s'</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">getenv</span><span class="p">(</span><span class="s">'PAGER'</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s">''</span><span class="p">))</span>
|
||
|
||
<span class="n">homedir</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">getenv</span><span class="p">(</span><span class="s">'HOME'</span><span class="p">)</span>
|
||
<span class="k">if</span> <span class="n">homedir</span> <span class="ow">is</span> <span class="bp">None</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">os</span><span class="p">.</span><span class="n">access</span><span class="p">(</span><span class="n">homedir</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">W_OK</span><span class="p">):</span>
|
||
<span class="n">logging</span><span class="p">.</span><span class="n">error</span><span class="p">(</span><span class="s">'Cannot write to home directory, $HOME=%r'</span><span class="p">,</span> <span class="n">homedir</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">No</span><span class="p">:</span>
|
||
<span class="kn">import</span> <span class="nn">os</span>
|
||
<span class="kn">from</span> <span class="nn">absl</span> <span class="kn">import</span> <span class="n">logging</span>
|
||
|
||
<span class="n">logging</span><span class="p">.</span><span class="n">info</span><span class="p">(</span><span class="s">'Current $PAGER is:'</span><span class="p">)</span>
|
||
<span class="n">logging</span><span class="p">.</span><span class="n">info</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">getenv</span><span class="p">(</span><span class="s">'PAGER'</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s">''</span><span class="p">))</span>
|
||
|
||
<span class="n">homedir</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">getenv</span><span class="p">(</span><span class="s">'HOME'</span><span class="p">)</span>
|
||
<span class="k">if</span> <span class="n">homedir</span> <span class="ow">is</span> <span class="bp">None</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">os</span><span class="p">.</span><span class="n">access</span><span class="p">(</span><span class="n">homedir</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">W_OK</span><span class="p">):</span>
|
||
<span class="n">logging</span><span class="p">.</span><span class="n">error</span><span class="p">(</span><span class="sa">f</span><span class="s">'Cannot write to home directory, $HOME=</span><span class="si">{</span><span class="n">homedir</span><span class="si">!r}</span><span class="s">'</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s3.10.2-error-messages"></a>
|
||
<a id="3102-error-messages"></a>
|
||
<a id="error-messages"></a></p>
|
||
|
||
<p><a id="error-messages"></a></p>
|
||
<h4 id="3102-error-messages">3.10.2 Error Messages</h4>
|
||
|
||
<p>Error messages (such as: message strings on exceptions like <code class="language-plaintext highlighter-rouge">ValueError</code>, or
|
||
messages shown to the user) should follow three guidelines:</p>
|
||
|
||
<ol>
|
||
<li>
|
||
<p>The message needs to precisely match the actual error condition.</p>
|
||
</li>
|
||
<li>
|
||
<p>Interpolated pieces need to always be clearly identifiable as such.</p>
|
||
</li>
|
||
<li>
|
||
<p>They should allow simple automated processing (e.g. grepping).</p>
|
||
</li>
|
||
</ol>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">Yes</span><span class="p">:</span>
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="mi">0</span> <span class="o"><=</span> <span class="n">p</span> <span class="o"><=</span> <span class="mi">1</span><span class="p">:</span>
|
||
<span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s">'Not a probability: </span><span class="si">{</span><span class="n">p</span><span class="o">=</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>
|
||
|
||
<span class="k">try</span><span class="p">:</span>
|
||
<span class="n">os</span><span class="p">.</span><span class="n">rmdir</span><span class="p">(</span><span class="n">workdir</span><span class="p">)</span>
|
||
<span class="k">except</span> <span class="nb">OSError</span> <span class="k">as</span> <span class="n">error</span><span class="p">:</span>
|
||
<span class="n">logging</span><span class="p">.</span><span class="n">warning</span><span class="p">(</span><span class="s">'Could not remove directory (reason: %r): %r'</span><span class="p">,</span>
|
||
<span class="n">error</span><span class="p">,</span> <span class="n">workdir</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">No</span><span class="p">:</span>
|
||
<span class="k">if</span> <span class="n">p</span> <span class="o"><</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">p</span> <span class="o">></span> <span class="mi">1</span><span class="p">:</span> <span class="c1"># PROBLEM: also false for float('nan')!
|
||
</span> <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s">'Not a probability: </span><span class="si">{</span><span class="n">p</span><span class="o">=</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>
|
||
|
||
<span class="k">try</span><span class="p">:</span>
|
||
<span class="n">os</span><span class="p">.</span><span class="n">rmdir</span><span class="p">(</span><span class="n">workdir</span><span class="p">)</span>
|
||
<span class="k">except</span> <span class="nb">OSError</span><span class="p">:</span>
|
||
<span class="c1"># PROBLEM: Message makes an assumption that might not be true:
|
||
</span> <span class="c1"># Deletion might have failed for some other reason, misleading
|
||
</span> <span class="c1"># whoever has to debug this.
|
||
</span> <span class="n">logging</span><span class="p">.</span><span class="n">warning</span><span class="p">(</span><span class="s">'Directory already was deleted: %s'</span><span class="p">,</span> <span class="n">workdir</span><span class="p">)</span>
|
||
|
||
<span class="k">try</span><span class="p">:</span>
|
||
<span class="n">os</span><span class="p">.</span><span class="n">rmdir</span><span class="p">(</span><span class="n">workdir</span><span class="p">)</span>
|
||
<span class="k">except</span> <span class="nb">OSError</span><span class="p">:</span>
|
||
<span class="c1"># PROBLEM: The message is harder to grep for than necessary, and
|
||
</span> <span class="c1"># not universally non-confusing for all possible values of `workdir`.
|
||
</span> <span class="c1"># Imagine someone calling a library function with such code
|
||
</span> <span class="c1"># using a name such as workdir = 'deleted'. The warning would read:
|
||
</span> <span class="c1"># "The deleted directory could not be deleted."
|
||
</span> <span class="n">logging</span><span class="p">.</span><span class="n">warning</span><span class="p">(</span><span class="s">'The %s directory could not be deleted.'</span><span class="p">,</span> <span class="n">workdir</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s3.11-files-sockets-closeables"></a>
|
||
<a id="s3.11-files-and-sockets"></a>
|
||
<a id="311-files-and-sockets"></a>
|
||
<a id="files-and-sockets"></a></p>
|
||
|
||
<p><a id="files"></a></p>
|
||
<h3 id="311-files-sockets-and-similar-stateful-resources">3.11 Files, Sockets, and similar Stateful Resources</h3>
|
||
|
||
<p>Explicitly close files and sockets when done with them. This rule naturally
|
||
extends to closeable resources that internally use sockets, such as database
|
||
connections, and also other resources that need to be closed down in a similar
|
||
fashion. To name only a few examples, this also includes
|
||
<a href="https://docs.python.org/3/library/mmap.html">mmap</a> mappings,
|
||
<a href="https://docs.h5py.org/en/stable/high/file.html">h5py File objects</a>, and
|
||
<a href="https://matplotlib.org/2.1.0/api/_as_gen/matplotlib.pyplot.close.html">matplotlib.pyplot figure windows</a>.</p>
|
||
|
||
<p>Leaving files, sockets or other such stateful objects open unnecessarily has
|
||
many downsides:</p>
|
||
|
||
<ul>
|
||
<li>They may consume limited system resources, such as file descriptors. Code
|
||
that deals with many such objects may exhaust those resources unnecessarily
|
||
if they’re not returned to the system promptly after use.</li>
|
||
<li>Holding files open may prevent other actions such as moving or deleting
|
||
them, or unmounting a filesystem.</li>
|
||
<li>Files and sockets that are shared throughout a program may inadvertently be
|
||
read from or written to after logically being closed. If they are actually
|
||
closed, attempts to read or write from them will raise exceptions, making
|
||
the problem known sooner.</li>
|
||
</ul>
|
||
|
||
<p>Furthermore, while files and sockets (and some similarly behaving resources) are
|
||
automatically closed when the object is destructed, coupling the lifetime of the
|
||
object to the state of the resource is poor practice:</p>
|
||
|
||
<ul>
|
||
<li>There are no guarantees as to when the runtime will actually invoke the
|
||
<code class="language-plaintext highlighter-rouge">__del__</code> method. Different Python implementations use different memory
|
||
management techniques, such as delayed garbage collection, which may
|
||
increase the object’s lifetime arbitrarily and indefinitely.</li>
|
||
<li>Unexpected references to the file, e.g. in globals or exception tracebacks,
|
||
may keep it around longer than intended.</li>
|
||
</ul>
|
||
|
||
<p>Relying on finalizers to do automatic cleanup that has observable side effects
|
||
has been rediscovered over and over again to lead to major problems, across many
|
||
decades and multiple languages (see e.g.
|
||
<a href="https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers">this article</a>
|
||
for Java).</p>
|
||
|
||
<p>The preferred way to manage files and similar resources is using the
|
||
<a href="http://docs.python.org/reference/compound_stmts.html#the-with-statement"><code class="language-plaintext highlighter-rouge">with</code> statement</a>:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"hello.txt"</span><span class="p">)</span> <span class="k">as</span> <span class="n">hello_file</span><span class="p">:</span>
|
||
<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">hello_file</span><span class="p">:</span>
|
||
<span class="k">print</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>For file-like objects that do not support the <code class="language-plaintext highlighter-rouge">with</code> statement, use
|
||
<code class="language-plaintext highlighter-rouge">contextlib.closing()</code>:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">contextlib</span>
|
||
|
||
<span class="k">with</span> <span class="n">contextlib</span><span class="p">.</span><span class="n">closing</span><span class="p">(</span><span class="n">urllib</span><span class="p">.</span><span class="n">urlopen</span><span class="p">(</span><span class="s">"http://www.python.org/"</span><span class="p">))</span> <span class="k">as</span> <span class="n">front_page</span><span class="p">:</span>
|
||
<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">front_page</span><span class="p">:</span>
|
||
<span class="k">print</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>In rare cases where context-based resource management is infeasible, code
|
||
documentation must explain clearly how resource lifetime is managed.</p>
|
||
|
||
<p><a id="s3.12-todo-comments"></a>
|
||
<a id="312-todo-comments"></a></p>
|
||
|
||
<p><a id="todo"></a></p>
|
||
<h3 id="312-todo-comments">3.12 TODO Comments</h3>
|
||
|
||
<p>Use <code class="language-plaintext highlighter-rouge">TODO</code> comments for code that is temporary, a short-term solution, or
|
||
good-enough but not perfect.</p>
|
||
|
||
<p>A <code class="language-plaintext highlighter-rouge">TODO</code> comment begins with the word <code class="language-plaintext highlighter-rouge">TODO</code> in all caps, a following colon, and
|
||
a link to a resource that contains the context, ideally a bug reference. A bug
|
||
reference is preferable because bugs are tracked and have follow-up comments.
|
||
Follow this piece of context with an explanatory string introduced with a hyphen
|
||
<code class="language-plaintext highlighter-rouge">-</code>.
|
||
The purpose is to have a consistent <code class="language-plaintext highlighter-rouge">TODO</code> format that can be searched to find
|
||
out how to get more details.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># TODO: crbug.com/192795 - Investigate cpufreq optimizations.
|
||
</span></code></pre></div></div>
|
||
|
||
<p>Old style, formerly recommended, but discouraged for use in new code:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># TODO(crbug.com/192795): Investigate cpufreq optimizations.
|
||
# TODO(yourusername): Use a "\*" here for concatenation operator.
|
||
</span></code></pre></div></div>
|
||
|
||
<p>Avoid adding TODOs that refer to an individual or team as the context:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># TODO: @yourusername - File an issue and use a '*' for repetition.
|
||
</span></code></pre></div></div>
|
||
|
||
<p>If your <code class="language-plaintext highlighter-rouge">TODO</code> is of the form “At a future date do something” make sure that you
|
||
either include a very specific date (“Fix by November 2009”) or a very specific
|
||
event (“Remove this code when all clients can handle XML responses.”) that
|
||
future code maintainers will comprehend. Issues are ideal for tracking this.</p>
|
||
|
||
<p><a id="s3.13-imports-formatting"></a>
|
||
<a id="313-imports-formatting"></a></p>
|
||
|
||
<p><a id="imports-formatting"></a></p>
|
||
<h3 id="313-imports-formatting">3.13 Imports formatting</h3>
|
||
|
||
<p>Imports should be on separate lines; there are
|
||
<a href="#typing-imports">exceptions for <code class="language-plaintext highlighter-rouge">typing</code> and <code class="language-plaintext highlighter-rouge">collections.abc</code> imports</a>.</p>
|
||
|
||
<p>E.g.:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span> <span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Mapping</span><span class="p">,</span> <span class="n">Sequence</span>
|
||
<span class="kn">import</span> <span class="nn">os</span>
|
||
<span class="kn">import</span> <span class="nn">sys</span>
|
||
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Any</span><span class="p">,</span> <span class="n">NewType</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span> <span class="kn">import</span> <span class="nn">os</span><span class="p">,</span> <span class="n">sys</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>Imports are always put at the top of the file, just after any module comments
|
||
and docstrings and before module globals and constants. Imports should be
|
||
grouped from most generic to least generic:</p>
|
||
|
||
<ol>
|
||
<li>
|
||
<p>Python future import statements. For example:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">annotations</span>
|
||
</code></pre></div> </div>
|
||
|
||
<p>See <a href="#from-future-imports">above</a> for more information about those.</p>
|
||
</li>
|
||
<li>
|
||
<p>Python standard library imports. For example:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">sys</span>
|
||
</code></pre></div> </div>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://pypi.org/">third-party</a> module
|
||
or package imports. For example:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">tensorflow</span> <span class="k">as</span> <span class="n">tf</span>
|
||
</code></pre></div> </div>
|
||
</li>
|
||
<li>
|
||
<p>Code repository
|
||
sub-package imports. For example:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">otherproject.ai</span> <span class="kn">import</span> <span class="n">mind</span>
|
||
</code></pre></div> </div>
|
||
</li>
|
||
<li>
|
||
<p><strong>Deprecated:</strong> application-specific imports that are part of the same
|
||
top-level
|
||
sub-package as this file. For example:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">myproject.backend.hgwells</span> <span class="kn">import</span> <span class="n">time_machine</span>
|
||
</code></pre></div> </div>
|
||
|
||
<p>You may find older Google Python Style code doing this, but it is no longer
|
||
required. <strong>New code is encouraged not to bother with this.</strong> Simply treat
|
||
application-specific sub-package imports the same as other sub-package
|
||
imports.</p>
|
||
</li>
|
||
</ol>
|
||
|
||
<p>Within each grouping, imports should be sorted lexicographically, ignoring case,
|
||
according to each module’s full package path (the <code class="language-plaintext highlighter-rouge">path</code> in <code class="language-plaintext highlighter-rouge">from path import
|
||
...</code>). Code may optionally place a blank line between import sections.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">collections</span>
|
||
<span class="kn">import</span> <span class="nn">queue</span>
|
||
<span class="kn">import</span> <span class="nn">sys</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">absl</span> <span class="kn">import</span> <span class="n">app</span>
|
||
<span class="kn">from</span> <span class="nn">absl</span> <span class="kn">import</span> <span class="n">flags</span>
|
||
<span class="kn">import</span> <span class="nn">bs4</span>
|
||
<span class="kn">import</span> <span class="nn">cryptography</span>
|
||
<span class="kn">import</span> <span class="nn">tensorflow</span> <span class="k">as</span> <span class="n">tf</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">book.genres</span> <span class="kn">import</span> <span class="n">scifi</span>
|
||
<span class="kn">from</span> <span class="nn">myproject.backend</span> <span class="kn">import</span> <span class="n">huxley</span>
|
||
<span class="kn">from</span> <span class="nn">myproject.backend.hgwells</span> <span class="kn">import</span> <span class="n">time_machine</span>
|
||
<span class="kn">from</span> <span class="nn">myproject.backend.state_machine</span> <span class="kn">import</span> <span class="n">main_loop</span>
|
||
<span class="kn">from</span> <span class="nn">otherproject.ai</span> <span class="kn">import</span> <span class="n">body</span>
|
||
<span class="kn">from</span> <span class="nn">otherproject.ai</span> <span class="kn">import</span> <span class="n">mind</span>
|
||
<span class="kn">from</span> <span class="nn">otherproject.ai</span> <span class="kn">import</span> <span class="n">soul</span>
|
||
|
||
<span class="c1"># Older style code may have these imports down here instead:
|
||
#from myproject.backend.hgwells import time_machine
|
||
#from myproject.backend.state_machine import main_loop
|
||
</span></code></pre></div></div>
|
||
|
||
<p><a id="s3.14-statements"></a>
|
||
<a id="314-statements"></a></p>
|
||
|
||
<p><a id="statements"></a></p>
|
||
<h3 id="314-statements">3.14 Statements</h3>
|
||
|
||
<p>Generally only one statement per line.</p>
|
||
|
||
<p>However, you may put the result of a test on the same line as the test only if
|
||
the entire statement fits on one line. In particular, you can never do so with
|
||
<code class="language-plaintext highlighter-rouge">try</code>/<code class="language-plaintext highlighter-rouge">except</code> since the <code class="language-plaintext highlighter-rouge">try</code> and <code class="language-plaintext highlighter-rouge">except</code> can’t both fit on the same line, and
|
||
you can only do so with an <code class="language-plaintext highlighter-rouge">if</code> if there is no <code class="language-plaintext highlighter-rouge">else</code>.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span>
|
||
|
||
<span class="k">if</span> <span class="n">foo</span><span class="p">:</span> <span class="n">bar</span><span class="p">(</span><span class="n">foo</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span>
|
||
|
||
<span class="k">if</span> <span class="n">foo</span><span class="p">:</span> <span class="n">bar</span><span class="p">(</span><span class="n">foo</span><span class="p">)</span>
|
||
<span class="k">else</span><span class="p">:</span> <span class="n">baz</span><span class="p">(</span><span class="n">foo</span><span class="p">)</span>
|
||
|
||
<span class="k">try</span><span class="p">:</span> <span class="n">bar</span><span class="p">(</span><span class="n">foo</span><span class="p">)</span>
|
||
<span class="k">except</span> <span class="nb">ValueError</span><span class="p">:</span> <span class="n">baz</span><span class="p">(</span><span class="n">foo</span><span class="p">)</span>
|
||
|
||
<span class="k">try</span><span class="p">:</span>
|
||
<span class="n">bar</span><span class="p">(</span><span class="n">foo</span><span class="p">)</span>
|
||
<span class="k">except</span> <span class="nb">ValueError</span><span class="p">:</span> <span class="n">baz</span><span class="p">(</span><span class="n">foo</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s3.15-accessors"></a>
|
||
<a id="s3.15-access-control"></a>
|
||
<a id="315-access-control"></a>
|
||
<a id="access-control"></a>
|
||
<a id="accessors"></a></p>
|
||
|
||
<p><a id="getters-and-setters"></a></p>
|
||
<h3 id="315-getters-and-setters">3.15 Getters and Setters</h3>
|
||
|
||
<p>Getter and setter functions (also called accessors and mutators) should be used
|
||
when they provide a meaningful role or behavior for getting or setting a
|
||
variable’s value.</p>
|
||
|
||
<p>In particular, they should be used when getting or setting the variable is
|
||
complex or the cost is significant, either currently or in a reasonable future.</p>
|
||
|
||
<p>If, for example, a pair of getters/setters simply read and write an internal
|
||
attribute, the internal attribute should be made public instead. By comparison,
|
||
if setting a variable means some state is invalidated or rebuilt, it should be a
|
||
setter function. The function invocation hints that a potentially non-trivial
|
||
operation is occurring. Alternatively, <a href="#properties">properties</a> may be an
|
||
option when simple logic is needed, or refactoring to no longer need getters and
|
||
setters.</p>
|
||
|
||
<p>Getters and setters should follow the <a href="#s3.16-naming">Naming</a> guidelines, such
|
||
as <code class="language-plaintext highlighter-rouge">get_foo()</code> and <code class="language-plaintext highlighter-rouge">set_foo()</code>.</p>
|
||
|
||
<p>If the past behavior allowed access through a property, do not bind the new
|
||
getter/setter functions to the property. Any code still attempting to access the
|
||
variable by the old method should break visibly so they are made aware of the
|
||
change in complexity.</p>
|
||
|
||
<p><a id="s3.16-naming"></a>
|
||
<a id="316-naming"></a></p>
|
||
|
||
<p><a id="naming"></a></p>
|
||
<h3 id="316-naming">3.16 Naming</h3>
|
||
|
||
<p><code class="language-plaintext highlighter-rouge">module_name</code>, <code class="language-plaintext highlighter-rouge">package_name</code>, <code class="language-plaintext highlighter-rouge">ClassName</code>, <code class="language-plaintext highlighter-rouge">method_name</code>, <code class="language-plaintext highlighter-rouge">ExceptionName</code>,
|
||
<code class="language-plaintext highlighter-rouge">function_name</code>, <code class="language-plaintext highlighter-rouge">GLOBAL_CONSTANT_NAME</code>, <code class="language-plaintext highlighter-rouge">global_var_name</code>, <code class="language-plaintext highlighter-rouge">instance_var_name</code>,
|
||
<code class="language-plaintext highlighter-rouge">function_parameter_name</code>, <code class="language-plaintext highlighter-rouge">local_var_name</code>, <code class="language-plaintext highlighter-rouge">query_proper_noun_for_thing</code>,
|
||
<code class="language-plaintext highlighter-rouge">send_acronym_via_https</code>.</p>
|
||
|
||
<p>Names should be descriptive. This includes functions, classes, variables,
|
||
attributes, files and any other type of named entities.</p>
|
||
|
||
<p>Avoid abbreviation. In particular, do not use abbreviations that are ambiguous
|
||
or unfamiliar to readers outside your project, and do not abbreviate by deleting
|
||
letters within a word.</p>
|
||
|
||
<p>Always use a <code class="language-plaintext highlighter-rouge">.py</code> filename extension. Never use dashes.</p>
|
||
|
||
<p><a id="s3.16.1-names-to-avoid"></a>
|
||
<a id="3161-names-to-avoid"></a></p>
|
||
|
||
<p><a id="names-to-avoid"></a></p>
|
||
<h4 id="3161-names-to-avoid">3.16.1 Names to Avoid</h4>
|
||
|
||
<ul>
|
||
<li>
|
||
<p>single character names, except for specifically allowed cases:</p>
|
||
|
||
<ul>
|
||
<li>counters or iterators (e.g. <code class="language-plaintext highlighter-rouge">i</code>, <code class="language-plaintext highlighter-rouge">j</code>, <code class="language-plaintext highlighter-rouge">k</code>, <code class="language-plaintext highlighter-rouge">v</code>, et al.)</li>
|
||
<li><code class="language-plaintext highlighter-rouge">e</code> as an exception identifier in <code class="language-plaintext highlighter-rouge">try/except</code> statements.</li>
|
||
<li><code class="language-plaintext highlighter-rouge">f</code> as a file handle in <code class="language-plaintext highlighter-rouge">with</code> statements</li>
|
||
<li>private <a href="#typing-type-var">type variables</a> with no constraints (e.g.
|
||
<code class="language-plaintext highlighter-rouge">_T = TypeVar("_T")</code>, <code class="language-plaintext highlighter-rouge">_P = ParamSpec("_P")</code>)</li>
|
||
<li>names that match established notation in a reference paper or algorithm
|
||
(see <a href="#math-notation">Mathematical Notation</a>)</li>
|
||
</ul>
|
||
|
||
<p>Please be mindful not to abuse single-character naming. Generally speaking,
|
||
descriptiveness should be proportional to the name’s scope of visibility.
|
||
For example, <code class="language-plaintext highlighter-rouge">i</code> might be a fine name for 5-line code block but within
|
||
multiple nested scopes, it is likely too vague.</p>
|
||
</li>
|
||
<li>
|
||
<p>dashes (<code class="language-plaintext highlighter-rouge">-</code>) in any package/module name</p>
|
||
</li>
|
||
<li>
|
||
<p><code class="language-plaintext highlighter-rouge">__double_leading_and_trailing_underscore__</code> names (reserved by Python)</p>
|
||
</li>
|
||
<li>
|
||
<p>offensive terms</p>
|
||
</li>
|
||
<li>
|
||
<p>names that needlessly include the type of the variable (for example:
|
||
<code class="language-plaintext highlighter-rouge">id_to_name_dict</code>)</p>
|
||
</li>
|
||
</ul>
|
||
|
||
<p><a id="s3.16.2-naming-conventions"></a>
|
||
<a id="3162-naming-convention"></a></p>
|
||
|
||
<p><a id="naming-conventions"></a></p>
|
||
<h4 id="3162-naming-conventions">3.16.2 Naming Conventions</h4>
|
||
|
||
<ul>
|
||
<li>
|
||
<p>“Internal” means internal to a module, or protected or private within a
|
||
class.</p>
|
||
</li>
|
||
<li>
|
||
<p>Prepending a single underscore (<code class="language-plaintext highlighter-rouge">_</code>) has some support for protecting module
|
||
variables and functions (linters will flag protected member access). Note
|
||
that it is okay for unit tests to access protected constants from the
|
||
modules under test.</p>
|
||
</li>
|
||
<li>
|
||
<p>Prepending a double underscore (<code class="language-plaintext highlighter-rouge">__</code> aka “dunder”) to an instance variable
|
||
or method effectively makes the variable or method private to its class
|
||
(using name mangling); we discourage its use as it impacts readability and
|
||
testability, and isn’t <em>really</em> private. Prefer a single underscore.</p>
|
||
</li>
|
||
<li>
|
||
<p>Place related classes and top-level functions together in a
|
||
module.
|
||
Unlike Java, there is no need to limit yourself to one class per module.</p>
|
||
</li>
|
||
<li>
|
||
<p>Use CapWords for class names, but lower_with_under.py for module names.
|
||
Although there are some old modules named CapWords.py, this is now
|
||
discouraged because it’s confusing when the module happens to be named after
|
||
a class. (“wait – did I write <code class="language-plaintext highlighter-rouge">import StringIO</code> or <code class="language-plaintext highlighter-rouge">from StringIO import
|
||
StringIO</code>?”)</p>
|
||
</li>
|
||
<li>
|
||
<p>New <em>unit test</em> files follow PEP 8 compliant lower_with_under method
|
||
names, for example, <code class="language-plaintext highlighter-rouge">test_<method_under_test>_<state></code>. For consistency(*)
|
||
with legacy modules that follow CapWords function names, underscores may
|
||
appear in method names starting with <code class="language-plaintext highlighter-rouge">test</code> to separate logical components
|
||
of the name. One possible pattern is <code class="language-plaintext highlighter-rouge">test<MethodUnderTest>_<state></code>.</p>
|
||
</li>
|
||
</ul>
|
||
|
||
<p><a id="s3.16.3-file-naming"></a>
|
||
<a id="3163-file-naming"></a></p>
|
||
|
||
<p><a id="file-naming"></a></p>
|
||
<h4 id="3163-file-naming">3.16.3 File Naming</h4>
|
||
|
||
<p>Python filenames must have a <code class="language-plaintext highlighter-rouge">.py</code> extension and must not contain dashes (<code class="language-plaintext highlighter-rouge">-</code>).
|
||
This allows them to be imported and unittested. If you want an executable to be
|
||
accessible without the extension, use a symbolic link or a simple bash wrapper
|
||
containing <code class="language-plaintext highlighter-rouge">exec "$0.py" "$@"</code>.</p>
|
||
|
||
<p><a id="s3.16.4-guidelines-derived-from-guidos-recommendations"></a>
|
||
<a id="3164-guidelines-derived-from-guidos-recommendations"></a></p>
|
||
|
||
<p><a id="guidelines-derived-from-guidos-recommendations"></a></p>
|
||
<h4 id="3164-guidelines-derived-from-guidos-recommendations">3.16.4 Guidelines derived from <a href="https://en.wikipedia.org/wiki/Guido_van_Rossum">Guido</a>’s Recommendations</h4>
|
||
|
||
<table rules="all" border="1" summary="Guidelines from Guido's Recommendations" cellspacing="2" cellpadding="2">
|
||
|
||
<tr>
|
||
<th>Type</th>
|
||
<th>Public</th>
|
||
<th>Internal</th>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td>Packages</td>
|
||
<td><code>lower_with_under</code></td>
|
||
<td></td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td>Modules</td>
|
||
<td><code>lower_with_under</code></td>
|
||
<td><code>_lower_with_under</code></td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td>Classes</td>
|
||
<td><code>CapWords</code></td>
|
||
<td><code>_CapWords</code></td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td>Exceptions</td>
|
||
<td><code>CapWords</code></td>
|
||
<td></td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td>Functions</td>
|
||
<td><code>lower_with_under()</code></td>
|
||
<td><code>_lower_with_under()</code></td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td>Global/Class Constants</td>
|
||
<td><code>CAPS_WITH_UNDER</code></td>
|
||
<td><code>_CAPS_WITH_UNDER</code></td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td>Global/Class Variables</td>
|
||
<td><code>lower_with_under</code></td>
|
||
<td><code>_lower_with_under</code></td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td>Instance Variables</td>
|
||
<td><code>lower_with_under</code></td>
|
||
<td><code>_lower_with_under</code> (protected)</td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td>Method Names</td>
|
||
<td><code>lower_with_under()</code></td>
|
||
<td><code>_lower_with_under()</code> (protected)</td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td>Function/Method Parameters</td>
|
||
<td><code>lower_with_under</code></td>
|
||
<td></td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td>Local Variables</td>
|
||
<td><code>lower_with_under</code></td>
|
||
<td></td>
|
||
</tr>
|
||
|
||
</table>
|
||
|
||
<p><a id="s3.17-main"></a>
|
||
<a id="317-main"></a></p>
|
||
|
||
<p><a id="math-notation"></a></p>
|
||
<h4 id="3165-mathematical-notation">3.16.5 Mathematical Notation</h4>
|
||
|
||
<p>For mathematically-heavy code, short variable names that would otherwise violate
|
||
the style guide are preferred when they match established notation in a
|
||
reference paper or algorithm.</p>
|
||
|
||
<p>When using names based on established notation:</p>
|
||
|
||
<ol>
|
||
<li>Cite the source of all naming conventions, preferably with a hyperlink to
|
||
academic resource itself, in a comment or docstring. If the source is not
|
||
accessible, clearly document the naming conventions.</li>
|
||
<li>Prefer PEP8-compliant <code class="language-plaintext highlighter-rouge">descriptive_names</code> for public APIs, which are much
|
||
more likely to be encountered out of context.</li>
|
||
<li>Use a narrowly-scoped <code class="language-plaintext highlighter-rouge">pylint: disable=invalid-name</code> directive to silence
|
||
warnings. For just a few variables, use the directive as an endline comment
|
||
for each one; for more, apply the directive at the beginning of a block.</li>
|
||
</ol>
|
||
|
||
<p><a id="main"></a></p>
|
||
<h3 id="317-main">3.17 Main</h3>
|
||
|
||
<p>In Python, <code class="language-plaintext highlighter-rouge">pydoc</code> as well as unit tests require modules to be importable. If a
|
||
file is meant to be used as an executable, its main functionality should be in a
|
||
<code class="language-plaintext highlighter-rouge">main()</code> function, and your code should always check <code class="language-plaintext highlighter-rouge">if __name__ == '__main__'</code>
|
||
before executing your main program, so that it is not executed when the module
|
||
is imported.</p>
|
||
|
||
<p>When using <a href="https://github.com/abseil/abseil-py">absl</a>, use <code class="language-plaintext highlighter-rouge">app.run</code>:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">absl</span> <span class="kn">import</span> <span class="n">app</span>
|
||
<span class="p">...</span>
|
||
|
||
<span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">argv</span><span class="p">:</span> <span class="n">Sequence</span><span class="p">[</span><span class="nb">str</span><span class="p">]):</span>
|
||
<span class="c1"># process non-flag arguments
|
||
</span> <span class="p">...</span>
|
||
|
||
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span>
|
||
<span class="n">app</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">main</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>Otherwise, use:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
|
||
<span class="p">...</span>
|
||
|
||
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span>
|
||
<span class="n">main</span><span class="p">()</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>All code at the top level will be executed when the module is imported. Be
|
||
careful not to call functions, create objects, or perform other operations that
|
||
should not be executed when the file is being <code class="language-plaintext highlighter-rouge">pydoc</code>ed.</p>
|
||
|
||
<p><a id="s3.18-function-length"></a>
|
||
<a id="318-function-length"></a></p>
|
||
|
||
<p><a id="function-length"></a></p>
|
||
<h3 id="318-function-length">3.18 Function length</h3>
|
||
|
||
<p>Prefer small and focused functions.</p>
|
||
|
||
<p>We recognize that long functions are sometimes appropriate, so no hard limit is
|
||
placed on function length. If a function exceeds about 40 lines, think about
|
||
whether it can be broken up without harming the structure of the program.</p>
|
||
|
||
<p>Even if your long function works perfectly now, someone modifying it in a few
|
||
months may add new behavior. This could result in bugs that are hard to find.
|
||
Keeping your functions short and simple makes it easier for other people to read
|
||
and modify your code.</p>
|
||
|
||
<p>You could find long and complicated functions when working with
|
||
some
|
||
code. Do not be intimidated by modifying existing code: if working with such a
|
||
function proves to be difficult, you find that errors are hard to debug, or you
|
||
want to use a piece of it in several different contexts, consider breaking up
|
||
the function into smaller and more manageable pieces.</p>
|
||
|
||
<p><a id="s3.19-type-annotations"></a>
|
||
<a id="319-type-annotations"></a></p>
|
||
|
||
<p><a id="type-annotations"></a></p>
|
||
<h3 id="319-type-annotations">3.19 Type Annotations</h3>
|
||
|
||
<p><a id="s3.19.1-general-rules"></a>
|
||
<a id="s3.19.1-general"></a>
|
||
<a id="3191-general-rules"></a></p>
|
||
|
||
<p><a id="typing-general"></a></p>
|
||
<h4 id="3191-general-rules">3.19.1 General Rules</h4>
|
||
|
||
<ul>
|
||
<li>
|
||
<p>Familiarize yourself with
|
||
<a href="https://docs.python.org/3/library/typing.html">type hints</a>.</p>
|
||
</li>
|
||
<li>
|
||
<p>Annotating <code class="language-plaintext highlighter-rouge">self</code> or <code class="language-plaintext highlighter-rouge">cls</code> is generally not necessary.
|
||
<a href="https://docs.python.org/3/library/typing.html#typing.Self"><code class="language-plaintext highlighter-rouge">Self</code></a> can be
|
||
used if it is necessary for proper type information, e.g.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Self</span>
|
||
|
||
<span class="k">class</span> <span class="nc">BaseClass</span><span class="p">:</span>
|
||
<span class="o">@</span><span class="nb">classmethod</span>
|
||
<span class="k">def</span> <span class="nf">create</span><span class="p">(</span><span class="n">cls</span><span class="p">)</span> <span class="o">-></span> <span class="n">Self</span><span class="p">:</span>
|
||
<span class="p">...</span>
|
||
|
||
<span class="k">def</span> <span class="nf">difference</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="n">Self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">float</span><span class="p">:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div> </div>
|
||
</li>
|
||
<li>
|
||
<p>Similarly, don’t feel compelled to annotate the return value of <code class="language-plaintext highlighter-rouge">__init__</code>
|
||
(where <code class="language-plaintext highlighter-rouge">None</code> is the only valid option).</p>
|
||
</li>
|
||
<li>
|
||
<p>If any other variable or a returned type should not be expressed, use <code class="language-plaintext highlighter-rouge">Any</code>.</p>
|
||
</li>
|
||
<li>
|
||
<p>You are not required to annotate all the functions in a module.</p>
|
||
|
||
<ul>
|
||
<li>At least annotate your public APIs.</li>
|
||
<li>Use judgment to get to a good balance between safety and clarity on the
|
||
one hand, and flexibility on the other.</li>
|
||
<li>Annotate code that is prone to type-related errors (previous bugs or
|
||
complexity).</li>
|
||
<li>Annotate code that is hard to understand.</li>
|
||
<li>Annotate code as it becomes stable from a types perspective. In many
|
||
cases, you can annotate all the functions in mature code without losing
|
||
too much flexibility.</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<p><a id="s3.19.2-line-breaking"></a>
|
||
<a id="3192-line-breaking"></a></p>
|
||
|
||
<p><a id="typing-line-breaking"></a></p>
|
||
<h4 id="3192-line-breaking">3.19.2 Line Breaking</h4>
|
||
|
||
<p>Try to follow the existing <a href="#indentation">indentation</a> rules.</p>
|
||
|
||
<p>After annotating, many function signatures will become “one parameter per line”.
|
||
To ensure the return type is also given its own line, a comma can be placed
|
||
after the last parameter.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">my_method</span><span class="p">(</span>
|
||
<span class="bp">self</span><span class="p">,</span>
|
||
<span class="n">first_var</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span>
|
||
<span class="n">second_var</span><span class="p">:</span> <span class="n">Foo</span><span class="p">,</span>
|
||
<span class="n">third_var</span><span class="p">:</span> <span class="n">Bar</span> <span class="o">|</span> <span class="bp">None</span><span class="p">,</span>
|
||
<span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>Always prefer breaking between variables, and not, for example, between variable
|
||
names and type annotations. However, if everything fits on the same line, go for
|
||
it.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">my_method</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">first_var</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>If the combination of the function name, the last parameter, and the return type
|
||
is too long, indent by 4 in a new line. When using line breaks, prefer putting
|
||
each parameter and the return type on their own lines and aligning the closing
|
||
parenthesis with the <code class="language-plaintext highlighter-rouge">def</code>:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">my_method</span><span class="p">(</span>
|
||
<span class="bp">self</span><span class="p">,</span>
|
||
<span class="n">other_arg</span><span class="p">:</span> <span class="n">MyLongType</span> <span class="o">|</span> <span class="bp">None</span><span class="p">,</span>
|
||
<span class="p">)</span> <span class="o">-></span> <span class="nb">tuple</span><span class="p">[</span><span class="n">MyLongType1</span><span class="p">,</span> <span class="n">MyLongType1</span><span class="p">]:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>Optionally, the return type may be put on the same line as the last parameter:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Okay</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">my_method</span><span class="p">(</span>
|
||
<span class="bp">self</span><span class="p">,</span>
|
||
<span class="n">first_var</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span>
|
||
<span class="n">second_var</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="nb">dict</span><span class="p">[</span><span class="n">OtherLongType</span><span class="p">,</span> <span class="n">MyLongType</span><span class="p">]:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><code class="language-plaintext highlighter-rouge">pylint</code>
|
||
allows you to move the closing parenthesis to a new line and align with the
|
||
opening one, but this is less readable.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">my_method</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span>
|
||
<span class="n">other_arg</span><span class="p">:</span> <span class="n">MyLongType</span> <span class="o">|</span> <span class="bp">None</span><span class="p">,</span>
|
||
<span class="p">)</span> <span class="o">-></span> <span class="nb">dict</span><span class="p">[</span><span class="n">OtherLongType</span><span class="p">,</span> <span class="n">MyLongType</span><span class="p">]:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>As in the examples above, prefer not to break types. However, sometimes they are
|
||
too long to be on a single line (try to keep sub-types unbroken).</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">my_method</span><span class="p">(</span>
|
||
<span class="bp">self</span><span class="p">,</span>
|
||
<span class="n">first_var</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">list</span><span class="p">[</span><span class="n">MyLongType1</span><span class="p">],</span>
|
||
<span class="nb">list</span><span class="p">[</span><span class="n">MyLongType2</span><span class="p">]],</span>
|
||
<span class="n">second_var</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">dict</span><span class="p">[</span>
|
||
<span class="n">MyLongType3</span><span class="p">,</span> <span class="n">MyLongType4</span><span class="p">]],</span>
|
||
<span class="p">)</span> <span class="o">-></span> <span class="bp">None</span><span class="p">:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>If a single name and type is too long, consider using an
|
||
<a href="#typing-aliases">alias</a> for the type. The last resort is to break after the
|
||
colon and indent by 4.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">my_function</span><span class="p">(</span>
|
||
<span class="n">long_variable_name</span><span class="p">:</span>
|
||
<span class="n">long_module_name</span><span class="p">.</span><span class="n">LongTypeName</span><span class="p">,</span>
|
||
<span class="p">)</span> <span class="o">-></span> <span class="bp">None</span><span class="p">:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">my_function</span><span class="p">(</span>
|
||
<span class="n">long_variable_name</span><span class="p">:</span> <span class="n">long_module_name</span><span class="p">.</span>
|
||
<span class="n">LongTypeName</span><span class="p">,</span>
|
||
<span class="p">)</span> <span class="o">-></span> <span class="bp">None</span><span class="p">:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s3.19.3-forward-declarations"></a>
|
||
<a id="3193-forward-declarations"></a></p>
|
||
|
||
<p><a id="forward-declarations"></a></p>
|
||
<h4 id="3193-forward-declarations">3.19.3 Forward Declarations</h4>
|
||
|
||
<p>If you need to use a class name (from the same module) that is not yet
|
||
defined – for example, if you need the class name inside the declaration of
|
||
that class, or if you use a class that is defined later in the code – either
|
||
use <code class="language-plaintext highlighter-rouge">from __future__ import annotations</code> or use a string for the class name.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span>
|
||
<span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">annotations</span>
|
||
|
||
<span class="k">class</span> <span class="nc">MyClass</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">stack</span><span class="p">:</span> <span class="n">Sequence</span><span class="p">[</span><span class="n">MyClass</span><span class="p">],</span> <span class="n">item</span><span class="p">:</span> <span class="n">OtherClass</span><span class="p">)</span> <span class="o">-></span> <span class="bp">None</span><span class="p">:</span>
|
||
|
||
<span class="k">class</span> <span class="nc">OtherClass</span><span class="p">:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span>
|
||
<span class="k">class</span> <span class="nc">MyClass</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">stack</span><span class="p">:</span> <span class="n">Sequence</span><span class="p">[</span><span class="s">'MyClass'</span><span class="p">],</span> <span class="n">item</span><span class="p">:</span> <span class="s">'OtherClass'</span><span class="p">)</span> <span class="o">-></span> <span class="bp">None</span><span class="p">:</span>
|
||
|
||
<span class="k">class</span> <span class="nc">OtherClass</span><span class="p">:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s3.19.4-default-values"></a>
|
||
<a id="3194-default-values"></a></p>
|
||
|
||
<p><a id="typing-default-values"></a></p>
|
||
<h4 id="3194-default-values">3.19.4 Default Values</h4>
|
||
|
||
<p>As per <a href="https://peps.python.org/pep-0008/#other-recommendations">PEP-008</a>, use
|
||
spaces around the <code class="language-plaintext highlighter-rouge">=</code> <em>only</em> for arguments that have both a type annotation and
|
||
a default value.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span><span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="n">a</span><span class="p">:</span><span class="nb">int</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s3.19.5-nonetype"></a>
|
||
<a id="s3.19.5-none-type"></a>
|
||
<a id="3195-nonetype"></a></p>
|
||
|
||
<p><a id="none-type"></a></p>
|
||
<h4 id="3195-nonetype">3.19.5 NoneType</h4>
|
||
|
||
<p>In the Python type system, <code class="language-plaintext highlighter-rouge">NoneType</code> is a “first class” type, and for typing
|
||
purposes, <code class="language-plaintext highlighter-rouge">None</code> is an alias for <code class="language-plaintext highlighter-rouge">NoneType</code>. If an argument can be <code class="language-plaintext highlighter-rouge">None</code>, it
|
||
has to be declared! You can use <code class="language-plaintext highlighter-rouge">|</code> union type expressions (recommended in new
|
||
Python 3.10+ code), or the older <code class="language-plaintext highlighter-rouge">Optional</code> and <code class="language-plaintext highlighter-rouge">Union</code> syntaxes.</p>
|
||
|
||
<p>Use explicit <code class="language-plaintext highlighter-rouge">X | None</code> instead of implicit. Earlier versions of type checkers
|
||
allowed <code class="language-plaintext highlighter-rouge">a: str = None</code> to be interpreted as <code class="language-plaintext highlighter-rouge">a: str | None = None</code>, but that is
|
||
no longer the preferred behavior.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">modern_or_union</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="nb">int</span> <span class="o">|</span> <span class="bp">None</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="bp">None</span> <span class="o">=</span> <span class="bp">None</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
||
<span class="p">...</span>
|
||
<span class="k">def</span> <span class="nf">union_optional</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="bp">None</span><span class="p">],</span> <span class="n">b</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="bp">None</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">nullable_union</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="bp">None</span><span class="p">,</span> <span class="nb">str</span><span class="p">])</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
||
<span class="p">...</span>
|
||
<span class="k">def</span> <span class="nf">implicit_optional</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="bp">None</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s3.19.6-type-aliases"></a>
|
||
<a id="s3.19.6-aliases"></a>
|
||
<a id="3196-type-aliases"></a>
|
||
<a id="typing-aliases"></a></p>
|
||
|
||
<p><a id="type-aliases"></a></p>
|
||
<h4 id="3196-type-aliases">3.19.6 Type Aliases</h4>
|
||
|
||
<p>You can declare aliases of complex types. The name of an alias should be
|
||
CapWorded. If the alias is used only in this module, it should be _Private.</p>
|
||
|
||
<p>Note that the <code class="language-plaintext highlighter-rouge">: TypeAlias</code> annotation is only supported in versions 3.10+.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TypeAlias</span>
|
||
|
||
<span class="n">_LossAndGradient</span><span class="p">:</span> <span class="n">TypeAlias</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">[</span><span class="n">tf</span><span class="p">.</span><span class="n">Tensor</span><span class="p">,</span> <span class="n">tf</span><span class="p">.</span><span class="n">Tensor</span><span class="p">]</span>
|
||
<span class="n">ComplexTFMap</span><span class="p">:</span> <span class="n">TypeAlias</span> <span class="o">=</span> <span class="n">Mapping</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">_LossAndGradient</span><span class="p">]</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s3.19.7-ignoring-types"></a>
|
||
<a id="s3.19.7-ignore"></a>
|
||
<a id="3197-ignoring-types"></a></p>
|
||
|
||
<p><a id="typing-ignore"></a></p>
|
||
<h4 id="3197-ignoring-types">3.19.7 Ignoring Types</h4>
|
||
|
||
<p>You can disable type checking on a line with the special comment <code class="language-plaintext highlighter-rouge"># type:
|
||
ignore</code>.</p>
|
||
|
||
<p><code class="language-plaintext highlighter-rouge">pytype</code> has a disable option for specific errors (similar to lint):</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># pytype: disable=attribute-error
|
||
</span></code></pre></div></div>
|
||
|
||
<p><a id="s3.19.8-typing-variables"></a>
|
||
<a id="s3.19.8-comments"></a>
|
||
<a id="3198-typing-internal-variables"></a></p>
|
||
|
||
<p><a id="typing-variables"></a></p>
|
||
<h4 id="3198-typing-variables">3.19.8 Typing Variables</h4>
|
||
|
||
<dl>
|
||
<dt><a id="annotated-assignments"></a></dt>
|
||
<dt><a href="#annotated-assignments"><em>Annotated Assignments</em></a></dt>
|
||
<dd>If an internal variable has a type that is hard or impossible to infer,
|
||
specify its type with an annotated assignment - use a colon and type between
|
||
the variable name and value (the same as is done with function arguments
|
||
that have a default value):
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">a</span><span class="p">:</span> <span class="n">Foo</span> <span class="o">=</span> <span class="n">SomeUndecoratedFunction</span><span class="p">()</span>
|
||
</code></pre></div> </div>
|
||
</dd>
|
||
<dt><a id="type-comments"></a></dt>
|
||
<dt><a href="#type-comments"><em>Type Comments</em></a></dt>
|
||
<dd>Though you may see them remaining in the codebase (they were necessary
|
||
before Python 3.6), do not add any more uses of a <code class="language-plaintext highlighter-rouge"># type: <type name></code>
|
||
comment on the end of the line:
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">a</span> <span class="o">=</span> <span class="n">SomeUndecoratedFunction</span><span class="p">()</span> <span class="c1"># type: Foo
|
||
</span></code></pre></div> </div>
|
||
</dd>
|
||
</dl>
|
||
|
||
<p><a id="s3.19.9-tuples-vs-lists"></a>
|
||
<a id="s3.19.9-tuples"></a>
|
||
<a id="3199-tuples-vs-lists"></a></p>
|
||
|
||
<p><a id="typing-tuples"></a></p>
|
||
<h4 id="3199-tuples-vs-lists">3.19.9 Tuples vs Lists</h4>
|
||
|
||
<p>Typed lists can only contain objects of a single type. Typed tuples can either
|
||
have a single repeated type or a set number of elements with different types.
|
||
The latter is commonly used as the return type from a function.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">a</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>
|
||
<span class="n">b</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="p">...]</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
|
||
<span class="n">c</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">str</span><span class="p">,</span> <span class="nb">float</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">"2"</span><span class="p">,</span> <span class="mf">3.5</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s3.19.10-typevars"></a>
|
||
<a id="s3.19.10-type-var"></a>
|
||
<a id="31910-typevar"></a>
|
||
<a id="typing-type-var"></a></p>
|
||
|
||
<p><a id="typevars"></a></p>
|
||
<h4 id="31910-type-variables">3.19.10 Type variables</h4>
|
||
|
||
<p>The Python type system has
|
||
<a href="https://docs.python.org/3/library/typing.html#generics">generics</a>. A type
|
||
variable, such as <code class="language-plaintext highlighter-rouge">TypeVar</code> and <code class="language-plaintext highlighter-rouge">ParamSpec</code>, is a common way to use them.</p>
|
||
|
||
<p>Example:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Callable</span>
|
||
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">ParamSpec</span><span class="p">,</span> <span class="n">TypeVar</span>
|
||
<span class="n">_P</span> <span class="o">=</span> <span class="n">ParamSpec</span><span class="p">(</span><span class="s">"_P"</span><span class="p">)</span>
|
||
<span class="n">_T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s">"_T"</span><span class="p">)</span>
|
||
<span class="p">...</span>
|
||
<span class="k">def</span> <span class="nf">next</span><span class="p">(</span><span class="n">l</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">_T</span><span class="p">])</span> <span class="o">-></span> <span class="n">_T</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="n">l</span><span class="p">.</span><span class="n">pop</span><span class="p">()</span>
|
||
|
||
<span class="k">def</span> <span class="nf">print_when_called</span><span class="p">(</span><span class="n">f</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[</span><span class="n">_P</span><span class="p">,</span> <span class="n">_T</span><span class="p">])</span> <span class="o">-></span> <span class="n">Callable</span><span class="p">[</span><span class="n">_P</span><span class="p">,</span> <span class="n">_T</span><span class="p">]:</span>
|
||
<span class="k">def</span> <span class="nf">inner</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">:</span> <span class="n">_P</span><span class="p">.</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">:</span> <span class="n">_P</span><span class="p">.</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="n">_T</span><span class="p">:</span>
|
||
<span class="k">print</span><span class="p">(</span><span class="s">"Function was called"</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="n">f</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="n">inner</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>A <code class="language-plaintext highlighter-rouge">TypeVar</code> can be constrained:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">AddableType</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s">"AddableType"</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="nb">float</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
|
||
<span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="n">AddableType</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="n">AddableType</span><span class="p">)</span> <span class="o">-></span> <span class="n">AddableType</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>A common predefined type variable in the <code class="language-plaintext highlighter-rouge">typing</code> module is <code class="language-plaintext highlighter-rouge">AnyStr</code>. Use it for
|
||
multiple annotations that can be <code class="language-plaintext highlighter-rouge">bytes</code> or <code class="language-plaintext highlighter-rouge">str</code> and must all be the same type.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">AnyStr</span>
|
||
<span class="k">def</span> <span class="nf">check_length</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="n">AnyStr</span><span class="p">)</span> <span class="o">-></span> <span class="n">AnyStr</span><span class="p">:</span>
|
||
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o"><=</span> <span class="mi">42</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="n">x</span>
|
||
<span class="k">raise</span> <span class="nb">ValueError</span><span class="p">()</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>A type variable must have a descriptive name, unless it meets all of the
|
||
following criteria:</p>
|
||
|
||
<ul>
|
||
<li>not externally visible</li>
|
||
<li>not constrained</li>
|
||
</ul>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Yes</span><span class="p">:</span>
|
||
<span class="n">_T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s">"_T"</span><span class="p">)</span>
|
||
<span class="n">_P</span> <span class="o">=</span> <span class="n">ParamSpec</span><span class="p">(</span><span class="s">"_P"</span><span class="p">)</span>
|
||
<span class="n">AddableType</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s">"AddableType"</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="nb">float</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
|
||
<span class="n">AnyFunction</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s">"AnyFunction"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="n">Callable</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">No</span><span class="p">:</span>
|
||
<span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s">"T"</span><span class="p">)</span>
|
||
<span class="n">P</span> <span class="o">=</span> <span class="n">ParamSpec</span><span class="p">(</span><span class="s">"P"</span><span class="p">)</span>
|
||
<span class="n">_T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s">"_T"</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="nb">float</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
|
||
<span class="n">_F</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s">"_F"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="n">Callable</span><span class="p">)</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s3.19.11-string-types"></a>
|
||
<a id="s3.19.11-strings"></a>
|
||
<a id="31911-string-types"></a></p>
|
||
|
||
<p><a id="typing-strings"></a></p>
|
||
<h4 id="31911-string-types">3.19.11 String types</h4>
|
||
|
||
<blockquote>
|
||
<p>Do not use <code class="language-plaintext highlighter-rouge">typing.Text</code> in new code. It’s only for Python 2/3 compatibility.</p>
|
||
</blockquote>
|
||
|
||
<p>Use <code class="language-plaintext highlighter-rouge">str</code> for string/text data. For code that deals with binary data, use
|
||
<code class="language-plaintext highlighter-rouge">bytes</code>.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">deals_with_text_data</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
||
<span class="p">...</span>
|
||
<span class="k">def</span> <span class="nf">deals_with_binary_data</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">)</span> <span class="o">-></span> <span class="nb">bytes</span><span class="p">:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>If all the string types of a function are always the same, for example if the
|
||
return type is the same as the argument type in the code above, use
|
||
<a href="#typing-type-var">AnyStr</a>.</p>
|
||
|
||
<p><a id="s3.19.12-imports-for-typing"></a>
|
||
<a id="s3.19.12-imports"></a>
|
||
<a id="31912-imports-for-typing"></a></p>
|
||
|
||
<p><a id="typing-imports"></a></p>
|
||
<h4 id="31912-imports-for-typing">3.19.12 Imports For Typing</h4>
|
||
|
||
<p>For symbols (including types, functions, and constants) from the <code class="language-plaintext highlighter-rouge">typing</code> or
|
||
<code class="language-plaintext highlighter-rouge">collections.abc</code> modules used to support static analysis and type checking,
|
||
always import the symbol itself. This keeps common annotations more concise and
|
||
matches typing practices used around the world. You are explicitly allowed to
|
||
import multiple specific symbols on one line from the <code class="language-plaintext highlighter-rouge">typing</code> and
|
||
<code class="language-plaintext highlighter-rouge">collections.abc</code> modules. For example:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Mapping</span><span class="p">,</span> <span class="n">Sequence</span>
|
||
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Generic</span><span class="p">,</span> <span class="n">cast</span><span class="p">,</span> <span class="n">TYPE_CHECKING</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>Given that this way of importing adds items to the local namespace, names in
|
||
<code class="language-plaintext highlighter-rouge">typing</code> or <code class="language-plaintext highlighter-rouge">collections.abc</code> should be treated similarly to keywords, and not
|
||
be defined in your Python code, typed or not. If there is a collision between a
|
||
type and an existing name in a module, import it using <code class="language-plaintext highlighter-rouge">import x as y</code>.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Any</span> <span class="k">as</span> <span class="n">AnyType</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>When annotating function signatures, prefer abstract container types like
|
||
<code class="language-plaintext highlighter-rouge">collections.abc.Sequence</code> over concrete types like <code class="language-plaintext highlighter-rouge">list</code>. If you need to use a
|
||
concrete type (for example, a <code class="language-plaintext highlighter-rouge">tuple</code> of typed elements), prefer built-in types
|
||
like <code class="language-plaintext highlighter-rouge">tuple</code> over the parametric type aliases from the <code class="language-plaintext highlighter-rouge">typing</code> module (e.g.,
|
||
<code class="language-plaintext highlighter-rouge">typing.Tuple</code>).</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">List</span><span class="p">,</span> <span class="n">Tuple</span>
|
||
|
||
<span class="k">def</span> <span class="nf">transform_coordinates</span><span class="p">(</span><span class="n">original</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Tuple</span><span class="p">[</span><span class="nb">float</span><span class="p">,</span> <span class="nb">float</span><span class="p">]])</span> <span class="o">-></span>
|
||
<span class="n">List</span><span class="p">[</span><span class="n">Tuple</span><span class="p">[</span><span class="nb">float</span><span class="p">,</span> <span class="nb">float</span><span class="p">]]:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Sequence</span>
|
||
|
||
<span class="k">def</span> <span class="nf">transform_coordinates</span><span class="p">(</span><span class="n">original</span><span class="p">:</span> <span class="n">Sequence</span><span class="p">[</span><span class="nb">tuple</span><span class="p">[</span><span class="nb">float</span><span class="p">,</span> <span class="nb">float</span><span class="p">]])</span> <span class="o">-></span>
|
||
<span class="n">Sequence</span><span class="p">[</span><span class="nb">tuple</span><span class="p">[</span><span class="nb">float</span><span class="p">,</span> <span class="nb">float</span><span class="p">]]:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="s3.19.13-conditional-imports"></a>
|
||
<a id="31913-conditional-imports"></a></p>
|
||
|
||
<p><a id="typing-conditional-imports"></a></p>
|
||
<h4 id="31913-conditional-imports">3.19.13 Conditional Imports</h4>
|
||
|
||
<p>Use conditional imports only in exceptional cases where the additional imports
|
||
needed for type checking must be avoided at runtime. This pattern is
|
||
discouraged; alternatives such as refactoring the code to allow top-level
|
||
imports should be preferred.</p>
|
||
|
||
<p>Imports that are needed only for type annotations can be placed within an <code class="language-plaintext highlighter-rouge">if
|
||
TYPE_CHECKING:</code> block.</p>
|
||
|
||
<ul>
|
||
<li>Conditionally imported types need to be referenced as strings, to be forward
|
||
compatible with Python 3.6 where the annotation expressions are actually
|
||
evaluated.</li>
|
||
<li>Only entities that are used solely for typing should be defined here; this
|
||
includes aliases. Otherwise it will be a runtime error, as the module will
|
||
not be imported at runtime.</li>
|
||
<li>The block should be right after all the normal imports.</li>
|
||
<li>There should be no empty lines in the typing imports list.</li>
|
||
<li>Sort this list as if it were a regular imports list.
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">typing</span>
|
||
<span class="k">if</span> <span class="n">typing</span><span class="p">.</span><span class="n">TYPE_CHECKING</span><span class="p">:</span>
|
||
<span class="kn">import</span> <span class="nn">sketch</span>
|
||
<span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="s">"sketch.Sketch"</span><span class="p">):</span> <span class="p">...</span>
|
||
</code></pre></div> </div>
|
||
</li>
|
||
</ul>
|
||
|
||
<p><a id="s3.19.14-circular-dependencies"></a>
|
||
<a id="s3.19.14-circular-deps"></a>
|
||
<a id="31914-circular-dependencies"></a></p>
|
||
|
||
<p><a id="typing-circular-deps"></a></p>
|
||
<h4 id="31914-circular-dependencies">3.19.14 Circular Dependencies</h4>
|
||
|
||
<p>Circular dependencies that are caused by typing are code smells. Such code is a
|
||
good candidate for refactoring. Although technically it is possible to keep
|
||
circular dependencies, various build systems will not let you do so
|
||
because each module has to depend on the other.</p>
|
||
|
||
<p>Replace modules that create circular dependency imports with <code class="language-plaintext highlighter-rouge">Any</code>. Set an
|
||
<a href="#typing-aliases">alias</a> with a meaningful name, and use the real type name from
|
||
this module (any attribute of <code class="language-plaintext highlighter-rouge">Any</code> is <code class="language-plaintext highlighter-rouge">Any</code>). Alias definitions should be
|
||
separated from the last import by one line.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Any</span>
|
||
|
||
<span class="n">some_mod</span> <span class="o">=</span> <span class="n">Any</span> <span class="c1"># some_mod.py imports this module.
|
||
</span><span class="p">...</span>
|
||
|
||
<span class="k">def</span> <span class="nf">my_method</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">var</span><span class="p">:</span> <span class="s">"some_mod.SomeType"</span><span class="p">)</span> <span class="o">-></span> <span class="bp">None</span><span class="p">:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="typing-generics"></a>
|
||
<a id="s3.19.15-generics"></a>
|
||
<a id="31915-generics"></a></p>
|
||
|
||
<p><a id="generics"></a></p>
|
||
<h4 id="31915-generics">3.19.15 Generics</h4>
|
||
|
||
<p>When annotating, prefer to specify type parameters for
|
||
<a href="https://docs.python.org/3/library/typing.html#generics">generic</a> types in a
|
||
parameter list; otherwise, the generics’ parameters will be assumed to be
|
||
<a href="https://docs.python.org/3/library/typing.html#the-any-type"><code class="language-plaintext highlighter-rouge">Any</code></a>.</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Yes:
|
||
</span><span class="k">def</span> <span class="nf">get_names</span><span class="p">(</span><span class="n">employee_ids</span><span class="p">:</span> <span class="n">Sequence</span><span class="p">[</span><span class="nb">int</span><span class="p">])</span> <span class="o">-></span> <span class="n">Mapping</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">str</span><span class="p">]:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># No:
|
||
# This is interpreted as get_names(employee_ids: Sequence[Any]) -> Mapping[Any, Any]
|
||
</span><span class="k">def</span> <span class="nf">get_names</span><span class="p">(</span><span class="n">employee_ids</span><span class="p">:</span> <span class="n">Sequence</span><span class="p">)</span> <span class="o">-></span> <span class="n">Mapping</span><span class="p">:</span>
|
||
<span class="p">...</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>If the best type parameter for a generic is <code class="language-plaintext highlighter-rouge">Any</code>, make it explicit, but
|
||
remember that in many cases <a href="#typing-type-var"><code class="language-plaintext highlighter-rouge">TypeVar</code></a> might be more
|
||
appropriate:</p>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># No:
|
||
</span><span class="k">def</span> <span class="nf">get_names</span><span class="p">(</span><span class="n">employee_ids</span><span class="p">:</span> <span class="n">Sequence</span><span class="p">[</span><span class="n">Any</span><span class="p">])</span> <span class="o">-></span> <span class="n">Mapping</span><span class="p">[</span><span class="n">Any</span><span class="p">,</span> <span class="nb">str</span><span class="p">]:</span>
|
||
<span class="s">"""Returns a mapping from employee ID to employee name for given IDs."""</span>
|
||
</code></pre></div></div>
|
||
|
||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Yes:
|
||
</span><span class="n">_T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s">'_T'</span><span class="p">)</span>
|
||
<span class="k">def</span> <span class="nf">get_names</span><span class="p">(</span><span class="n">employee_ids</span><span class="p">:</span> <span class="n">Sequence</span><span class="p">[</span><span class="n">_T</span><span class="p">])</span> <span class="o">-></span> <span class="n">Mapping</span><span class="p">[</span><span class="n">_T</span><span class="p">,</span> <span class="nb">str</span><span class="p">]:</span>
|
||
<span class="s">"""Returns a mapping from employee ID to employee name for given IDs."""</span>
|
||
</code></pre></div></div>
|
||
|
||
<p><a id="4-parting-words"></a></p>
|
||
|
||
<p><a id="consistency"></a></p>
|
||
<h2 id="4-parting-words">4 Parting Words</h2>
|
||
|
||
<p><em>BE CONSISTENT</em>.</p>
|
||
|
||
<p>If you’re editing code, take a few minutes to look at the code around you and
|
||
determine its style. If they use <code class="language-plaintext highlighter-rouge">_idx</code> suffixes in index variable names, you
|
||
should too. If their comments have little boxes of hash marks around them, make
|
||
your comments have little boxes of hash marks around them too.</p>
|
||
|
||
<p>The point of having style guidelines is to have a common vocabulary of coding so
|
||
people can concentrate on what you’re saying rather than on how you’re saying
|
||
it. We present global style rules here so people know the vocabulary, but local
|
||
style is also important. If code you add to a file looks drastically different
|
||
from the existing code around it, it throws readers out of their rhythm when
|
||
they go to read it.</p>
|
||
|
||
<p>However, there are limits to consistency. It applies more heavily locally and on
|
||
choices unspecified by the global style. Consistency should not generally be
|
||
used as a justification to do things in an old style without considering the
|
||
benefits of the new style, or the tendency of the codebase to converge on newer
|
||
styles over time.</p>
|
||
|
||
|
||
|
||
|
||
<div class="footer border-top border-gray-light mt-5 pt-3 text-right text-gray">
|
||
This site is open source. <a href="https://github.com/google/styleguide/edit/gh-pages/pyguide.md">Improve this page</a>.
|
||
</div>
|
||
|
||
</div>
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/anchor-js/4.1.0/anchor.min.js" integrity="sha256-lZaRhKri35AyJSypXXs4o6OPFTbTmUoltBbDCbdzegg=" crossorigin="anonymous"></script>
|
||
<script>anchors.add();</script>
|
||
</body>
|
||
</html>
|