Pep 8 руководство по написанию кода на python pdf

Author:
Guido van Rossum <guido at python.org>,
Barry Warsaw <barry at python.org>,
Nick Coghlan <ncoghlan at gmail.com>
Status:
Active
Type:
Process
Created:
05-Jul-2001
Post-History:
05-Jul-2001, 01-Aug-2013

Table of Contents

  • Introduction
  • A Foolish Consistency is the Hobgoblin of Little Minds
  • Code Lay-out
    • Indentation
    • Tabs or Spaces?
    • Maximum Line Length
    • Should a Line Break Before or After a Binary Operator?
    • Blank Lines
    • Source File Encoding
    • Imports
    • Module Level Dunder Names
  • String Quotes
  • Whitespace in Expressions and Statements
    • Pet Peeves
    • Other Recommendations
  • When to Use Trailing Commas
  • Comments
    • Block Comments
    • Inline Comments
    • Documentation Strings
  • Naming Conventions
    • Overriding Principle
    • Descriptive: Naming Styles
    • Prescriptive: Naming Conventions
      • Names to Avoid
      • ASCII Compatibility
      • Package and Module Names
      • Class Names
      • Type Variable Names
      • Exception Names
      • Global Variable Names
      • Function and Variable Names
      • Function and Method Arguments
      • Method Names and Instance Variables
      • Constants
      • Designing for Inheritance
    • Public and Internal Interfaces
  • Programming Recommendations
    • Function Annotations
    • Variable Annotations
  • References
  • Copyright

Introduction

This document gives coding conventions for the Python code comprising
the standard library in the main Python distribution. Please see the
companion informational PEP describing style guidelines for the C code
in the C implementation of Python.

This document and PEP 257 (Docstring Conventions) were adapted from
Guido’s original Python Style Guide essay, with some additions from
Barry’s style guide [2].

This style guide evolves over time as additional conventions are
identified and past conventions are rendered obsolete by changes in
the language itself.

Many projects have their own coding style guidelines. In the event of any
conflicts, such project-specific guides take precedence for that project.

A Foolish Consistency is the Hobgoblin of Little Minds

One of Guido’s key insights is that code is read much more often than
it is written. The guidelines provided here are intended to improve
the readability of code and make it consistent across the wide
spectrum of Python code. As PEP 20 says, “Readability counts”.

A style guide is about consistency. Consistency with this style guide
is important. Consistency within a project is more important.
Consistency within one module or function is the most important.

However, know when to be inconsistent – sometimes style guide
recommendations just aren’t applicable. When in doubt, use your best
judgment. Look at other examples and decide what looks best. And
don’t hesitate to ask!

In particular: do not break backwards compatibility just to comply with
this PEP!

Some other good reasons to ignore a particular guideline:

  1. When applying the guideline would make the code less readable, even
    for someone who is used to reading code that follows this PEP.
  2. To be consistent with surrounding code that also breaks it (maybe
    for historic reasons) – although this is also an opportunity to
    clean up someone else’s mess (in true XP style).
  3. Because the code in question predates the introduction of the
    guideline and there is no other reason to be modifying that code.
  4. When the code needs to remain compatible with older versions of
    Python that don’t support the feature recommended by the style guide.

Code Lay-out

Indentation

Use 4 spaces per indentation level.

Continuation lines should align wrapped elements either vertically
using Python’s implicit line joining inside parentheses, brackets and
braces, or using a hanging indent [1]. When using a hanging
indent the following should be considered; there should be no
arguments on the first line and further indentation should be used to
clearly distinguish itself as a continuation line:

# Correct:

# Aligned with opening delimiter.
foo = long_function_name(var_one, var_two,
                         var_three, var_four)

# Add 4 spaces (an extra level of indentation) to distinguish arguments from the rest.
def long_function_name(
        var_one, var_two, var_three,
        var_four):
    print(var_one)

# Hanging indents should add a level.
foo = long_function_name(
    var_one, var_two,
    var_three, var_four)
# Wrong:

# Arguments on first line forbidden when not using vertical alignment.
foo = long_function_name(var_one, var_two,
    var_three, var_four)

# Further indentation required as indentation is not distinguishable.
def long_function_name(
    var_one, var_two, var_three,
    var_four):
    print(var_one)

The 4-space rule is optional for continuation lines.

Optional:

# Hanging indents *may* be indented to other than 4 spaces.
foo = long_function_name(
  var_one, var_two,
  var_three, var_four)

When the conditional part of an if-statement is long enough to require
that it be written across multiple lines, it’s worth noting that the
combination of a two character keyword (i.e. if), plus a single space,
plus an opening parenthesis creates a natural 4-space indent for the
subsequent lines of the multiline conditional. This can produce a visual
conflict with the indented suite of code nested inside the if-statement,
which would also naturally be indented to 4 spaces. This PEP takes no
explicit position on how (or whether) to further visually distinguish such
conditional lines from the nested suite inside the if-statement.
Acceptable options in this situation include, but are not limited to:

# No extra indentation.
if (this_is_one_thing and
    that_is_another_thing):
    do_something()

# Add a comment, which will provide some distinction in editors
# supporting syntax highlighting.
if (this_is_one_thing and
    that_is_another_thing):
    # Since both conditions are true, we can frobnicate.
    do_something()

# Add some extra indentation on the conditional continuation line.
if (this_is_one_thing
        and that_is_another_thing):
    do_something()

(Also see the discussion of whether to break before or after binary
operators below.)

The closing brace/bracket/parenthesis on multiline constructs may
either line up under the first non-whitespace character of the last
line of list, as in:

my_list = [
    1, 2, 3,
    4, 5, 6,
    ]
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
    )

or it may be lined up under the first character of the line that
starts the multiline construct, as in:

my_list = [
    1, 2, 3,
    4, 5, 6,
]
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
)

Tabs or Spaces?

Spaces are the preferred indentation method.

Tabs should be used solely to remain consistent with code that is
already indented with tabs.

Python disallows mixing tabs and spaces for indentation.

Maximum Line Length

Limit all lines to a maximum of 79 characters.

For flowing long blocks of text with fewer structural restrictions
(docstrings or comments), the line length should be limited to 72
characters.

Limiting the required editor window width makes it possible to have
several files open side by side, and works well when using code
review tools that present the two versions in adjacent columns.

The default wrapping in most tools disrupts the visual structure of the
code, making it more difficult to understand. The limits are chosen to
avoid wrapping in editors with the window width set to 80, even
if the tool places a marker glyph in the final column when wrapping
lines. Some web based tools may not offer dynamic line wrapping at all.

Some teams strongly prefer a longer line length. For code maintained
exclusively or primarily by a team that can reach agreement on this
issue, it is okay to increase the line length limit up to 99 characters,
provided that comments and docstrings are still wrapped at 72
characters.

The Python standard library is conservative and requires limiting
lines to 79 characters (and docstrings/comments to 72).

The preferred way of wrapping long lines is by using Python’s implied
line continuation inside parentheses, brackets and braces. Long lines
can be broken over multiple lines by wrapping expressions in
parentheses. These should be used in preference to using a backslash
for line continuation.

Backslashes may still be appropriate at times. For example, long,
multiple with-statements could not use implicit continuation
before Python 3.10, so backslashes were acceptable for that case:

with open('/path/to/some/file/you/want/to/read') as file_1, 
     open('/path/to/some/file/being/written', 'w') as file_2:
    file_2.write(file_1.read())

(See the previous discussion on multiline if-statements for further
thoughts on the indentation of such multiline with-statements.)

Another such case is with assert statements.

Make sure to indent the continued line appropriately.

Should a Line Break Before or After a Binary Operator?

For decades the recommended style was to break after binary operators.
But this can hurt readability in two ways: the operators tend to get
scattered across different columns on the screen, and each operator is
moved away from its operand and onto the previous line. Here, the eye
has to do extra work to tell which items are added and which are
subtracted:

# Wrong:
# operators sit far away from their operands
income = (gross_wages +
          taxable_interest +
          (dividends - qualified_dividends) -
          ira_deduction -
          student_loan_interest)

To solve this readability problem, mathematicians and their publishers
follow the opposite convention. Donald Knuth explains the traditional
rule in his Computers and Typesetting series: “Although formulas
within a paragraph always break after binary operations and relations,
displayed formulas always break before binary operations” [3].

Following the tradition from mathematics usually results in more
readable code:

# Correct:
# easy to match operators with operands
income = (gross_wages
          + taxable_interest
          + (dividends - qualified_dividends)
          - ira_deduction
          - student_loan_interest)

In Python code, it is permissible to break before or after a binary
operator, as long as the convention is consistent locally. For new
code Knuth’s style is suggested.

Blank Lines

Surround top-level function and class definitions with two blank
lines.

Method definitions inside a class are surrounded by a single blank
line.

Extra blank lines may be used (sparingly) to separate groups of
related functions. Blank lines may be omitted between a bunch of
related one-liners (e.g. a set of dummy implementations).

Use blank lines in functions, sparingly, to indicate logical sections.

Python accepts the control-L (i.e. ^L) form feed character as
whitespace; many tools treat these characters as page separators, so
you may use them to separate pages of related sections of your file.
Note, some editors and web-based code viewers may not recognize
control-L as a form feed and will show another glyph in its place.

Source File Encoding

Code in the core Python distribution should always use UTF-8, and should not
have an encoding declaration.

In the standard library, non-UTF-8 encodings should be used only for
test purposes. Use non-ASCII characters sparingly, preferably only to
denote places and human names. If using non-ASCII characters as data,
avoid noisy Unicode characters like z̯̯͡a̧͎̺l̡͓̫g̹̲o̡̼̘ and byte order
marks.

All identifiers in the Python standard library MUST use ASCII-only
identifiers, and SHOULD use English words wherever feasible (in many
cases, abbreviations and technical terms are used which aren’t
English).

Open source projects with a global audience are encouraged to adopt a
similar policy.

Imports

  • Imports should usually be on separate lines:
    # Correct:
    import os
    import sys
    

    It’s okay to say this though:

    # Correct:
    from subprocess import Popen, PIPE
    
  • 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 in the following order:

    1. Standard library imports.
    2. Related third party imports.
    3. Local application/library specific imports.

    You should put a blank line between each group of imports.

  • Absolute imports are recommended, as they are usually more readable
    and tend to be better behaved (or at least give better error
    messages) if the import system is incorrectly configured (such as
    when a directory inside a package ends up on sys.path):

    import mypkg.sibling
    from mypkg import sibling
    from mypkg.sibling import example
    

    However, explicit relative imports are an acceptable alternative to
    absolute imports, especially when dealing with complex package layouts
    where using absolute imports would be unnecessarily verbose:

    from . import sibling
    from .sibling import example
    

    Standard library code should avoid complex package layouts and always
    use absolute imports.

  • When importing a class from a class-containing module, it’s usually
    okay to spell this:

    from myclass import MyClass
    from foo.bar.yourclass import YourClass
    

    If this spelling causes local name clashes, then spell them explicitly:

    import myclass
    import foo.bar.yourclass
    

    and use “myclass.MyClass” and “foo.bar.yourclass.YourClass”.

  • Wildcard imports (from <module> import *) should be avoided, as
    they make it unclear which names are present in the namespace,
    confusing both readers and many automated tools. There is one
    defensible use case for a wildcard import, which is to republish an
    internal interface as part of a public API (for example, overwriting
    a pure Python implementation of an interface with the definitions
    from an optional accelerator module and exactly which definitions
    will be overwritten isn’t known in advance).

    When republishing names this way, the guidelines below regarding
    public and internal interfaces still apply.

Module Level Dunder Names

Module level “dunders” (i.e. names with two leading and two trailing
underscores) such as __all__, __author__, __version__,
etc. should be placed after the module docstring but before any import
statements except from __future__ imports. Python mandates that
future-imports must appear in the module before any other code except
docstrings:

"""This is the example module.

This module does stuff.
"""

from __future__ import barry_as_FLUFL

__all__ = ['a', 'b', 'c']
__version__ = '0.1'
__author__ = 'Cardinal Biggles'

import os
import sys

String Quotes

In Python, single-quoted strings and double-quoted strings are the
same. This PEP does not make a recommendation for this. Pick a rule
and stick to it. When a string contains single or double quote
characters, however, use the other one to avoid backslashes in the
string. It improves readability.

For triple-quoted strings, always use double quote characters to be
consistent with the docstring convention in PEP 257.

