参考PEP8


格式规范


检查工具:pylint、flake8
依赖安装:
pip install flake8
pip install pylint
pip install flake8-docstrings
pip install flake8-import-order
检查命令:
pylint -r y ${PROJECT}
flake8 —docstring-convention google —import-order-style google —application-import-names app ${PROJECT}
风格规范:Google Style
参考链接:https://github.com/google/styleguide/blob/gh-pages/pyguide.md#382-modules

编程规范


1、主逻辑判断放外层
说明:能写一层就不写多层,方便阅读和代码逻辑扩展。
示例:

  1. if user_name:
  2. if password:
  3. print("yes")
  4. else:
  5. raise Exception("No password")
  6. else:
  7. raise Exception("No user_name")

修正:

  1. if not user_name:
  2. raise Exception("No user_name")
  3. if not password:
  4. raise Exception("No password")
  5. print("yes")


2、避免hard_code,统一管理常量
示例:

  1. def my_func(var_a, var_b, max_bytes=510241024):
  2. """docstring..."""


修正:

  1. # Constants我们把常量写在一个Module中
  2. def my_func(var_a, var_b, max_bytes=Constants.MAX_BYTES):
  3. """docstring..."""

3、移除不必要的常量,不要hard code
说明:如果不存在引用该常量,那么就舍弃掉。
示例:

  1. class Constant:
  2. """docstring..."""
  3. MODULE_REDIS = "single_redis"
  4. MODULE_APOLLO = "apollo"
  5. MODULE_LOG = "log" # 这里的MODULE_LOG只是纯粹为了和上述保持一致


修正:不需要形式上的统一,没有使用到就移除掉

  1. class Constant:
  2. """docstring..."""
  3. MODULE_REDIS = "single_redis"
  4. MODULE_APOLLO = "apollo"


4、文档说明,要句子不要短语
说明:句子以大写字母开头,以实心点结尾。
示例:

  1. def get_logger(name):
  2. """logger instance"""


修正:

  1. def get_logger(name):
  2. """Get a logger with the specified name."""


5、文档说明,不要口语化
说明:句子不要以We开头,不要无效的修饰。
示例:

  1. def get_logger(name):
  2. """Here we just want to get a logger instance with specified name."""


修正:

  1. def get_logger(name):
  2. """Get a logger with the specified name."""


6、任务拆解,每个MR只做一件事
说明:如果有多件事需要做,可以在代码中留TODO,以备下一个MR提交。
7、变量精简,减少重复赋值
示例:

  1. host, port = db_uri.split(",")
  2. date_base = MySql(hostport)
  3. class MySql:
  4. """docstring..."""
  5. def init(self, host, port):
  6. """docstring"""
  7. self.host = host
  8. self.port = port

修正:

  1. date_bae = MySql(db_uri)
  2. class MySql:
  3. """docstring..."""
  4. def init(self, db_uri):
  5. """docstring..."""
  6. self.host, self.port = db_uri.split(",")


8、函数原子,模块原子
说明:一个函数干一件事,一个模块干一个事。
示例:

  1. class ConfigCenter:
  2. """docstring..."""
  3. ... ...
  4. def log_socket_uri(self):
  5. """docstring..."""
  6. section = Constant.SECTION_LOG
  7. entry = Constant.ENTRY_LOG_SOCKET_URI
  8. socket_uri = self.config.get(section, entry)
  9. host, port = socket_uri.split(",")
  10. if int(port) < 0 or int(port) > 65536:
  11. raise ValueError("invalid port")
  12. return host, port


修正:配置中心的任务就是读配置,不需要做配置拆解,也不需要做拆解之后的校验

  1. class ConfigCenter:
  2. """docstring..."""
  3. ... ...
  4. def log_socket_uri(self):
  5. """docstring..."""
  6. section = Constant.SECTION_LOG
  7. entry = Constant.ENTRY_LOG_SOCKET_URI
  8. socket_uri = self.config.get(section, entry)
  9. return socket_uri


9、避免为了形式好看而注释,让代码一目了然
说明:除非代码相对冗长且不可拆解,否则,不需要形式上的注释。
示例:

  1. def get_instance():
  2. """docstring..."""
  3. # for log console
  4. log_console = config.log_console
  5. # for log file
  6. log_dir = config.log.file_dir
  7. os.makedirs(log_dir, exist_ok=True)
  8. # for log socket
  9. socket_uri = config.log_socket_uri


修正:不要好看,让代码自己一目了然,可以以空行间隔

  1. def get_instance():
  2. """docstring..."""
  3. log_console = config.log_console
  4. log_dir = config.log.file_dir
  5. os.makedirs(log_dir, exist_ok=True)
  6. socket_uri = config.log_socket_ur

10、不要做变量的重复性赋值和拆解
说明:避免重复性劳动,或者没必要的打包
示例:

  1. class ConfigCenter:
  2. """docstring..."""
  3. ... ...
  4. def redis_config(self):
  5. """docstring..."""
  6. ...
  7. redis_uri = self.config.get(Constant.SECTION_REDIS, Constant.ENTRY_REDIS_URI)
  8. return {Constant.REDIS: redis_uri}


修正:不必要的打包不要打

  1. class ConfigCenter:
  2. """docstring..."""
  3. ... ...
  4. def redis_config(self):
  5. """docstring..."""
  6. ...
  7. redis_uri = self.config.get(Constant.SECTION_REDIS, Constant.ENTRY_REDIS_URI)
  8. return redis_uri


11、description 需要写完整的句子
说明:description 不能是单个词或短语,而应该为完整的句子
示例:

  1. class UserUpdate(BaseModel): # pylint: disable=too-few-public-methods
  2. """Body of Person PATCH requests."""
  3. username: Optional[str] = Field(None,
  4. max_length=20,
  5. description="username")


修正:

  1. class UserUpdate(BaseModel): # pylint: disable=too-few-public-methods
  2. """Body of Person PATCH requests."""
  3. username: Optional[str] = Field(None,
  4. max_length=20,
  5. description="The name of user.")

12、每行只导入一个 module
说明:在导入module时,应该每行只导入一个
示例:

  1. from app.schemas.user import UserCreate, UserRead, UserUpdate


修正:

  1. from app.schemas.user import UserCreate
  2. from app.schemas.user import UserRead
  3. from app.schemas.user import UserUpdate


13、函数注释使用有实际意义的 docstrings
说明:函数注释不能太过简略,要能够表达实际意义
示例:

  1. class UniversalCacheInterface(ABC):
  2. """Universal Cache Interface."""
  3. @abstractmethod
  4. def get(self, key, *args):
  5. """Get Method, Force to Implements."""


修正:

  1. class UniversalCacheInterface(ABC):
  2. """Universal Cache Interface."""
  3. @abstractmethod
  4. def get(self, key):
  5. """Return value for key in cache, force subclass to implement.""

14、interface 的方法定义中不宜使用 *args 参数
说明:在 interface 定义的方法中不宜出现 *args,因为需要精准把控方法接收的参数。
示例:

  1. class ClusterRedis(UniversalCacheInterface):
  2. def __init__(self, conn_list, redis_password):
  3. """Constructs a redis cluster instance."""
  4. self.instance = RedisCluster(startup_nodes=conn_list,
  5. decode_responses=True,
  6. password=redis_password)
  7. def get(self, key, *args):


修正:

  1. def get(self, key):
  2. """Return value for key."""
  3. return self.instance.get(key)


如果需要某个参数,例如ttl,可以逐个添加:

  1. def set(self, key, value, ttl=None):
  2. """Set key-value in redis cluster."""
  3. return self.instance.set(key, value, ex=ttl)