The purpose of this article

“Dynamic typing is fun, code refactoring is a crematorium.” Dynamic languages are fun to develop in the early stages, but difficult to maintain in the later stages. As one of the dynamic languages, Python naturally has such disadvantages. Actually say “crematorium”, also not so serious, as long as strictly abide by a set of norms, also can achieve “reconstruction of the time, also the same cool”.

Rules are important, especially in dynamic languages (many people write Python scripts at will, which makes maintenance difficult). As the saying goes, we should do enough “surface work” before we start writing code.

Which are not covered in this article

Do not do “document rereader”. It’s already in PEP 8, so I won’t repeat it. It’s not interesting to repeat the “low level” stuff.

In fact, I don’t recommend the “Google Python Guide”, which is a specification for Google, not a community specification. I think this specification is both incomplete and “everyone knows” and I don’t recommend it.

Shun religion and flatter pragmatism. For example, the typical “import this”, am I the only one who thinks it is just a bunch of empty nonsense, besides, many places in the Python standard library, also do not do “simple, explicit, and powerful” in “import this”. Every time this is mentioned in various articles (unscrupulous marketing articles, with various training institutions as the main body), I feel uncomfortable & embarrassed (writing code is very engineering and serious business, why engage in such metaphysics).

Scope of application & Principle

  • Python 2.7-Python 3.x. Although Python 2 has an official lifespan of 2020, it seems that Python 3 is now mainstream. But, boy, legacy code can’t just be removed, and Python 2 will still be around for quite some time. Also, does Python 3 have a “killer feature” relative to Python 2? No.
  • Modeled after PEP 8 and closely rallied around PEP 8. Any unofficial documentation is for reference only (in the same way, this article is a reference of sorts).
  • PEP 8 already has it, so don’t repeat it.

specification

[Force + Force] [Select a “static check” tool and use it strictly from beginning to end]

In short, this means: 1. Pylint 2. Flake8 3. pyTest should be used from the start, and used strictly (the benefits of taking the time to learn about these tools are infinite, if you are a more formal project).Copy the code

【 使 用 UT】

The same goes for other programming languages. Have a UT in hand, rebuild up, the heart rest assured a lot. For Python, all you need to know is unittest, and pyTest will do.Copy the code

[Mandatory] [File Encoding & Unicode]

PS: I think it’s important that the following tips help you avoid a lot of boring coding problems

  1. Use 4 Spaces to indent, disabling any TAB characters
  2. Source files use UTF-8 without BOM
  3. Always use Unix \n style newlines
  4. In each py header, add the following:
#! /usr/bin/env python
# -*- coding: utf-8 -*-
#
 

# Import only these two features of the Future space. The other features are likely to cause "incompatibilities" in other areas and are not necessary to use.From __future__ import (absolute_import, unicode_literals) So, you need to know about EditorConfigCopy the code

###【 mandatory 】【 Name 】

  1. How to name class, function, do not elaborate, strictly follow PEP8 to do, do not think much.
  2. Global variables should always be capitalized, such as:
GLOBAL_PUBLIC = "G1"
_GLOBAL_PRIVATE = "G2"

class Person:
    _GLOBAL_IN_CLASS = 'G3'According to this requirement, in fact, many libraries or open source libraries, are not in line with the requirements. Why so tough? Variables defined in Python, there is no "declaration", "definition", "initialization", "value" concept, so an a = 1 if there is no context, you are difficult to determine its scope, also it is difficult to determine What is initialize or assign a value (a) already exists, if global variables also does not use all uppercase, It's only gonna bring more trouble. If you stick to this principle, it will greatly improve the readability of your code.Copy the code

[Mandatory] Define enumeration, always add Enum suffix; Always suffix an Exception when defining an Exception; To define a mixin, always add a mixin suffix, such as

class DirectionEnum:
    UP = 1
    DOWN = 2
    
    
class MyException(Exception):
    pass
class MyError(Exception):
    pass
    
class SomeMixin:
    pass
Copy the code

2. To enforce the concept of private

The principle of least knowledge: the less you expose, the better Example attributes, generally defined as private 2. class, the less externally provided methods, the better 3. Module, the less externally provided interfaces, the better 4. Package, the less externally provided modules, the better Project layout Package / __init__.py _private_mod.py public_mod.py 2. Contents of a module public_mod.py PUBLIC_GLOBAL ='G1'
_PRIVATE_GLOBAL = 'G2'
class _Class:
    pass
class PublicClass:
    _PRIVATE_GLOBAL = 'G3'def __init__(self, name,age): self._name = name self._age = age def public_method(self): pass def _private(self): Pass everything, you define it to be private from the start, and you don't make it public until you really need open access.Copy the code

[Mandatory & Important] [Concern about the complexity of exposed interfaces]

Def interface(p1, p2); / / def interface(p1, p2); / / def interface(p1, p2); / / def interface(p1, p2); / / def interface(p1, p2); / / def interface(p1, p2); / / def interface(p1, p2); Pass The maximum tolerated interface is def interface(p1, p2, p3='SOME DEFAULT'): pass def interface(p1, *args): pass def interface(p1, *args): Def interface(*args, **kwargs):# Try not to use **kwargs, some popular libraries have this problem, I think: greatly increases the psychological burden of the caller, reflecting interface designer lazinessPass has always felt that **kwargs are only suitable for very specific situations and need to be clearly documented (explaining why they should be used), but the reality is that this feature has been abused and needs to be explained separately.Copy the code

PS: I have always felt that the abuse of ** Kwargs API, almost all are not good API, intangible increase psychological burden.

Design namespaces based on packages, not Modules

【推荐】【 推荐】

Function of __init__.py function of __main__.pyif __name__ == '__main__': functions as Python's namespace loading mechanism, namely: sys.path sys.modules contentsCopy the code

Design project directory structure reasonably

If you're using a framework (such as Django), follow the framework's specifications. If it's a "non-framework" project, Py core/ utils/ constants/ __main__.py tests/ docs/ examples/ readme.md. pylintrc .flake8Copy the code