Whitespace in Expressions and Statements

Pet Peeves

Avoid extraneous whitespace in the following situations:

  • Immediately inside parentheses, brackets or braces:
    # Correct:
    spam(ham[1], {eggs: 2})
    
    # Wrong:
    spam( ham[ 1 ], { eggs: 2 } )
    
  • Between a trailing comma and a following close parenthesis:
  • Immediately before a comma, semicolon, or colon:
    # Correct:
    if x == 4: print(x, y); x, y = y, x
    
    # Wrong:
    if x == 4 : print(x , y) ; x , y = y , x
    
  • However, in a slice the colon acts like a binary operator, and
    should have equal amounts on either side (treating it as the
    operator with the lowest priority). In an extended slice, both
    colons must have the same amount of spacing applied. Exception:
    when a slice parameter is omitted, the space is omitted:

    # Correct:
    ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:]
    ham[lower:upper], ham[lower:upper:], ham[lower::step]
    ham[lower+offset : upper+offset]
    ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
    ham[lower + offset : upper + offset]
    
    # Wrong:
    ham[lower + offset:upper + offset]
    ham[1: 9], ham[1 :9], ham[1:9 :3]
    ham[lower : : upper]
    ham[ : upper]
    
  • Immediately before the open parenthesis that starts the argument
    list of a function call:

  • Immediately before the open parenthesis that starts an indexing or
    slicing:

    # Correct:
    dct['key'] = lst[index]
    
    # Wrong:
    dct ['key'] = lst [index]
    
  • More than one space around an assignment (or other) operator to
    align it with another:

    # Correct:
    x = 1
    y = 2
    long_variable = 3
    
    # Wrong:
    x             = 1
    y             = 2
    long_variable = 3
    

Other Recommendations

  • Avoid trailing whitespace anywhere. Because it’s usually invisible,
    it can be confusing: e.g. a backslash followed by a space and a
    newline does not count as a line continuation marker. Some editors
    don’t preserve it and many projects (like CPython itself) have
    pre-commit hooks that reject it.
  • Always surround these binary operators with a single space on either
    side: assignment (=), augmented assignment (+=, -=
    etc.), comparisons (==, <, >, !=, <>, <=,
    >=, in, not in, is, is not), Booleans (and,
    or, not).
  • If operators with different priorities are used, consider adding
    whitespace around the operators with the lowest priority(ies). Use
    your own judgment; however, never use more than one space, and
    always have the same amount of whitespace on both sides of a binary
    operator:

    # Correct:
    i = i + 1
    submitted += 1
    x = x*2 - 1
    hypot2 = x*x + y*y
    c = (a+b) * (a-b)
    
    # Wrong:
    i=i+1
    submitted +=1
    x = x * 2 - 1
    hypot2 = x * x + y * y
    c = (a + b) * (a - b)
    
  • Function annotations should use the normal rules for colons and
    always have spaces around the -> arrow if present. (See
    Function Annotations below for more about function annotations.):

    # Correct:
    def munge(input: AnyStr): ...
    def munge() -> PosInt: ...
    
    # Wrong:
    def munge(input:AnyStr): ...
    def munge()->PosInt: ...
    
  • Don’t use spaces around the = sign when used to indicate a
    keyword argument, or when used to indicate a default value for an
    unannotated function parameter:

    # Correct:
    def complex(real, imag=0.0):
        return magic(r=real, i=imag)
    
    # Wrong:
    def complex(real, imag = 0.0):
        return magic(r = real, i = imag)
    

    When combining an argument annotation with a default value, however, do use
    spaces around the = sign:

    # Correct:
    def munge(sep: AnyStr = None): ...
    def munge(input: AnyStr, sep: AnyStr = None, limit=1000): ...
    
    # Wrong:
    def munge(input: AnyStr=None): ...
    def munge(input: AnyStr, limit = 1000): ...
    
  • Compound statements (multiple statements on the same line) are
    generally discouraged:

    # Correct:
    if foo == 'blah':
        do_blah_thing()
    do_one()
    do_two()
    do_three()
    

    Rather not:

    # Wrong:
    if foo == 'blah': do_blah_thing()
    do_one(); do_two(); do_three()
    
  • While sometimes it’s okay to put an if/for/while with a small body
    on the same line, never do this for multi-clause statements. Also
    avoid folding such long lines!

    Rather not:

    # Wrong:
    if foo == 'blah': do_blah_thing()
    for x in lst: total += x
    while t < 10: t = delay()
    

    Definitely not:

    # Wrong:
    if foo == 'blah': do_blah_thing()
    else: do_non_blah_thing()
    
    try: something()
    finally: cleanup()
    
    do_one(); do_two(); do_three(long, argument,
                                 list, like, this)
    
    if foo == 'blah': one(); two(); three()
    

When to Use Trailing Commas

Trailing commas are usually optional, except they are mandatory when
making a tuple of one element. For clarity, it is recommended to
surround the latter in (technically redundant) parentheses:

# Correct:
FILES = ('setup.cfg',)
# Wrong:
FILES = 'setup.cfg',

When trailing commas are redundant, they are often helpful when a
version control system is used, when a list of values, arguments or
imported items is expected to be extended over time. The pattern is
to put each value (etc.) on a line by itself, always adding a trailing
comma, and add the close parenthesis/bracket/brace on the next line.
However it does not make sense to have a trailing comma on the same
line as the closing delimiter (except in the above case of singleton
tuples):

# Correct:
FILES = [
    'setup.cfg',
    'tox.ini',
    ]
initialize(FILES,
           error=True,
           )
# Wrong:
FILES = ['setup.cfg', 'tox.ini',]
initialize(FILES, error=True,)

Naming Conventions

The naming conventions of Python’s library are a bit of a mess, so
we’ll never get this completely consistent – nevertheless, here are
the currently recommended naming standards. New modules and packages
(including third party frameworks) should be written to these
standards, but where an existing library has a different style,
internal consistency is preferred.

Overriding Principle

Names that are visible to the user as public parts of the API should
follow conventions that reflect usage rather than implementation.

Descriptive: Naming Styles

There are a lot of different naming styles. It helps to be able to
recognize what naming style is being used, independently from what
they are used for.

The following naming styles are commonly distinguished:

  • b (single lowercase letter)
  • B (single uppercase letter)
  • lowercase
  • lower_case_with_underscores
  • UPPERCASE
  • UPPER_CASE_WITH_UNDERSCORES
  • CapitalizedWords (or CapWords, or CamelCase – so named because
    of the bumpy look of its letters [4]). This is also sometimes known
    as StudlyCaps.

    Note: When using acronyms in CapWords, capitalize all the
    letters of the acronym. Thus HTTPServerError is better than
    HttpServerError.

  • mixedCase (differs from CapitalizedWords by initial lowercase
    character!)
  • Capitalized_Words_With_Underscores (ugly!)

There’s also the style of using a short unique prefix to group related
names together. This is not used much in Python, but it is mentioned
for completeness. For example, the os.stat() function returns a
tuple whose items traditionally have names like st_mode,
st_size, st_mtime and so on. (This is done to emphasize the
correspondence with the fields of the POSIX system call struct, which
helps programmers familiar with that.)

The X11 library uses a leading X for all its public functions. In
Python, this style is generally deemed unnecessary because attribute
and method names are prefixed with an object, and function names are
prefixed with a module name.

In addition, the following special forms using leading or trailing
underscores are recognized (these can generally be combined with any
case convention):

  • _single_leading_underscore: weak “internal use” indicator.
    E.g. from M import * does not import objects whose names start
    with an underscore.
  • single_trailing_underscore_: used by convention to avoid
    conflicts with Python keyword, e.g.

    tkinter.Toplevel(master, class_='ClassName')
    
  • __double_leading_underscore: when naming a class attribute,
    invokes name mangling (inside class FooBar, __boo becomes
    _FooBar__boo; see below).
  • __double_leading_and_trailing_underscore__: “magic” objects or
    attributes that live in user-controlled namespaces.
    E.g. __init__, __import__ or __file__. Never invent
    such names; only use them as documented.

Prescriptive: Naming Conventions

Names to Avoid

Never use the characters ‘l’ (lowercase letter el), ‘O’ (uppercase
letter oh), or ‘I’ (uppercase letter eye) as single character variable
names.

In some fonts, these characters are indistinguishable from the
numerals one and zero. When tempted to use ‘l’, use ‘L’ instead.

ASCII Compatibility

Identifiers used in the standard library must be ASCII compatible
as described in the
policy section
of PEP 3131.

Package and Module Names

Modules should have short, all-lowercase names. Underscores can be
used in the module name if it improves readability. Python packages
should also have short, all-lowercase names, although the use of
underscores is discouraged.

When an extension module written in C or C++ has an accompanying
Python module that provides a higher level (e.g. more object oriented)
interface, the C/C++ module has a leading underscore
(e.g. _socket).

Class Names

Class names should normally use the CapWords convention.

The naming convention for functions may be used instead in cases where
the interface is documented and used primarily as a callable.

Note that there is a separate convention for builtin names: most builtin
names are single words (or two words run together), with the CapWords
convention used only for exception names and builtin constants.

Type Variable Names

Names of type variables introduced in PEP 484 should normally use CapWords
preferring short names: T, AnyStr, Num. It is recommended to add
suffixes _co or _contra to the variables used to declare covariant
or contravariant behavior correspondingly:

from typing import TypeVar

VT_co = TypeVar('VT_co', covariant=True)
KT_contra = TypeVar('KT_contra', contravariant=True)

Exception Names

Because exceptions should be classes, the class naming convention
applies here. However, you should use the suffix “Error” on your
exception names (if the exception actually is an error).

Global Variable Names

(Let’s hope that these variables are meant for use inside one module
only.) The conventions are about the same as those for functions.

Modules that are designed for use via from M import * should use
the __all__ mechanism to prevent exporting globals, or use the
older convention of prefixing such globals with an underscore (which
you might want to do to indicate these globals are “module
non-public”).

Function and Variable Names

Function names should be lowercase, with words separated by
underscores as necessary to improve readability.

Variable names follow the same convention as function names.

mixedCase is allowed only in contexts where that’s already the
prevailing style (e.g. threading.py), to retain backwards
compatibility.

Function and Method Arguments

Always use self for the first argument to instance methods.

Always use cls for the first argument to class methods.

If a function argument’s name clashes with a reserved keyword, it is
generally better to append a single trailing underscore rather than
use an abbreviation or spelling corruption. Thus class_ is better
than clss. (Perhaps better is to avoid such clashes by using a
synonym.)

Method Names and Instance Variables

Use the function naming rules: lowercase with words separated by
underscores as necessary to improve readability.

Use one leading underscore only for non-public methods and instance
variables.

To avoid name clashes with subclasses, use two leading underscores to
invoke Python’s name mangling rules.

Python mangles these names with the class name: if class Foo has an
attribute named __a, it cannot be accessed by Foo.__a. (An
insistent user could still gain access by calling Foo._Foo__a.)
Generally, double leading underscores should be used only to avoid
name conflicts with attributes in classes designed to be subclassed.

Note: there is some controversy about the use of __names (see below).

Constants

Constants are usually defined on a module level and written in all
capital letters with underscores separating words. Examples include
MAX_OVERFLOW and TOTAL.

Designing for Inheritance

Always decide whether a class’s methods and instance variables
(collectively: “attributes”) should be public or non-public. If in
doubt, choose non-public; it’s easier to make it public later than to
make a public attribute non-public.

Public attributes are those that you expect unrelated clients of your
class to use, with your commitment to avoid backwards incompatible
changes. Non-public attributes are those that are not intended to be
used by third parties; you make no guarantees that non-public
attributes won’t change or even be removed.

We don’t use the term “private” here, since no attribute is really
private in Python (without a generally unnecessary amount of work).

Another category of attributes are those that are part of the
“subclass API” (often called “protected” in other languages). Some
classes are designed to be inherited from, either to extend or modify
aspects of the class’s behavior. When designing such a class, take
care to make explicit decisions about which attributes are public,
which are part of the subclass API, and which are truly only to be
used by your base class.

With this in mind, here are the Pythonic guidelines:

  • Public attributes should have no leading underscores.
  • If your public attribute name collides with a reserved keyword,
    append a single trailing underscore to your attribute name. This is
    preferable to an abbreviation or corrupted spelling. (However,
    notwithstanding this rule, ‘cls’ is the preferred spelling for any
    variable or argument which is known to be a class, especially the
    first argument to a class method.)

    Note 1: See the argument name recommendation above for class methods.

  • For simple public data attributes, it is best to expose just the
    attribute name, without complicated accessor/mutator methods. Keep
    in mind that Python provides an easy path to future enhancement,
    should you find that a simple data attribute needs to grow
    functional behavior. In that case, use properties to hide
    functional implementation behind simple data attribute access
    syntax.

    Note 1: Try to keep the functional behavior side-effect free,
    although side-effects such as caching are generally fine.

    Note 2: Avoid using properties for computationally expensive
    operations; the attribute notation makes the caller believe that
    access is (relatively) cheap.

  • If your class is intended to be subclassed, and you have attributes
    that you do not want subclasses to use, consider naming them with
    double leading underscores and no trailing underscores. This
    invokes Python’s name mangling algorithm, where the name of the
    class is mangled into the attribute name. This helps avoid
    attribute name collisions should subclasses inadvertently contain
    attributes with the same name.

    Note 1: Note that only the simple class name is used in the mangled
    name, so if a subclass chooses both the same class name and attribute
    name, you can still get name collisions.

    Note 2: Name mangling can make certain uses, such as debugging and
    __getattr__(), less convenient. However the name mangling
    algorithm is well documented and easy to perform manually.

    Note 3: Not everyone likes name mangling. Try to balance the
    need to avoid accidental name clashes with potential use by
    advanced callers.

Public and Internal Interfaces

Any backwards compatibility guarantees apply only to public interfaces.
Accordingly, it is important that users be able to clearly distinguish
between public and internal interfaces.

Documented interfaces are considered public, unless the documentation
explicitly declares them to be provisional or internal interfaces exempt
from the usual backwards compatibility guarantees. All undocumented
interfaces should be assumed to be internal.

To better support introspection, modules should explicitly declare the
names in their public API using the __all__ attribute. Setting
__all__ to an empty list indicates that the module has no public API.

Even with __all__ set appropriately, internal interfaces (packages,
modules, classes, functions, attributes or other names) should still be
prefixed with a single leading underscore.

An interface is also considered internal if any containing namespace
(package, module or class) is considered internal.

Imported names should always be considered an implementation detail.
Other modules must not rely on indirect access to such imported names
unless they are an explicitly documented part of the containing module’s
API, such as os.path or a package’s __init__ module that exposes
functionality from submodules.

Programming Recommendations

  • Code should be written in a way that does not disadvantage other
    implementations of Python (PyPy, Jython, IronPython, Cython, Psyco,
    and such).

    For example, do not rely on CPython’s efficient implementation of
    in-place string concatenation for statements in the form a += b
    or a = a + b. This optimization is fragile even in CPython (it
    only works for some types) and isn’t present at all in implementations
    that don’t use refcounting. In performance sensitive parts of the
    library, the ''.join() form should be used instead. This will
    ensure that concatenation occurs in linear time across various
    implementations.

  • Comparisons to singletons like None should always be done with
    is or is not, never the equality operators.

    Also, beware of writing if x when you really mean if x is not
    None
    – e.g. when testing whether a variable or argument that
    defaults to None was set to some other value. The other value might
    have a type (such as a container) that could be false in a boolean
    context!

  • Use is not operator rather than not ... is. While both
    expressions are functionally identical, the former is more readable
    and preferred:

    # Correct:
    if foo is not None:
    
    # Wrong:
    if not foo is None:
    
  • When implementing ordering operations with rich comparisons, it is
    best to implement all six operations (__eq__, __ne__,
    __lt__, __le__, __gt__, __ge__) rather than relying
    on other code to only exercise a particular comparison.

    To minimize the effort involved, the functools.total_ordering()
    decorator provides a tool to generate missing comparison methods.

    PEP 207 indicates that reflexivity rules are assumed by Python.
    Thus, the interpreter may swap y > x with x < y, y >= x
    with x <= y, and may swap the arguments of x == y and x !=
    y
    . The sort() and min() operations are guaranteed to use
    the < operator and the max() function uses the >
    operator. However, it is best to implement all six operations so
    that confusion doesn’t arise in other contexts.

  • Always use a def statement instead of an assignment statement that binds
    a lambda expression directly to an identifier:

    # Correct:
    def f(x): return 2*x
    
    # Wrong:
    f = lambda x: 2*x
    

    The first form means that the name of the resulting function object is
    specifically ‘f’ instead of the generic ‘<lambda>’. This is more
    useful for tracebacks and string representations in general. The use
    of the assignment statement eliminates the sole benefit a lambda
    expression can offer over an explicit def statement (i.e. that it can
    be embedded inside a larger expression)

  • Derive exceptions from Exception rather than BaseException.
    Direct inheritance from BaseException is reserved for exceptions
    where catching them is almost always the wrong thing to do.

    Design exception hierarchies based on the distinctions that code
    catching the exceptions is likely to need, rather than the locations
    where the exceptions are raised. Aim to answer the question
    “What went wrong?” programmatically, rather than only stating that
    “A problem occurred” (see PEP 3151 for an example of this lesson being
    learned for the builtin exception hierarchy)

    Class naming conventions apply here, although you should add the
    suffix “Error” to your exception classes if the exception is an
    error. Non-error exceptions that are used for non-local flow control
    or other forms of signaling need no special suffix.

  • Use exception chaining appropriately. raise X from Y
    should be used to indicate explicit replacement without losing the
    original traceback.

    When deliberately replacing an inner exception (using raise X from
    None
    ), ensure that relevant details are transferred to the new
    exception (such as preserving the attribute name when converting
    KeyError to AttributeError, or embedding the text of the original
    exception in the new exception message).

  • When catching exceptions, mention specific exceptions whenever
    possible instead of using a bare except: clause:

    try:
        import platform_specific_module
    except ImportError:
        platform_specific_module = None
    

    A bare except: clause will catch SystemExit and
    KeyboardInterrupt exceptions, making it harder to interrupt a
    program with Control-C, and can disguise other problems. If you
    want to catch all exceptions that signal program errors, use
    except Exception: (bare except is equivalent to except
    BaseException:
    ).

    A good rule of thumb is to limit use of bare ‘except’ clauses to two
    cases:

    1. If the exception handler will be printing out or logging the
      traceback; at least the user will be aware that an error has
      occurred.
    2. If the code needs to do some cleanup work, but then lets the
      exception propagate upwards with raise. try...finally
      can be a better way to handle this case.
  • When catching operating system errors, prefer the explicit exception
    hierarchy introduced in Python 3.3 over introspection of errno
    values.
  • Additionally, for all try/except clauses, limit the try clause
    to the absolute minimum amount of code necessary. Again, this
    avoids masking bugs:

    # Correct:
    try:
        value = collection[key]
    except KeyError:
        return key_not_found(key)
    else:
        return handle_value(value)
    
    # Wrong:
    try:
        # Too broad!
        return handle_value(collection[key])
    except KeyError:
        # Will also catch KeyError raised by handle_value()
        return key_not_found(key)
    
  • When a resource is local to a particular section of code, use a
    with statement to ensure it is cleaned up promptly and reliably
    after use. A try/finally statement is also acceptable.
  • Context managers should be invoked through separate functions or methods
    whenever they do something other than acquire and release resources:

    # Correct:
    with conn.begin_transaction():
        do_stuff_in_transaction(conn)
    
    # Wrong:
    with conn:
        do_stuff_in_transaction(conn)
    

    The latter example doesn’t provide any information to indicate that
    the __enter__ and __exit__ methods are doing something other
    than closing the connection after a transaction. Being explicit is
    important in this case.

  • Be consistent in return statements. Either all return statements in
    a function should return an expression, or none of them should. If
    any return statement returns an expression, any return statements
    where no value is returned should explicitly state this as return
    None
    , and an explicit return statement should be present at the
    end of the function (if reachable):

    # Correct:
    
    def foo(x):
        if x >= 0:
            return math.sqrt(x)
        else:
            return None
    
    def bar(x):
        if x < 0:
            return None
        return math.sqrt(x)
    
    # Wrong:
    
    def foo(x):
        if x >= 0:
            return math.sqrt(x)
    
    def bar(x):
        if x < 0:
            return
        return math.sqrt(x)
    
  • Use ''.startswith() and ''.endswith() instead of string
    slicing to check for prefixes or suffixes.

    startswith() and endswith() are cleaner and less error prone:

    # Correct:
    if foo.startswith('bar'):
    
    # Wrong:
    if foo[:3] == 'bar':
    
  • Object type comparisons should always use isinstance() instead of
    comparing types directly:

    # Correct:
    if isinstance(obj, int):
    
    # Wrong:
    if type(obj) is type(1):
    
  • For sequences, (strings, lists, tuples), use the fact that empty
    sequences are false:

    # Correct:
    if not seq:
    if seq:
    
    # Wrong:
    if len(seq):
    if not len(seq):
    
  • Don’t write string literals that rely on significant trailing
    whitespace. Such trailing whitespace is visually indistinguishable
    and some editors (or more recently, reindent.py) will trim them.
  • Don’t compare boolean values to True or False using ==:
    # Wrong:
    if greeting == True:
    

    Worse:

    # Wrong:
    if greeting is True:
    
  • Use of the flow control statements return/break/continue
    within the finally suite of a try...finally, where the flow control
    statement would jump outside the finally suite, is discouraged. This
    is because such statements will implicitly cancel any active exception
    that is propagating through the finally suite:

    # Wrong:
    def foo():
        try:
            1 / 0
        finally:
            return 42
    

Function Annotations

With the acceptance of PEP 484, the style rules for function
annotations have changed.

  • Function annotations should use PEP 484 syntax (there are some
    formatting recommendations for annotations in the previous section).
  • The experimentation with annotation styles that was recommended
    previously in this PEP is no longer encouraged.
  • However, outside the stdlib, experiments within the rules of PEP 484
    are now encouraged. For example, marking up a large third party
    library or application with PEP 484 style type annotations,
    reviewing how easy it was to add those annotations, and observing
    whether their presence increases code understandability.
  • The Python standard library should be conservative in adopting such
    annotations, but their use is allowed for new code and for big
    refactorings.
  • For code that wants to make a different use of function annotations
    it is recommended to put a comment of the form:

    near the top of the file; this tells type checkers to ignore all
    annotations. (More fine-grained ways of disabling complaints from
    type checkers can be found in PEP 484.)

  • Like linters, type checkers are optional, separate tools. Python
    interpreters by default should not issue any messages due to type
    checking and should not alter their behavior based on annotations.
  • Users who don’t want to use type checkers are free to ignore them.
    However, it is expected that users of third party library packages
    may want to run type checkers over those packages. For this purpose
    PEP 484 recommends the use of stub files: .pyi files that are read
    by the type checker in preference of the corresponding .py files.
    Stub files can be distributed with a library, or separately (with
    the library author’s permission) through the typeshed repo [5].

Variable Annotations

PEP 526 introduced variable annotations. The style recommendations for them are
similar to those on function annotations described above:

  • Annotations for module level variables, class and instance variables,
    and local variables should have a single space after the colon.
  • There should be no space before the colon.
  • If an assignment has a right hand side, then the equality sign should have
    exactly one space on both sides:

    # Correct:
    
    code: int
    
    class Point:
        coords: Tuple[int, int]
        label: str = '<unknown>'
    
    # Wrong:
    
    code:int  # No space after colon
    code : int  # Space before colon
    
    class Test:
        result: int=0  # No spaces around equality sign
    
  • Although the PEP 526 is accepted for Python 3.6, the variable annotation
    syntax is the preferred syntax for stub files on all versions of Python
    (see PEP 484 for details).

Footnotes

References

Copyright

This document has been placed in the public domain.

Когда дело доходит до написания крупных проектов или поддержки существующего кода, становится очень важным следовать определенным стандартам кодирования, чтобы обеспечить читаемость, понятность и поддерживаемость кода.

Один из таких стандартов — PEP8, который устанавливает рекомендации по стилю и форматированию кода на языке Python.

Содержание

  1. Введение
  2. Причины использовать
  3. Основные правила
  4. Отступы
  5. Максимальная длина строки
  6. Пробелы
  7. Именование
  8. Комментарии
  9. Импорты
  10. Пробелы вокруг операторов
  11. Названия функций и методов
  12. Название переменных
  13. Расположение функций и классов
  14. Длина строки
  15. Тройные кавычки
  16. Полезные инструменты
  17. Дополнительные источники
  18. Заключение

Введение

PEP8 — это документ, описывающий стандарты, которые разработчики должны следовать при написании кода на Python. Следование этим рекомендациям может значительно улучшить качество вашего кода, сделать его более читаемым и понятным для других разработчиков.

В этой статье мы рассмотрим основные правила, описанные в PEP8, и объясним, как их следовать, чтобы написать чистый, читаемый и поддерживаемый код на Python.

Причины использовать

PEP8 — это руководство по стилю кода для языка программирования Python. Он описывает рекомендации и правила для написания читаемого, понятного и консистентного кода на Python.

PEP8 важен для написания качественного кода на Python по нескольким причинам. Во-первых, он помогает сделать код более читаемым и понятным для других программистов, которые могут работать с вашим кодом. Это особенно важно, если вы работаете в команде или если ваш код будет использоваться другими людьми.

Во-вторых, соблюдение стандартов PEP8 может помочь сделать ваш код более консистентным. Это означает, что ваш код будет выглядеть более единообразно и просто, что упрощает его понимание и обслуживание.

В-третьих, соблюдение стандартов PEP8 может помочь обнаружить ошибки и потенциальные проблемы в вашем коде. Например, если вы используете нестандартное именование переменных или не соблюдаете правила отступов, это может привести к ошибкам или проблемам при чтении вашего кода.

Кроме того, многие инструменты разработки поддерживают стандарты PEP8 и могут помочь вам автоматически проверять соответствие вашего кода этим стандартам.

В целом, соблюдение стандартов PEP8 является важной практикой для написания качественного кода на Python. Он помогает сделать ваш код более читаемым, консистентным и устойчивым к ошибкам.

Основные правила

Основные правила PEP8 — это набор рекомендаций по оформлению кода на Python, который помогает сделать код более читаемым и понятным. Ниже я перечислю несколько основных правил PEP8:

Отступы

Используйте 4 пробела для каждого уровня отступа. Это правило помогает визуально выделить блоки кода и упрощает чтение кода. Использование символов табуляции или пробелов для отступов не рекомендуется, так как это может вызывать проблемы с отображением в разных текстовых редакторах.

Например:

# Правильно:
if x == 1:
    print("x is 1")

# Неправильно:
if x == 1:
        print("x is 1")

Максимальная длина строки

Ограничьте длину строки не более чем 79 символами. Если строка длиннее, разбейте ее на несколько строк. Длинные строки могут быть трудны для чтения, особенно когда они выходят за границы окна редактора. Разбиение длинных строк на несколько строк с помощью продолжения строки с помощью символа обратной косой черты является хорошей практикой.

Например:

# Правильно:
long_string = "This is a really long string that "
              "spans multiple lines."

# Неправильно:
long_string = "This is a really long string that spans multiple lines."

Пробелы

Используйте один пробел между операторами и операндами. Не используйте пробелы для выделения скобок вокруг аргументов функций. Это правило помогает упростить код и сделать его более читабельным.

Например:

# Правильно:
x = 2 + 3
y = (1 + 2) * 3

# Неправильно:
x=2+3
y = ( 1 + 2 ) * 3

Именование

Используйте понятные и описательные имена переменных, функций и методов. Для имени переменных используйте строчные буквы, а для имен функций и методов — заглавные буквы. Это правило помогает делать ваш код более читаемым и понятным для других программистов.

Например:

# Правильно:
age = 25
name = "John"

def calculate_sum(numbers):
    return sum(numbers)

# Неправильно:
a = 25
b = "John"

def calc_sum(nums):
    return sum(nums)

Комментарии

Добавляйте комментарии к вашему коду, чтобы объяснить сложные участки кода.

Комментарии должны быть короткими, лаконичными и описательными, они должны помогать другим программистам понимать ваш код. Не используйте комментарии для описания очевидных вещей, таких как присваивание переменной значения, и избегайте комментариев в конце строки.

Например:

# Правильно:
# Получаем текущую дату и время
current_time = datetime.datetime.now()

# Неправильно:
current_time = datetime.datetime.now()  # Получаем текущую дату и время

Импорты

Импортируйте модули в алфавитном порядке, разделяйте группы импортов пустой строкой и избегайте использования символа *. Это правило помогает упростить импорты и улучшить читабельность кода.

Например:

# Правильно:
import datetime
import os

from math import sqrt

import requests

# Неправильно:
import requests, os, datetime

from math import *

import my_module

Пробелы вокруг операторов

Используйте пустые строки для разделения логически связанных частей кода. Не используйте несколько операторов на одной строке.

Используйте пробелы вокруг операторов (=, +, -, *, /, //, %, и т. д.), но не используйте пробелы вокруг символа индексирования или среза.

Например:

# Правильно:
x = 2 + 3
y = x * 4
z = list[0]

# Неправильно:
x=2+3
y = x*4
z = list [0]

Названия функций и методов

Используйте глаголы в названиях функций и методов, используйте нижнее подчеркивание для разделения слов. Это правило помогает делать код более понятным и легче читаемым.

Например:

# Правильно:
def calculate_sum(numbers):
    return sum(numbers)

def get_user_name(user):
    return user.name

# Неправильно:
def numbersSum(nums):
    return sum(nums)

def user(user):
    return user.name

Название переменных

Используйте понятные и описательные названия для переменных, избегайте использования одиночных символов в качестве названий переменных, используйте нижнее подчеркивание для разделения слов.

Например:

# Правильно:
total_sum = 0
list_of_numbers = [1, 2, 3, 4]
user_name = "John"

# Неправильно:
t = 0
n = [1, 2, 3, 4]
un = "John"

Расположение функций и классов

Располагайте функции и классы логически в вашем коде. Разделяйте функции и классы пустыми строками, чтобы улучшить читабельность кода. Функции должны быть определены перед их использованием.

Например:

# Правильно:
def calculate_sum(numbers):
    return sum(numbers)

def main():
    list_of_numbers = [1, 2, 3, 4]
    total_sum = calculate_sum(list_of_numbers)
    print(f"The total sum is: {total_sum}")

if __name__ == "__main__":
    main()

# Неправильно:
def main():
    list_of_numbers = [1, 2, 3, 4]
    total_sum = calculate_sum(list_of_numbers)
    print(f"The total sum is: {total_sum}")

def calculate_sum(numbers):
    return sum(numbers)

if __name__ == "__main__":
    main()

Длина строки

Строки не должны быть длиннее 79 символов. Если строка слишком длинная, ее можно разбить на несколько строк, используя скобки, запятые или операторы конкатенации.

Например:

# Правильно:
message = "This is a very long message that should be split " 
          "into multiple lines for better readability."

total_sum = (100 + 200 + 300 +
             400 + 500 + 600)

# Неправильно:
message = "This is a very long message that should be split into multiple lines for better readability."

total_sum = 100 + 200 + 300 + 400 + 500 + 600

Тройные кавычки

Используйте тройные кавычки для документации вашего кода. Это помогает другим программистам понимать ваш код и использовать его в своих проектах.

Например:

# Правильно:
def calculate_sum(numbers):
    """
    This function calculates the sum of the numbers in the given list.

    Parameters:
        numbers (list): A list of numbers to calculate the sum of.

    Returns:
        float: The sum of the numbers in the list.
    """
    return sum(numbers)

# Неправильно:
def calculate_sum(numbers):
    # This function calculates the sum of the numbers in the given list.
    return sum(numbers)

Полезные инструменты

Действительно, существует множество инструментов, которые помогают разработчикам Python следовать стандартам PEP8. Эти инструменты включают линтеры и автоматические форматировщики.

Линтеры — это инструменты, которые анализируют код и проверяют его соответствие стандартам PEP8. Они предупреждают разработчиков о нарушениях стандартов PEP8 и других проблемах в их коде. Некоторые из наиболее популярных линтеров для Python включают:

  • pylint — это линтер для Python, который проверяет соответствие кода стандартам PEP8. Он также обнаруживает другие проблемы в коде, такие как синтаксические ошибки, неиспользуемые переменные и дублирование кода.
  • flake8 — это линтер, который проверяет соответствие кода стандартам PEP8, а также обнаруживает другие проблемы в коде, такие как неиспользуемые импорты и неправильное форматирование строк.
  • PyCharm — это IDE для Python, которая включает встроенный линтер, который проверяет соответствие кода стандартам PEP8 и другие проблемы в коде. Он также предлагает рекомендации по исправлению нарушений стандартов PEP8.

Автоматические форматировщики — это инструменты, которые автоматически форматируют код в соответствии со стандартами PEP8. Они упрощают процесс форматирования кода и позволяют разработчикам сосредоточиться на его содержимом. Некоторые из наиболее популярных автоматических форматировщиков для Python включают:

  1. Black — это автоматический форматировщик кода на Python, который форматирует код в соответствии со стандартами PEP8. Он удаляет неоднозначность в коде и делает его более понятным.
  2. autopep8 — это инструмент, который автоматически форматирует код в соответствии со стандартами PEP8. Он также может исправлять другие проблемы в коде, такие как синтаксические ошибки.
  3. YAPF — это автоматический форматировщик кода на Python, который форматирует код в соответствии со стандартами PEP8 и другими рекомендациями по стилю кодирования.

Использование линтеров и автоматических форматировщиков может значительно упростить процесс следования стандартам PEP8 и улучшить качество кода. Например, линтеры могут предупреждать о нарушениях стандартов PEP8 до того, как код будет отправлен на ревью, что помогает избежать ошибок, связанных со стилем кода. Автоматические форматировщики позволяют быстро и легко отформатировать код в соответствии со стандартами PEP8.

Кроме того, многие инструменты интегрируются с популярными средами разработки, такими как PyCharm и VS Code, что упрощает их использование и интеграцию в рабочий процесс разработки.

Важно отметить, что линтеры и автоматические форматировщики не могут полностью заменить ручное форматирование и проверку кода на соответствие стандартам PEP8. Иногда они могут допустить ошибки или предложить неоптимальные решения. Поэтому важно использовать эти инструменты в сочетании с ручной проверкой кода и соблюдением наилучших практик при написании кода на Python.

Дополнительные источники

Существует множество ресурсов и инструментов для дополнительного изучения PEP8 и его реализации в проектах.

Некоторые из них перечислены ниже:

  • Официальный документ PEP8: Документ PEP8 можно найти на официальном сайте Python. Он содержит все основные правила и рекомендации по написанию чистого и понятного кода на Python.
  • Flake8: Flake8 — это инструмент статического анализа кода на Python, который проверяет соответствие кода стандартам PEP8. Он также проверяет синтаксические ошибки, использование необъявленных переменных и другие нарушения.
  • PyCharm: PyCharm — это интегрированная среда разработки (IDE) для Python, которая имеет встроенный инструмент PEP8. Он предупреждает вас, если ваш код нарушает стандарты PEP8, и предлагает исправления.
  • Black: Black — это автоматический форматтер кода на Python, который следует стандартам PEP8. Он автоматически форматирует ваш код, чтобы он соответствовал стандартам PEP8, и также может использоваться для автоматического форматирования кода в больших проектах.
  • pylint: pylint — это еще один инструмент статического анализа кода на Python, который проверяет соответствие кода стандартам PEP8. Он также предупреждает вас об использовании устаревших или небезопасных конструкций в вашем коде.
  • Real Python: Real Python — это онлайн-платформа для изучения Python, которая содержит множество статей, учебных пособий и видеоуроков. Они предлагают руководства по написанию чистого и понятного кода на Python в соответствии с PEP8.
  • Python Code Quality Authority: Python Code Quality Authority — это организация, которая управляет несколькими инструментами для проверки качества кода на Python, включая Flake8 и pylint. Они также поддерживают ряд стандартов и рекомендаций для написания чистого и понятного кода на Python.

Заключение

Следование правилам PEP8 поможет вам написать более чистый, понятный и поддерживаемый код на Python. Однако, не стоит забывать, что эти правила не являются абсолютными и всегда могут быть нарушены в некоторых случаях. Важно следить за своим стилем и придерживаться общепринятых стандартов в сообществе Python.

Документ Python Enhancement Proposal #8 (сокращенно РЕР8) содержит предложения по стилевому оформлению кода программ на языке Python. Вообще говоря, вы вправе форматировать свой код так, как считаете нужным. Однако применение единообразного стиля облегчит изучение кода другими людьми и улучшит его удобочитаемость. Совместное использование общего стиля с другими Руthоn-программистами в рамках большого сообщества способствует улучшению качества программ при коллективной работе над проектами. Но даже если единственный человек, который когда-либо будет читать ваш код, — это вы, соблюдение рекомендаций РЕР 8 облегчит внесение последующих изменений в код.

Документ РЕР8 содержит детализированные правила написания кода на Python. По мере развития языка этот документ постоянно обновляется. Было бы неплохо, если бы вы прочитали целиком все руководство

Ниже приведены некоторые правила, которых следует обязательно придерживаться.

В языке Python пробелы имеют синтаксическое значение. Особое значение Pythоn-программисты придают влиянию пробелов на удобочитаемость кода.

В документе РЕР8 для различных элементов языка предлагается свой стиль имен. Благодаря этому можно легко определить в процессе чтения кода, какому типу соответствует то или иное имя:

Одно из положений дзен-философии Python гласит: «Должен существовать один — и предпочтительно только один — очевидный способ сделать это». В рекомендациях документа РЕР8 предпринимается попытка кодифицировать такой стиль написания выражений и предложений.

В каждом подразделе модули должны располагаться в алфавитном порядке.

Если вы спросите программистов Python, что им больше всего нравится в Python, они часто будут ссылаться на его высокую читабельность. Действительно, высокий уровень читабельности лежит в основе дизайна языка Python, следуя общепризнанному факту, что код читается гораздо чаще, чем пишется.

Одной из причин высокой читабельности кода Python является его полный набор рекомендаций PEP8 по стилю кода и «Pythonic» идиом.

Когда ветеран Python-разработчик (Pythonista) называет части кода не «Pythonic», они обычно означают, что эти строки кода не следуют общим правилам и не выражают свое намерение в том, что считается лучшим (слушайте: наиболее читаемый) путь.

В некоторых случаях не было достигнуто соглашения о том, как выразить намерение в коде Python, но такие случаи редки.

Хотя в Python возможен любой вид черной магии, наиболее явный и простой способ предпочтителен.

В приведенном выше хорошем коде x и y явно принимаются от вызывающей стороны, и возвращается явный словарь. Разработчик, использующий эту функцию, точно знает, что делать, читая первые и последние строки, что не так с плохим примером.

Одно утверждение на строку 

Несмотря на то, что некоторые составные операторы, такие как списочные выражения, допускаются и ценятся за их краткость и выразительность, использование двух разделенных операторов в одной строке кода является плохой практикой.

Плохо

print 'one'; print 'two'

if x == 1: print 'one'

if <complex comparison> and <other complex comparison>:
    # do something

Хорошо

print 'one'
print 'two'

if x == 1:
    print 'one'

cond1 = <complex comparison>
cond2 = <other complex comparison>
if cond1 and cond2:
    # do something

Аргументы функции 

Аргументы могут быть переданы в функции четырьмя различными способами.

  1. Позиционные аргументы являются обязательными и не имеют значений по умолчанию. Они являются простейшей формой аргументов и могут использоваться для нескольких аргументов функции, которые полностью являются частью значения функции, и их порядок является естественным. Например, пользователь или пользователь функции без труда помнит, что эти две функции требуют двух аргументов и в каком порядке.send(message, recipient)point(x, y)

В этих двух случаях, можно использовать имена аргументов при вызове функции и, делая это, можно изменить порядок аргументов, вызывая, например , и , но это снижает читаемость и излишне многословные, по сравнению с более простыми вызовами к и .send(recipient='World', message='Hello')point(y=2, x=1)send('Hello', 'World')point(1, 2)

  1. Аргументы ключевых слов не являются обязательными и имеют значения по умолчанию. Они часто используются для необязательных параметров, отправляемых в функцию. Когда функция имеет более двух или трех позиционных параметров, ее сигнатуру труднее запомнить, и полезно использовать аргументы ключевых слов со значениями по умолчанию. Например, более полная sendфункция может быть определена как . Здесь и не являются обязательными, и оценивают, когда им не передается другое значение.send(message, to, cc=None, bcc=None)ccbccNone

Вызов функции с аргументами ключевых слов может быть выполнен несколькими способами в Python; например, можно следовать порядку аргументов в определении, не называя аргументы в явном виде, как, например , отправляя слепую копию для Бога. Также можно было бы назвать аргументы в другом порядке, например, в . Эти две возможности лучше избегать без каких — либо веских причин , чтобы не следить за синтаксис , который ближе всего к определению функции: .send('Hello', 'World', 'Cthulhu', 'God')send('Hello again', 'World', bcc='God', cc='Cthulhu')send('Hello', 'World', cc='Cthulhu', bcc='God')

В качестве примечания, следуя принципу YAGNI , зачастую сложнее удалить необязательный аргумент (и его логику внутри функции), который был добавлен «на всякий случай» и, по-видимому, никогда не используется, чем добавить новый необязательный аргумент и его логика, когда это необходимо.

  1. Список произвольных аргументов — это третий способ передачи аргументов в функцию. Если намерение функции лучше выражается сигнатурой с расширяемым числом позиционных аргументов, ее можно определить с помощью *argsконструкций. В теле функции argsбудет кортеж всех оставшихся позиционных аргументов. Например, может быть вызван с каждым получателем в качестве аргумента:, а в теле функции будет равно .send(message, *args)send('Hello', 'God', 'Mom', 'Cthulhu')args('God', 'Mom', 'Cthulhu')

Однако эта конструкция имеет некоторые недостатки и должна использоваться с осторожностью. Если функция получает список аргументов одинаковой природы, часто более понятно определить ее как функцию одного аргумента, причем этот аргумент является списком или любой последовательностью. Здесь, если sendесть несколько получателей, лучше определить это явно: и вызвать его с помощью . Таким образом, пользователь функции может заранее манипулировать списком получателей как списком, и это открывает возможность для передачи любой последовательности, включая итераторы, которая не может быть распакована как другие последовательности.send(message, recipients)send('Hello', ['God', 'Mom', 'Cthulhu'])

  1. Произвольный ключевой слово словарь аргумента является последним способом передать аргументы функции. Если функции требуется неопределенная серия именованных аргументов, можно использовать **kwargsконструкцию. В теле функции kwargsбудет словарь всех переданных именованных аргументов, которые не были перехвачены другими ключевыми аргументами в сигнатуре функции.

Необходима та же осторожность, что и в случае списка произвольных аргументов , по аналогичным причинам: эти мощные методы должны использоваться, когда существует явная необходимость их использования, и их не следует использовать, если более простая и понятная конструкция достаточна для выразить намерение функции.

Программист должен написать функцию, чтобы определить, какие аргументы являются позиционными аргументами, а какие — необязательными аргументами ключевых слов, и решить, использовать ли передовые методы передачи произвольных аргументов. Если следовать приведенному выше совету разумно, можно и приятно писать функции Python, которые:

  • легко читается (имя и аргументы не нуждаются в объяснениях)
  • легко изменить (добавление нового ключевого аргумента не нарушает другие части кода)

Избегайте волшебной палочки 

Мощный инструмент для хакеров, Python поставляется с очень богатым набором хуков и инструментов, позволяющих вам выполнять практически любые хитрые трюки. Например, можно выполнить каждое из следующих действий:

  • изменить способ создания и создания объектов
  • изменить способ импорта модулей интерпретатором Python
  • Можно даже (и рекомендуется при необходимости) встроить подпрограммы C в Python.

Тем не менее, все эти варианты имеют много недостатков, и всегда лучше использовать самый простой способ для достижения вашей цели. Основным недостатком является то, что читаемость сильно страдает при использовании этих конструкций. Многие инструменты анализа кода, такие как pylint или pyflakes, не смогут проанализировать этот «волшебный» код.

Мы считаем, что разработчик Python должен знать об этих почти безграничных возможностях, потому что это вселяет уверенность в том, что на пути не будет непроходимых проблем. Однако очень важно знать, как и, в частности, когда их не использовать.

Подобно мастеру кунг-фу, питонист знает, как убивать одним пальцем, и никогда не делать этого на самом деле.

Мы все ответственные пользователи 

Как видно выше, Python допускает множество трюков, и некоторые из них потенциально опасны. Хорошим примером является то, что любой клиентский код может переопределять свойства и методы объекта: в Python нет ключевого слова «private». Эта философия, очень отличающаяся от языков с высокой степенью защиты, таких как Java, которые предоставляют множество механизмов для предотвращения любого неправильного использования, выражается высказыванием: «Мы все ответственные пользователи».

Это не означает, что, например, никакие свойства не считаются закрытыми и что правильная инкапсуляция невозможна в Python. Скорее, вместо того, чтобы полагаться на бетонные стены, возводимые разработчиками между их кодом и чужим, сообщество Python предпочитает полагаться на ряд соглашений, указывающих, что к этим элементам не следует обращаться напрямую.

Основное соглашение для частных свойств и деталей реализации заключается в добавлении префикса ко всем «внутренним элементам». Если клиентский код нарушает это правило и получает доступ к этим отмеченным элементам, любое неправильное поведение или проблемы, возникшие при изменении кода, являются ответственностью клиентского кода.

Использование этого соглашения приветствуется: любой метод или свойство, которые не предназначены для использования клиентским кодом, должны начинаться с подчеркивания. Это гарантирует лучшее разделение обязанностей и более легкую модификацию существующего кода; всегда будет возможно обнародовать частную собственность, но сделать публичную собственность частной может быть гораздо более сложной операцией.

Возвращение значения 

Когда функция усложняется, нередко используют несколько операторов return внутри тела функции. Однако, чтобы сохранить четкое намерение и устойчивый уровень читабельности, желательно избегать возврата значимых значений из многих выходных точек в теле.

Существует два основных случая возврата значений в функцию: результат возврата функции, когда она была обработана нормально, и случаи ошибок, которые указывают на неправильный входной параметр, или любую другую причину, по которой функция не может завершить вычисление или задача.

Если вы не хотите вызывать исключения для второго случая, может потребоваться возврат значения, такого как None или False, указывающего, что функция не может работать правильно. В этом случае лучше вернуться, как только был обнаружен неправильный контекст. Это поможет сгладить структуру функции: весь код после оператора return-from-of-error может предполагать, что условие выполнено для дальнейшего вычисления основного результата функции. Наличие нескольких таких операторов возврата часто необходимо.

Однако, когда функция имеет несколько основных точек выхода для своего нормального хода, становится трудно отлаживать возвращаемый результат, поэтому может быть предпочтительнее сохранить одну точку выхода. Это также поможет выделить некоторые пути кода, а несколько точек выхода являются вероятным признаком того, что такой рефакторинг необходим.

def complex_function(a, b, c):
    if not a:
        return None  # Raising an exception might be better
    if not b:
        return None  # Raising an exception might be better
    # Some complex code trying to compute x from a, b and c
    # Resist temptation to return x if succeeded
    if not x:
        # Some Plan-B computation of x
    return x  # One single exit point for the returned value x will help
              # when maintaining the code.

Идиомы 

Проще говоря, идиома программирования — это способ написания кода. Понятие идиом программирования подробно обсуждается на c2 и в Stack Overflow .

Идиоматический код Python часто называют Pythonic .

Хотя обычно есть один — и предпочтительно только один — очевидный способ сделать это; способ писать идиоматические коды Python могут быть неочевидными для начинающего Python. Таким образом, хорошие идиомы должны быть осознанно приобретены.

Ниже приведены некоторые распространенные идиомы Python:

Распаковка 

Если вы знаете длину списка или кортежа, вы можете назначить имена его элементам при распаковке. Например, поскольку enumerate()будет предоставлять кортеж из двух элементов для каждого элемента в списке:

for index, item in enumerate(some_list):
    # do something with index and item

Вы также можете использовать это для замены переменных:

a, b = b, a

Вложенная распаковка тоже работает:

a, (b, c) = 1, (2, 3)

В Python 3 новый метод расширенной распаковки был представлен PEP3132 :

a, *rest = [1, 2, 3]
# a = 1, rest = [2, 3]
a, *middle, c = [1, 2, 3, 4]
# a = 1, middle = [2, 3], c = 4

Создать игнорируемую переменную 

Если вам нужно что-то назначить (например, в распаковке ), но вам не понадобится эта переменная, используйте __:

filename = 'foobar.txt'
basename, __, ext = filename.rpartition('.')

Заметка

Многие руководства по стилю Python рекомендуют использовать одно подчеркивание «_» для одноразовых переменных, а не двойное подчеркивание «__», рекомендованное здесь.Проблема заключается в том, что «_» обычно используется в качестве псевдонима дляgettext()функции, а также в интерактивном приглашении для хранения значения последней операции.Вместо этого использование двойного подчеркивания является столь же понятным и почти таким же удобным, и исключает риск случайного вмешательства в любой из этих других случаев использования.

Создайте список длины N того же самого 

Используйте *оператор списка Python :

four_nones = [None] * 4

Создание списка длины N списков 

Поскольку списки являются изменяемыми, *оператор (как указано выше) создаст список из N ссылок на один и тот же список, что вряд ли вам нужно. Вместо этого используйте понимание списка:

four_lists = [[] for __ in xrange(4)]

Примечание: используйте range () вместо xrange () в Python 3.

Создать строку из списка 

Распространенная идиома для создания строк — использовать str.join()пустую строку.

letters = ['s', 'p', 'a', 'm']
word = ''.join(letters)

Это установит значение переменной word в «spam». Эта идиома может применяться к спискам и кортежам.

Поиск предмета в коллекции 

Иногда нам нужно искать в коллекции вещей. Давайте рассмотрим два варианта: списки и наборы.

Возьмите следующий код для примера:

s = set(['s', 'p', 'a', 'm'])
l = ['s', 'p', 'a', 'm']

def lookup_set(s):
    return 's' in s

def lookup_list(l):
    return 's' in l

Хотя обе функции выглядят одинаково, поскольку lookup_set использует тот факт, что наборы в Python являются хеш-таблицами, производительность поиска между ними очень различна. Чтобы определить, есть ли элемент в списке, Python должен будет просмотреть каждый элемент, пока не найдет соответствующий элемент. Это отнимает много времени, особенно для длинных списков. В наборе, с другой стороны, хеш элемента сообщит Python, где в наборе искать соответствующий элемент. В результате поиск может быть выполнен быстро, даже если набор большой. Поиск в словарях работает так же. Для получения дополнительной информации см. Эту страницу StackOverflow . Для получения подробной информации о времени, которое различные общие операции выполняют для каждой из этих структур данных, см. Эту страницу .

Из-за этих различий в производительности часто рекомендуется использовать наборы или словари вместо списков в случаях, когда:

  • Коллекция будет содержать большое количество предметов
  • Вы будете неоднократно искать предметы в коллекции
  • У вас нет дубликатов.

Для небольших коллекций или коллекций, в которых вы не часто будете искать, дополнительное время и память, необходимые для настройки хэш-таблицы, часто будут больше, чем время, сэкономленное благодаря улучшенной скорости поиска.

Дзен питона 

Также известен как PEP 20 , руководящие принципы для дизайна Python.

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Некоторые примеры хорошего стиля Python см. На этих слайдах из группы пользователей Python .

Вот некоторые соглашения, которым вы должны следовать, чтобы сделать ваш код легче для чтения.

Проверьте, равна ли переменная постоянной 

Вам не нужно явно сравнивать значение с True, None или 0 — вы можете просто добавить его в оператор if. См. Проверка истинности значения для получения списка того, что считается ложным.

Плохо :

if attr == True:
    print 'True!'

if attr == None:
    print 'attr is None!'

Хорошо :

# Just check the value
if attr:
    print 'attr is truthy!'

# or check for the opposite
if not attr:
    print 'attr is falsey!'

# or, since None is considered false, explicitly check for it
if attr is None:
    print 'attr is None!

Доступ к элементу словаря 

Не используйте dict.has_key()метод. Вместо этого используйте синтаксис или передайте аргумент по умолчанию для .x in ddict.get()

Плохо :

d = {'hello': 'world'}
if d.has_key('hello'):
    print d['hello']    # prints 'world'
else:
    print 'default_value'

Хорошо :

d = {'hello': 'world'}

print d.get('hello', 'default_value') # prints 'world'
print d.get('thingy', 'default_value') # prints 'default_value'

# Or:
if 'hello' in d:
    print d['hello']

Короткие способы манипулирования списками 

Постижения списков предоставляют мощный и лаконичный способ работы со списками.

Выражения генератора следуют почти тому же синтаксису, что и списки, но возвращают генератор вместо списка.

Создание нового списка требует больше работы и использует больше памяти. Если вы просто собираетесь пройтись по новому списку, используйте вместо этого итератор.

Плохо :

# needlessly allocates a list of all (gpa, name) entires in memory
valedictorian = max([(student.gpa, student.name) for student in graduates])

Хорошо :

valedictorian = max((student.gpa, student.name) for student in graduates)

Используйте списки, когда вам действительно нужно создать второй список, например, если вам нужно использовать результат несколько раз.

Если ваша логика слишком сложна для понимания короткого списка или выражения генератора, рассмотрите возможность использования функции генератора вместо возврата списка.

Хорошо :

def make_batches(items, batch_size):
    """
    >>> list(make_batches([1, 2, 3, 4, 5], batch_size=3))
    [[1, 2, 3], [4, 5]]
    """
    current_batch = []
    for item in items:
        current_batch.append(item)
        if len(current_batch) == batch_size:
            yield current_batch
            current_batch = []
    yield current_batch

Никогда не используйте списочное понимание только для его побочных эффектов.

Плохо :

[print(x) for x in sequence]

Хорошо :

for x in sequence:
    print(x)

Фильтрация списка 

Плохо :

Никогда не удаляйте элементы из списка, пока вы просматриваете его.

# Filter elements greater than 4
a = [3, 4, 5]
for i in a:
    if i > 4:
        a.remove(i)

Не делайте несколько проходов по списку.

while i in a:
    a.remove(i)

Хорошо :

Используйте понимание списка или выражение генератора.

# comprehensions create a new list object
filtered_values = [value for value in sequence if value != x]

# generators don't create another list
filtered_values = (value for value in sequence if value != x)

Возможные побочные эффекты изменения исходного списка 

Изменение исходного списка может быть рискованным, если на него ссылаются другие переменные. Но вы можете использовать назначение срезов, если вы действительно хотите это сделать.

# replace the contents of the original list
sequence[::] = [value for value in sequence if value != x]

Изменение значений в списке 

Плохо :

Помните, что назначение никогда не создает новый объект. Если две или более переменных ссылаются на один и тот же список, изменение одной из них изменит их все.

# Add three to all list members.
a = [3, 4, 5]
b = a                     # a and b refer to the same list object

for i in range(len(a)):
    a[i] += 3             # b[i] also changes

Хорошо :

Безопаснее создать новый объект списка и оставить оригинал в покое.

a = [3, 4, 5]
b = a

# assign the variable "a" to a new list without changing "b"
a = [i + 3 for i in a]

Используйте enumerate()счетчик вашего места в списке.

a = [3, 4, 5]
for i, item in enumerate(a):
    print i, item
# prints
# 0 3
# 1 4
# 2 5

enumerate()Функция имеет лучшую читаемость , чем обработка счетчика вручную. Более того, он лучше оптимизирован для итераторов.

Читать из файла 

Используйте синтаксис для чтения из файлов. Это автоматически закроет файлы для вас.with open

Плохо :

f = open('file.txt')
a = f.read()
print a
f.close()

Хорошо :

with open('file.txt') as f:
    for line in f:
        print line

Это withутверждение лучше, потому что оно гарантирует, что вы всегда закроете файл, даже если внутри withблока возникнет исключение .

Продолжение строки 

Когда логическая строка кода длиннее допустимого предела, вам необходимо разбить ее на несколько физических строк. Интерпретатор Python объединяет последовательные строки, если последний символ строки является обратной косой чертой. Это полезно в некоторых случаях, но, как правило, его следует избегать из-за его хрупкости: пробел, добавленный в конец строки после обратной косой черты, нарушит код и может привести к неожиданным результатам.

Лучшее решение — использовать круглые скобки вокруг ваших элементов. Оставленный с незакрытой круглой скобкой в ​​конце строки, интерпретатор Python присоединится к следующей строке, пока круглые скобки не будут закрыты. То же самое относится и к фигурным и квадратным скобкам.

Плохо :

my_very_big_string = """For a long time I used to go to bed early. Sometimes, 
    when I had put out my candle, my eyes would close so quickly that I had not even 
    time to say “I’m going to sleep.”"""

from some.deep.module.inside.a.module import a_nice_function, another_nice_function, 
    yet_another_nice_function

Хорошо :

my_very_big_string = (
    "For a long time I used to go to bed early. Sometimes, "
    "when I had put out my candle, my eyes would close so quickly "
    "that I had not even time to say “I’m going to sleep.”"
)

from some.deep.module.inside.a.module import (
    a_nice_function, another_nice_function, yet_another_nice_function)

Однако чаще всего разделение длинной логической строки является признаком того, что вы пытаетесь сделать слишком много вещей одновременно, что может ухудшить читабельность.

В этом руководстве мы узнаем, что такое PEP-8 и как мы можем использовать его в кодировании Python. Мы обсудим рекомендации по использованию PEP в программировании – это руководство предназначено для начинающих и специалистов среднего уровня. Мы также обсудим преимущества использования PEP-8 в Python как правила для идеального кодирования.

PEP – это аббревиатура от Python Enterprise Proposal. Написание кода с правильной логикой является ключевым фактором программирования, но многие другие важные факторы могут повлиять на качество кода. Стиль кодирования разработчика делает код очень надежным, и каждый разработчик должен помнить, что Python строго следует порядку и формату строки.

Адаптивный красивый стиль кодирования делает код более читабельным. Код становится простым для конечного пользователя.

PEP 8 – это документ, который предоставляет различные рекомендации по написанию читаемого на Python. PEP 8 описывает, как разработчик может писать красивый код. Он был официально написан в 2001 году Гвидо ван Россумом, Барри Варшавой и Ником Когланом. Основная цель PEP – улучшить читаемость и согласованность кода.

Почему важен PEP 8?

PEP 8 улучшает читаемость кода Python, но почему читаемость так важна? Давайте разберемся с этой концепцией.

Создатель Python Гвидо ван Россум сказал, что код может быть написан за несколько минут, несколько часов или целый день, но как только мы напишем код, мы больше никогда его не переписываем. Но иногда нам нужно читать код снова и снова.

На этом этапе мы должны иметь представление о том, почему мы написали конкретную строку в коде. Код должен отражать значение каждой строки. Вот почему так важна удобочитаемость.

Мы опишем несколько важных рекомендаций по написанию эффективного кода, который также может быть прочитан другими.

Условные обозначения

Когда мы пишем код, нам нужно присвоить имя многим вещам, таким как переменные, функции, классы, пакеты и многое другое. Выбор собственного имени сэкономит время и силы. Когда мы через некоторое время оглядываемся на файл, мы можем легко вспомнить, что представляет собой определенная переменная, функция или класс. Разработчикам следует избегать выбора неподходящих имен.

Условные обозначения в Python немного запутаны, но есть определенные соглашения, которым мы можем легко следовать. Давайте посмотрим на следующие обозначения.

Пример –

Одна строчная буква

 
a = 10 

Одна заглавная буква

 
A = 10 

Строчные буквы

 
var = 10 

Строчные буквы с подчеркиванием

 
number_of_apple = 5 

ВЕРХНИЙ РЕГИСТР

 
VAR = 6 

ВЕРХНИЙ РЕГИСТР С ПОДЧЕРКИВАНИЕМ

 
NUM_OF_CARS =20  

Заглавные слова(или CamelCase)

 
NumberOfBooks = 100 

Примечание. При использовании сокращений в CapWords делайте все буквы сокращения заглавными. Таким образом, HTTPServerError лучше, чем HttpServerError.

Стили имен

Ниже приведена таблица, в которой указаны некоторые из распространенных стилей именования в Python. Рассмотрим следующую таблицу.

Тип Соглашение об именовании Примеры
Функция Мы должны использовать слова в нижнем регистре или разделять слова подчеркиванием. myfunction, my_function
Переменная Мы должны использовать строчные буквы, слова или отдельные слова, чтобы улучшить читаемость. a, var, variable_name
Класс Первая буква названия класса должна быть заглавной; используйте camel case. Не разделяйте слова подчеркиванием. MyClass, Form, Model
Метод Мы должны использовать строчные буквы, слова или отдельные слова, чтобы улучшить читаемость. class_method, method
Константа Использование  заглавных букв, слов или отдельных слов для повышения удобочитаемости. MYCONSTANT, CONSTANT, MY_CONSTANT
Модуль Мы должны использовать строчные буквы, слова или отдельные слова, чтобы улучшить читаемость. Module_name.py, module.py
Пакет Мы должны использовать строчные буквы, слова или отдельные слова, чтобы улучшить читаемость. Не разделяйте слова подчеркиванием. package, mypackage

Выше приведены некоторые общие соглашения об именах, которые можно использовать для улучшения кода Python. Для дополнительного улучшения мы должны тщательно выбирать имя.

Макет кода

Макет кода определяет, насколько код читается. В этом разделе мы узнаем, как использовать пробелы для улучшения читаемости кода.

Отступ

В отличие от других языков программирования, отступ используется для определения блока кода в Python. Отступы – важная часть языка программирования Python, определяющая уровень строк кода. Как правило, мы используем 4 пробела для отступа. Давайте разберемся в следующем примере.

 
x = 5 
if x ==  5: 
    print('x is larger than 5') 

В приведенном выше примере оператор печати с отступом будет выполнен, если условие оператора if истинно. Этот отступ определяет блок кода и сообщает нам, какие операторы выполняются при вызове функции или триггере условия.

Вкладки против пробела

Мы также можем использовать вкладки, чтобы предоставить последовательные пробелы, чтобы указать отступ, но пробелы являются наиболее предпочтительными. Python 2 позволяет смешивать табуляции и пробелы, но мы получим ошибку в Python 3.

Отступ после разрыва строки

Для продолжения строки важно использовать отступ, чтобы длина строки не превышала 79 символов. Это обеспечивает гибкость определения между двумя строками кода и одной строкой кода, которая расширяет две строки.

Пример –

 
# Correct Way: 
 
# Aligned with opening delimiter. 
obj = func_name(argument_one, argument_two, 
                         argument_three, argument_four 

Мы можем использовать следующую структуру.

 
# first line doesn't has any argument  
# We add 4 spaces from the second line to discriminate arguments from the rest. 
def function_name( 
        argument_one, argument_two, argument_three, 
        argument_four): 
    print(argument_two) 
 
# 4 space indentation to add a level. 
foo = long_function_name( 
    var_one, var_two, 
    var_three, var_four) 

Использование документационной строки

Python предоставляет два типа документационных строк – однострочные и многострочные. Мы используем тройные кавычки для определения однострочного или многострочного типа. В основном они используются для описания функции или конкретной программы. Давайте разберемся в следующем примере.

 
def add(a, b): 
    """This is simple add method""" 
 
    """This is 
    a 
   simple add program to add 
   the two numbers. """ 

Должна ли линия разрываться до или после бинарного оператора?

Строки разрываются до или после двоичной операции – это традиционный подход. Но это сильно влияет на удобочитаемость, потому что операторы разбросаны по разным экранам, и каждый оператор находится вдали от своего операнда и на предыдущей строке. Давайте разберемся в следующем примере.

Пример –

 
# Wrong: 
# operators sit far away from their operands 
marks =(engilsh_marks + 
          math_marks + 
         (science_marks - biology_marks) + 
          Physics_marks 

Как мы видим в приведенном выше примере, он кажется довольно запутанным для чтения. Мы можем решить подобные проблемы, используя следующую структуру.

Пример –

 
# Correct: 
# easy to match operators with operands 
Total_marks =(English_marks 
          + math_marks 
          +(science_marks - biology_marks) 
          + physics_marks 

Python позволяет нам разбивать строку до или после бинарного оператора, если соглашение согласовано локально.

Модуль импорта

Мы должны импортировать модули в разделительной строке следующим образом.

 
import pygame 
import os 
import sys 

Неверно

 
import sys, os 

Мы также можем использовать следующий подход.

 
from subprocess import Popen, PIPE 

Оператор импорта должен быть написан в верхней части файла или сразу после любого комментария модуля. Рекомендуется использовать абсолютный импорт, потому что он более удобочитаемый и, как правило, ведет себя лучше.

 
import mypkg.sibling 
from mypkg import sibling 
from mypkg.sibling import example 

Однако мы можем использовать явный относительный импорт вместо абсолютного импорта, особенно при работе со сложными пакетами.

Пустые строки

Пустые строки могут улучшить читаемость кода Python. Если много строк кода сгруппированы вместе, код станет труднее читать. Мы можем удалить это, используя множество пустых вертикальных линий, и читателю может потребоваться прокрутить больше, чем необходимо. Следуйте приведенным ниже инструкциям, чтобы добавить вертикальный пробел.

  • Функция верхнего уровня и классы с двумя линиями – поместите вокруг них дополнительное вертикальное пространство, чтобы было понятно.
 
class FirstClass: 
    pass 
 
 
class SecondClass: 
    pass 
 
 
def main_function(): 
 
    return None 
  • Одна пустая строка внутри классов – функции, которые мы определяем в классе, связаны друг с другом. Давайте посмотрим на следующий пример –
 
class FirstClass: 
    def method_one(self): 
        return None 
 
    def second_two(self): 
        return None 
  • Используйте пустые строки внутри функции – иногда нам нужно написать сложную функцию, состоящую из нескольких шагов перед оператором возврата. Таким образом, мы можем добавлять пустую строку между каждым шагом. Давайте разберемся в следующем примере.
 
def cal_variance(n_list): 
    list_sum = 0 
    for n in n_list: 
        list_sum = list_sum + n 
    mean = list_sum / len(n_list) 
 
    square_sum = 0 
    for n in n_list: 
        square_sum = square_sum + n**2 
    mean_squares = square_sum / len(n_list) 
 
    return mean_squares - mean**2 

Вышеупомянутый способ может удалить пробелы, чтобы улучшить читаемость кода.

Закрывающие скобки

Мы можем разбивать строки внутри круглых скобок, используя продолжения строки. PEP 8 позволяет нам использовать закрывающие фигурные скобки в подразумеваемых продолжениях строк. Давайте разберемся в следующем примере.

  • Совместите закрывающую скобку с первым непробельным символом.
 
    list_numbers = [ 
    5, 4, 1, 
    4, 6, 3, 
    7, 8, 9 
     ] 
  • Совместите закрывающие фигурные скобки с первым символом строки.
 
list_numbers = [ 
    5, 4, 1, 
    4, 6, 3, 
    7, 8, 9 
] 

Оба метода подходят для использования, но ключевым моментом является последовательность, поэтому выберите любой и продолжайте.

Комментарии

Комментарии являются неотъемлемой частью любого языка программирования. Это лучший способ объяснить код. Когда мы задокументировали наш код с соответствующими комментариями, каждый сможет понять код. Но следует помнить о следующих моментах.

  • Начните с заглавной буквы и напишите полное предложение.
  • Обновите комментарий в случае изменения кода.
  • Ограничьте длину строки комментариев и строк документации 72 символами.

Блочный комментарий

Блочные комментарии – хороший выбор для небольшого участка кода. Такие комментарии полезны, когда мы пишем несколько кодов строк для выполнения одного действия, такого как повторение цикла. Они помогают нам понять цель кода.

PEP 8 предоставляет следующие правила для записи блока комментариев.

  • Комментарий блока отступа должен быть на одном уровне.
  • Каждую строку начинайте с символа #, за которым следует один пробел.
  • Выделите строку одним знаком #.

Посмотрим на следующий код.

 
for i in range(0, 5): 
    # Loop will iterate over i five times and print out the value of i 
    # new line character 
    print(i, 'n') 

Мы можем использовать больше абзаца для технического кода.

Встроенные комментарии

Встроенные комментарии используются для объяснения одного оператора в фрагменте кода. Мы можем быстро понять, почему мы написали именно эту строку кода. PEP 8 определяет следующие правила для встроенных комментариев.

  • Комментарии в Python начинаются с символа # и одного пробела.
  • Осторожно используйте встроенные комментарии.
  • Мы должны разделять встроенные комментарии в той же строке, что и утверждение, на которое они ссылаются.

Ниже приведен пример встроенных комментариев.

 
a = 10    # The a is variable that holds integer value. 

Иногда мы можем использовать соглашение об именах, чтобы заменить встроенный комментарий.

 
x = 'Peter Decosta' #This is a student name 

Мы можем использовать следующее соглашение об именах.

 
Student_name = 'Peter Decosta' 

Встроенные комментарии необходимы, но блочные комментарии делают код более читабельным.

Излишнее добавление пробелов

В некоторых случаях использование пробелов может затруднить чтение кода. Слишком много пробелов может сделать код слишком разреженным и трудным для понимания. Не следует добавлять пробелы в конце строки. Это известно как завершающие пробелы.

Посмотрим на следующий пример.

Пример – 1

 
# Recommended 
list1 = [1, 2, 3] 
 
# Not recommended 
List1 = [ 1, 2, 3, ] 

Пример – 2

 
x = 5 
y = 6 
 
# Recommended 
print(x, y) 
 
# Not recommended 
print(x , y) 

Рекомендации по программированию

Как мы знаем, в Python есть несколько методов для выполнения аналогичных задач. В этом разделе мы увидим некоторые предложения PEP 8 по улучшению согласованности.

  • Избегайте сравнения логических значений с помощью оператора эквивалентности
 
# Not recommended 
bool_value = 10 > 5 
if bool_value == True: 
    return '10 is bigger than 5' 

Мы не должны использовать оператор эквивалентности == для сравнения логических значений. Он может принимать только Истину или Ложь. Посмотрим на следующий пример.

 
# Recommended 
if my_bool: 
    return '10 is bigger than 5' 

Этот подход прост, поэтому PEP 8 поощряет его.

  • Пустые последовательности ложны в операторах if

Если мы хотим проверить, является ли данный список пустым, нам может потребоваться проверить длину списка, поэтому нам нужно избегать следующего подхода.

 
# Not recommended 
list1 = [] 
if not len(list1): 
    print('List is empty!') 

Однако, если есть пустой список, набор или кортеж. Мы можем использовать следующий способ проверки.

 
# Recommended 
list1 = [] 
if not list1: 
    print('List is empty!') 

Второй способ более уместен; вот почему PEP 8 поощряет это.

  • Не используйте оператор not is in if

Есть два варианта проверить, имеет ли переменная определенное значение. В первом варианте x не равно None, как в следующем примере.

 
# Recommended 
if x is not None: 
    return 'x exists!' 

Второй вариант – оценить x как None и оператор if, основанный не на результате.

 
# Not recommended 
if not x is None: 
    return 'x exists!' 

Оба варианта верны, но первый прост, поэтому PEP 8 поддерживает его.

Заключение

Мы обсудили рекомендации PEP 8, чтобы код устранял двусмысленность и улучшал читаемость. Эти рекомендации улучшают код, особенно когда вы делитесь кодом с потенциальными сотрудниками или соавторами. Мы обсудили, что такое PEP и почему он используется, как писать код, совместимый с PEP 8. Кроме того, у нас есть краткое введение в соглашения об именах. Если вам нужна дополнительная информация о PEP 8, вы можете прочитать полную документацию или посетить pep8.org.

Изучаю Python вместе с вами, читаю, собираю и записываю информацию опытных программистов.

Синтаксис, правила написания кода в Python.

Одним из ключевых моментов PEP 8 является то, что код читается гораздо чаще, чем пишется. Приведенные здесь рекомендации предназначены для улучшения читабельности кода и обеспечения его согласованности с широким спектром кода Python. Как говориться в Дзене Python «Читаемость имеет значение».

Руководство по стилю о последовательности:

  • Согласованность с PEP 8 по стилю кодирования очень важна.
  • Согласованность внутри проекта важнее.
  • Согласованность внутри одного модуля или функции является наиболее важной.

Однако, иногда рекомендации по стилю просто не применимы. В случае сомнений используйте свое решение. Посмотрите на другие примеры и решите, что выглядит лучше. И не стесняйтесь спрашивать! В общем, не нарушайте обратную совместимость только из за соблюдения PEP 8!

Некоторые другие веские причины игнорировать это руководство:

  • Применение PEP 8 в проекте сделает код менее читабельным, даже для тех, кто привык читать код, который следует этому PEP.
  • Рассматриваемый код похож по стилю с ранее написанным кодом, который также нарушает PEP 8 (возможно, по историческим причинам) — хотя это возможность привести чужой код в порядок.
  • Рассматриваемый код предшествует введению руководства, и нет никаких других причин для изменения этого кода.
  • Когда код может остаться совместимым со старыми версиями Python, который не поддерживает функции, рекомендованную в PEP.

Разметка кода Python, PEP 8

Отступы в коде. TAB или пробелы? Максимальная длина строки с кодом. Разрыв строки до или после двоичного оператора? Пустые строки. Кодировка файла с кодом. Импорт. Кавычки в строках.

Пробелы в выражениях и операторах языка Python

Раздражители и другие рекомендации по пробелам в выражениях и операторах

Когда использовать запятые в коде на Python

Конечные запятые обычно необязательны, за исключением того, что они обязательны при создании кортежа из одного элемента

Комментарии в коде языка Python

Комментарии, которые противоречат коду, хуже, чем отсутствие комментариев. Всегда делайте приоритет обновления комментариев при изменении кода!

Соглашения об именах в Python

Соглашения об именах библиотеки Python немного беспорядочные, поэтому мы никогда не получим полное согласование. Тем не менее, вот рекомендуемые в настоящее время стандарты именования.

Рекомендации по программированию на Python

Код должен быть написан так, чтобы не зависеть от разных реализаций языка (PyPy, Jython, IronPython, Pyrex, Psyco и пр.).

Сообщество приняло набор стилевых рекомендаций PEP8, который Гвидо ван Россум, создатель языка, предложил еще в 2001 году. Как применять и когда отступать — рассказываем в этой статье.

Что такое стандарты PEP8 для языка Python

С предсказуемым кодом приятно работать: сразу понятно, где импортированные модули, константа здесь или переменная и в каком блоке текущая строка. Для предсказуемости важны стиль и оформление, особенно в Python, который многое прощает разработчику.

Требования PEP8 по оформлению Python-кода

Единообразие, наглядность и информативность — это основа PEP8. Страница с текстом предложения постоянно дополняется, рекомендуем иногда перечитывать.

Структура кода

В Python внутренние блоки кода выделяются отступами, а не специальными разделителями. Размер отступа — четыре пробела, табуляция не используется:

if (expression_is_true):
do_this()
elif (other_expression_is_true):
do_that()
else:
do_something_else()

Для удобства настройте табуляцию в любимом редакторе на проставление четырех пробелов.

Аргументы функций переносятся на следующую строку и выравниваются, если строка слишком длинная:

def long_func (arg_one, arg_two,
arg_three, arg_four)

def extra_long_function_name (
arg_one, arg_two, arg_three,
arg_four):
do_something()

Некоторые редакторы при переносе строки добавляют спецсимвол, поэтому вместо стандартных 80 символов максимальная длина строки в PEP8 — 79. Комментарии и документация — 72 символа.

Максимальную длину строки разрешается увеличить до 99 символов, если стандартные 79 ухудшают читаемость кода.

Знаки операций ставятся после переноса строки:

total_users = (currently_online
+ offline_but_active
+ offline_inactive
- duplicate_accounts
- banned)

Между функциями верхнего уровня и классами вставляются две пустые строки. Между определениями методов в классе — одна пустая строка. Разрешается добавлять пустые строки между логическими секциями, но не злоупотребляйте этим:

do_stuff()
do_similar_stuff()

do_different_stuff()

do_something_else_entirely()

Правила выбора имен

По правильно названной переменной или функции сразу понятно, зачем они нужны: в first_name лежит имя, а calculate_employee_salary() считает зарплату сотрудника.

Старайтесь использовать полные имена. Их проще читать, а с сокращениями вы и сами потом с трудом разберетесь:

# Правильно

first_name = ‘Ivan’
last_name = ‘Ivanov’

def plus_one (x):
return x + 1

# Неправильно

fnm = ‘Ivan’
lnm = ‘Ivanov’

# Plus 1? Phase 1? Point 1?
def p1 (x):
return x + 1

Придерживайтесь этих стилей именования:

Тип Рекомендация Примеры
Функция Одно или несколько слов в нижнем регистре, нижние подчеркивания для улучшения читаемости (snake case) function, add_one
Переменная Одна буква, слово или несколько слов в нижнем регистре, нижние подчеркивания для улучшения читаемости x, connection, first_name
Класс Одно или несколько слов с большой буквы без пробелов (camel case) Image, UserData
Метод Одно или несколько слов в нижнем регистре, нижние подчеркивания для улучшения читаемости draw(), get_user_data()
Константа Одна буква, слово или несколько слов в верхнем регистре, нижние подчеркивания для улучшения читаемости PI, MAX_CONNECTIONS
Модуль Короткое слово или слова в нижнем регистре, нижние подчеркивания для улучшения читаемости module.py, user_data.py
Пакет Короткое слово или слова в нижнем регистре без подчеркиваний package, userdata

Проверка истинности без знаков равенства

Условия с булевыми значениями проверяются без оператора эквивалентности (==):

# Правильно

if this_is_true:
do_something()

if not this_is_false:
do_something_else()

# Неправильно

if this_is_true == True:
do_something()

if this_is_false == False:
do_something_else()

Сравнение с None делается с помощью операторов is / is not:

if connection is None:
print_error_message()

if user is not None:
get_user_data()

Пустой массив, список, словарь или строка — это False. С содержимым — уже True:

first_name = ‘’

if not first_name:
do_something () # выполнится
colors = [‘red’]

if colors:
do_something_else() # выполнится

Использование комментариев

Хороший комментарий — полезный комментарий. Пользуйтесь простым и понятным языком и не забывайте обновлять их, если код меняется. Рекомендации PEP8:

  1. Пишите полные предложения с заглавной буквы, если это не название.
  2. Ставьте два пробела после точки в комментариях, кроме последнего предложения.
  3. Пишите на английском, если читатели не знают ваш язык.

Блочные комментарии объясняют следующий за ними участок кода. Выравнивайте их на том же уровне и начинайте каждую строку с # и пробела. Параграфы в блочных комментариях разделяются строкой с одной #:

# Returns a filled UserData object for the current user ID if user exists, None otherwise. Assumes database connection is already open
#
# TODO: very poor performance, rewrite it!

def get_user_data (db_connection, user_id)

Не злоупотребляйте комментариями на той же строке (внутренними). Они не должны объяснять очевидных вещей и затруднять чтение кода. Отделяйте их от текста как минимум двумя пробелами и начинайте с # и пробела:

# Правильно

first_name = ‘Ivan’ # test user, shouldn’t show up in prod

# Неправильно
first_name = ‘Ivan’ # first name

Пишите документацию для всех публичных модулей, функций, классов и методов. В приватных можно ограничиться комментариями, зачем они нужны и как используются.

В многострочных комментариях “”” в конце переносится на новую строку:

“””Run the provided database request. Scalar only!
For everything else, use db_query().
“””

В однострочных комментариях открывающие и закрывающие “”” — на той же строке:

“””Flush buffer and close the file”””

Выражения и инструкции

Стандартная кодировка для Python 3 — UTF8. В Python 2 — ASCII, которая не поддерживает кириллицу. Пользуйтесь Windows 1251 или аналогами:

# coding: cp1251
print (“Текст кириллицей”)

Импортируйте модули в начале файла, сразу после верхнеуровневых комментариев и строк документации. Группируйте их и разделяйте группы пустыми строками: сначала стандартная библиотека, потом — сторонние, в конце — локальные модули проекта. При импорте каждый модуль пишется с новой строки. Совмещайте несколько импортов из одного модуля:

import os
from math import pi, sin

Разделяйте условия, циклы и обработку исключений на отдельные строки, кроме тривиальных случаев:

# Правильно

if this_is_true
and that_is_true
and something_else_is_true:
do_stuff();
do_other_stuff();

# Допустимо
if file_position &amp;amp;lt; 0: file_position = 0 # file system quirk # Неправильно if this and that and something_else: do_stuff(); do_other_stuff() 

Использование запятых

Кортеж из одного элемента отделяется запятой и берется в скобки для улучшения читаемости. Для систем контроля версий элементы в списке пишутся с новой строки и отделяются запятыми, если список будет расширяться. В остальных случаях запятые не ставятся:

# Правильно

TEST_USERS = (‘ivanov_i’, )

TEST_ACCOUNT_IDS = [

‘123’,

‘456’,

]

# Неправильно

TEST_USERS = ‘ivanov_i’,

TEST_ACCOUNT_IDS = [‘123’, ‘456’, ]

Рекомендации по программированию

Определяйте функции с аннотациями типов аргументов и возвращаемых значений. Стрелка окружается пробелами с обеих сторон:

def sum(a: int, b: int) -&amp;gt; int:
return a + b

Для типов переменных вставляйте один пробел после двоеточия. Знак присваивания окружается пробелами с обеих сторон:

# Правильно

user_count: int

class UserData:
first_name: str = ‘replace_me’
login_and_password_hash: Tuple[str, str]

# Неправильно

user_count:int
user_count : int

class UserData:
first_name: str=’’

Не забудьте указать специальный комментарий, чтобы автоматические проверки игнорировали файл, если в проекте используются любые другие виды аннотаций:

# type: ignore

По умолчанию интерпретаторы Python должны игнорировать проверку типов и сохранять такое же поведение, как и без аннотаций. Линтеры и другой инструментарий — опциональны.

Другие рекомендации, на которые стоит обратить внимание:

  1. Используйте стандартную библиотеку, а не конкретную имплементацию (PyPy, CPython и т. д.).
  2. Реализуйте все операторы (__eq__, __ne__, __lt__, __le__, __gt__, __ge__) для сравнения элементов, не доверяйте внешнему коду в использовании только одного или нескольких.
  3. Определяйте функции ключевым словом def, а не знаком равенства: равенство оставляйте для лямбд.
  4. Наследуйте исключения от Exception вместо BaseException: BaseException зарезервировано для исключений, ловить которые — плохая идея.
  5. Сохраняйте стек вызовов при обработке цепочки исключений.
  6. Обрабатывайте конкретное исключение: слишком широкое условие (или пустой оператор except) поймает больше, чем нужно.
  7. Минимизируйте количество кода в try-блоке: в длинных условиях легче потеряться или проглотить ошибку.
  8. Очищайте локальные ресурсы с помощью with или try/finally.
  9. Вызывайте методы в менеджерах контекста явно. Исключение — резерв или возврат ресурса.
  10. Возвращайте единообразные значения: либо везде пустой return, либо везде результат или None.
  11. Проверяйте префиксы и суффиксы строк с помощью .startswith() и .endswith().
  12. Сравнивайте типы объектов через isinstance().
  13. Избегайте строковых литералов с пробельными символами в конце: некоторые редакторы и модули их обрежут.

Как проверить код на соответствие стандартам PEP8

Ручная проверка плохо подходит даже для небольших проектов: отнимает время, легко ошибиться. Используйте готовые инструменты:

  1. Среды разработки, например PyCharm.
  2. Pylint — для статического анализа и проверки стиля.
  3. Flake8 — для проверки стиля.

Pylint, Flake8 и многое другое лежит в разделе Python Code Quality Authority на гитхабе.

Когда можно проигнорировать соблюдение стандартов

Когда соблюдение стандартов ухудшает код. Помните: единообразный код понятнее и лучше читается. Например, PEP8 не применяется, если проект не доступен публично и уже использует другой стиль — или разрабатывался под старые версии Python. Для публичных библиотек PEP8 обязателен.

В проектах без единого стиля — договоритесь с командой и берите PEP8.

Коротко о главном

  1. Пишите единообразный код: его приятнее читать и легче воспринимать. PEP8 — стилевой стандарт сообщества.
  2. Выравнивайте блоки кода и отделяйте логические секции пустыми строками.
  3. Выбирайте понятные и однозначные имена для объектов.
  4. Добавляйте полезные комментарии. Обновляйте их, когда код меняется.
  5. Обрабатывайте исключения с узкими и краткими условиями.
  6. Берите автоматические инструменты проверки.
  7. Игнорируйте стандарты, если их соблюдение ухудшит код.

Понравилась статья? Поделить с друзьями:
  • Банк союз руководство банка
  • Транексам инструкция по применению при месячных отзывы таблетки кровотечении
  • 3 stage knife sharpener инструкция на русском языке
  • Руководство исследовательской деятельностью учащихся
  • Смотреть фильм руководство нянь поймать монстра 1 сезон