一、创建文件时的模板定义

💤 添加自定义模板

打开 Pycharm 设置并选中 File -> Settings -> Editor -> File and Code Templates

file 中选中需要修改的脚本类型,如 Python Script

🌽 代码模板

#!/usr/bin/python
# -*- coding:utf-8 -*-
# @author  : 青年有志
# @time    : ${DATE} ${TIME}
# @function: the script is used to do something.
# @version : V1

效果:

二、python 注释规范

python 有两种方式进行注释:

  • DocStrings:这种方式的注释是 python 提供的一种语言特性,即 python 代码本身是 “自注释” 的,即便编译成 pyc 二进制文件,DocStrings 仍然是存在的。
  • 普通注释:“#” 开头的注释,这种类型的注释和其他编程语言是一致的,编译成 pyc 后就消失了。

例如:

def print_msg(msg):
    '''
    这里是 DocStrings 注释
    
    Args:
        msg (str): the msg to show
    '''
    # 这里是普通注释
    print("hello" + msg)

这两种方式的注释是有区别的:

  • DocStrings 注释是给 “用户” 看的(自己也可以是用户),例如编写了一个模块、库,供别人或自己使用,那么就需要使用 DocStrings 编写注释,这里的注释更像是 “使用手册”
  • 普通注释是给 “开发者” 看的,它们需要通过普通的注释去了解代码内部的原理

使用 help 函数可以格式化输出 DocStrings

example:

help(sum)

🌙 注释风格

常见的 python 程序注释风格有 3 种:

  • google 推荐的注释风格,支持模块、类、函数、变量注释,非常详细,且易于阅读。
  • numpy 风格的注释,支持模块模块、类、函数、变量注释,同样易于阅读。
  • sphinx 风格的注释,支持函数、类,通过sphinx格式化输出比较漂亮,但阅读性弱一些。

笔者这里推荐使用第一种风格的注释,当然这三种风格的注释可以混用,只要格式简洁、易于阅读、不会产生歧义即可,著名的 openstack 社区多使用 sphinx 风格的注释,但也做了一些自己的修改、增强。

🍯 1. python dostring 规范(PEP)

  • docstring 是一种出现在模块、函数、类或者方法定义的第一行说明的字符串,这种 docstring 就会作为该对象的 __docs__ 属性。

  • 从规范角度来说,所有的模块都应该有 docstrings,那些从模块中引入的函数和类也要有 docstrings。公有方法(包括 __init__ 构造器)也要有docstring。对于一个包来说,包的说明文档可能就来自__init__文件中的docstring.

例如:

import collections
help(collections)

可以在 collections->__init__.py 中找到 help 函数返回的内容

  • Python 代码中其他地方出现的字符串也可以作为文档,但是其不会被Python 字节编码器识别,也就无法作为运行时对象属性(也就无法被分配给__doc__方法),但是有两种额外类型的 docstrings 可以被软件工具提取。

  • 为了保证一致性

    • 在文档字符串周围使用 """your docstring"""
    • 如果在文档字符串中使用任何反斜杠转义,那么需要用 r"""your raw docstring"""
    • 对于 Unicode 文档字符串,请使用 u"""your Unicode docstring """

🌏 docstring 的表现形式

pythondocstring 有两种,一种是单行,一种是多行

单行 docstring

def kos_root():
    """Return the pathname of the KOS root directory."""
    global _kos_root
    if _kos_root: return _kos_root
    ...

注意:

  • 即使字符串适合一行,也使用三引号,这样以后扩展起来比较容易
  • 结束引号与开始引号在同一行,这样单行看起来好看
  • 在文档字符串之前或之后都没有空行。
  • 文档字符串是以句号结尾的短语,描述的内容应该是"Do this", "Return that",这个函数是用来干嘛的,函数参数如何,函数返回什么,不应该写其他无关内容。

example:

def function(a, b):
"""Do X and return a list."""

多行 docstring

  • 多行 docstrings 由一个总结/总结行(类似单行说明文档)、一个空行,然后是其他更详细的内容描述。
    • 摘要行可以被自动索引工具使用,因此它需要符合位于第一行且后面空一行以和其他部分隔开这样的规范。
    • 总结行可以和开始的引号在一行,也可以在下一行。
    • 整个文档的缩进和第一行一样,如下面的例子。
  • 一个类的所有 docstrings 后面,要插入一个空行。(和后面的代码隔开)
    • 一般类方法会用一个空行和其他内容分开,docstrings 和第一个方法之间要有个空格
  • 脚本(一个独立程序,比如一个.py文件)的 docstring 应该可以作为它的 usage 信息,比如脚本被不正确的调用,或者还使用 -h 参数时,就会打印出这个信息。
    • 这样的 docstring 应该记录了脚本的函数功能,还有命令行语法,环境变量以及文件等等。用法消息可能会很多,甚至好几个屏幕,但是起码要写的能让新用户可以正确使用这个脚本,同时对于熟练用户来说也是一个所有功能列表的快速参考。
  • 不要使用 Emacs 约定在运行文本中以大写形式提及函数或方法的参数。 Python 区分大小写,参数名称可用于关键字参数,因此文档字符串应记录正确的参数名称。最好在单独的行中列出每个参数。

example 1:

def complex(real=0.0, imag=0.0):
    """Form a complex number.

    Keyword arguments:
    real -- the real part (default 0.0)
    imag -- the imaginary part (default 0.0)
    """
    if imag == 0.0 and real == 0.0:
        return complex_zero
    ...

example 2:

class Variable:
    """
    Attributes:
    history (:class:`History` or None) : the Function calls that created this variable or None if constant
    derivative (variable type): the derivative with respect to this variable
    grad (variable type) : alias for derivative, used for tensors
    name (string) : a globally unique name of the variable
    """

    def __init__(self, history, name=None):
        global variable_count
        assert history is None or isinstance(history, History), history

        self.history = history
        self._derivative = None

        # This is a bit simplistic, but make things easier.
        variable_count += 1
        self.unique_id = "Variable" + str(variable_count)

        # For debugging can have a name.
        if name is not None:
            self.name = name
        else:
            self.name = self.unique_id
        self.used = 0

    def requires_grad_(self, val):
        """
        Set the requires_grad flag to `val` on variable.

        Ensures that operations on this variable will trigger
        backpropagation.

        Args:
            val (bool): whether to require grad
        """
        self.history = History()

🏆 2. Google Styleguide

💦 2.1 模块 docstrings

  • 如果是一个模块,那么文件的最开始,应该有类似以下内容:
"""A one line summary of the module or program, terminated by a period.

Leave one blank line.  The rest of this docstring should contain an
overall description of the module or program.  Optionally, it may also
contain a brief description of exported classes and functions and/or usage
examples.

  Typical usage example:

  foo = ClassFoo()
  bar = foo.FunctionBar()
"""

🐠 2.2 函数和方法

  • 文档字符串应该提供足够的信息来编写对函数的调用,而无需阅读函数的代码。文档字符串应描述函数的调用语法及其语义,但通常不描述其实现细节,除非这些细节与函数的使用方式相关
  • 函数的描述信息中有几个部分是比较特殊,需要进行特殊指明的。比如:
    • 参数,按名称列出每个参数,名称后面就跟着描述,用冒号/空格/换行符分开名称和描述。如果描述信息太长,单行超过 80 个字符,可以使用比参数名称多 24 个空格的悬空缩进(与文件中其余的 docstring 保持一致)。如果代码不包含相应的类型注释,则说明应包括所需的类型。如果函数接受 foo(变长参数列表)和/或 bar(任意关键字参数),则它们应列为 foobar
    • 类似的还有 returnraise,这两种特殊类型的说明

如果是函数和方法,那么其 docstring 应该类似下面:

def fetch_smalltable_rows(table_handle: smalltable.Table,
                          keys: Sequence[Union[bytes, str]],
                          require_all_keys: bool = False,
) -> Mapping[bytes, Tuple[str]]:
    """Fetches rows from a Smalltable.

    Retrieves rows pertaining to the given keys from the Table instance
    represented by table_handle.  String keys will be UTF-8 encoded.

    Args:
        table_handle: An open smalltable.Table instance.
        keys: A sequence of strings representing the key of each table
          row to fetch.  String keys will be UTF-8 encoded.
        require_all_keys: If True only rows with values set for all keys will be
          returned.

    Returns:
        A dict mapping keys to the corresponding table row data
        fetched. Each row is represented as a tuple of strings. For
        example:

        {b'Serak': ('Rigel VII', 'Preparer'),
         b'Zim': ('Irk', 'Invader'),
         b'Lrrr': ('Omicron Persei 8', 'Emperor')}

        Returned keys are always bytes.  If a key from the keys argument is
        missing from the dictionary, then that row was not found in the
        table (and require_all_keys must have been False).

    Raises:
        IOError: An error occurred accessing the smalltable.
    """

🔮 2.3 类

class SampleClass:
    """Summary of class here.

    Longer class information....
    Longer class information....

    Attributes:
        likes_spam: A boolean indicating if we like SPAM or not.
        eggs: An integer count of the eggs we have laid.
    """

    def __init__(self, likes_spam: bool = False):
        """Inits SampleClass with blah."""
        self.likes_spam = likes_spam
        self.eggs = 0

    def public_method(self):
        """Performs operation blah."""

三、PyCharm 中添加方法注释(Docstring format & Live Templates)

本章介绍在 pyCharm 中使用两种方式进行方法的注释:Docstring formatLive Templates

⛄️ 1.1 Docstring format 添加方法注释

Docstring format 可通过下方路径进行设置,包括五种风格:Plain、Epytext、reStructuredText、Numpy、Google

File → \to Settings → \to Tools → \to Python Integrated Tools → \to Docstrings → \to Docstring format

使用方式为,在方法名下方输入三个双(单)引号,回车,自动生成。五种风格的样式如下:

def docstrings_func_plain(parm_a, parm_b, parm_c):
    """
    Plain 风格
    """


def docstrings_func_epytext(parm_a, parm_b, parm_c):
    """
    Epytext 风格

    @param parm_a: 参数a
    @param parm_b: 参数b
    @param parm_c: 参数c
    @return: 结果a
    """


def docstrings_func_restructuredtext(parm_a, parm_b, parm_c):
    """
    reStructuredText 风格

    :param parm_a: 参数a
    :param parm_b: 参数b
    :param parm_c: 参数c
    :return: 结果a
    """


def docstrings_func_numpy(parm_a, parm_b, parm_c):
    """
    NumPy 风格

    Parameters
    ----------
    parm_a : 参数a
    parm_b : 参数b
    parm_c : 参数a

    Returns
    -------
    result_a : 结果a
    """


def docstrings_func_google(parm_a, parm_b, parm_c):
    """
    Google 风格

    Args:
        parm_a: 参数a
        parm_b: 参数b
        parm_c: 参数c

    Returns:
        result_a  结果a
    """

🌴 1.2 Docstring format 添加参数类型注释

  • Python 是动态语言,使用动态类型(Dynamic Typed),即在运行时确定数据类型,变量使用之前不需要类型声明;对于一些已经确定类型的参数,加上类型的注释,可以借助 PyCharm 的方法类型检查功能,在书写代码时就能够提前发现错误。

下面代码第一行是没加参数类型注释,第二行添加了参数类型注释,PyCharm 就可根据方法对应的 docstrings 提前判断输入参数类型的问题,并给出正确类型提示。

PyCharm 中开启插入类型占位符注释路径如下: 开启后再使用 Docstring format 添加方法注释,就会出现类型占位符。

File → \to Settings → \to Editor → \to General → \to Smart Keys → \to Insert type placeholders in the documentation comment stub

添加了参数类型的各方法注释如下:

def docstrings_func_epytext_type(parm_a, parm_b, parm_c):
    """
    Epytext 风格 - 参数类型

    @param parm_a: 参数a
    @type parm_a: int
    @param parm_b: 参数b
    @type parm_b: str
    @param parm_c: 参数c
    @type parm_c: bool
    @return: result_a 结果a
    @rtype: int
    """


def docstrings_func_restructuredtext_type(parm_a, parm_b, parm_c):
    """
    reStructuredText 风格 - 参数类型
    
    :param parm_a: 参数a
    :type parm_a: int
    :param parm_b: 参数b
    :type parm_b: str 
    :param parm_c: 参数c 
    :type parm_c: bool 
    :return: result_a 结果a
    :rtype: int
    """


def docstrings_func_restructuredtext_type_2(parm_a, parm_b, parm_c):
    """
    reStructuredText 风格 - 参数类型 与参数描述同一行

    :param int parm_a: 参数a
    :param str parm_b: 参数b
    :param bool parm_c: 参数c
    :return: result_a 结果a
    :rtype: int
    """


def docstrings_func_numpy_type(parm_a, parm_b, parm_c):
    """
    NumPy 风格 - 参数类型

    Parameters
    ----------
    parm_a : int
        参数a
    parm_b : str
        参数b
    parm_c : bool
        参数c

    Returns
    -------
    result_a : int
        结果a
    """


def docstrings_func_google_type(parm_a, parm_b, parm_c):
    """
    Google 风格 - 参数类型

    Args:
        parm_a (int): 参数a
        parm_b (str): 参数b
        parm_c (bool): 参数c

    Returns:
        result_a (int):  结果a
    """

四、 Live Templates

  • Docstring format 已经可以自动格式化输出 docstrings,但无法加上创建人、创建时间、修改人、修改时间、版权声明;有些规范建义这些元素写在文件头部,而对于协同开发同一文件,觉得还是需要把这些元素加在各个方法里面,会更清晰明了。

可通过 PyCharmLive Templates 自定义模板实现。

Live Templates 中设置路径如下:

File → \to Settings → \to Editor → \to Live Templates

添加方式如下:

  • 进入 Live Templates 设置页面,点击右方加号,添加 Template Group
  • 任意名
  • 再添加 Live Template
  • 在下方添加 Abbreviation(快捷键缩写),Desctiption (快捷键描述)
  • 在下方添加 Applicable(可应用的语言范围)
  • 在 Template text 中添加下方模板代码
"""


Parameters
----------

Returns
-------

:Author:  青年有志
:Create:  $DATE$ $TIME$
:Blog:    https://blog.csdn.net/qq_46450354?type=blog
青年有志 Group All Rights Reserved.
"""
  • Edit variables 中配置 DATETIME,使创建时间自动生成
  • 为了使用注释方便,还可添加 更新时间 和 当前时间
:update: $DATE$ $TIME$

$DATE$ $TIME$
  • 在方法下方输入配置的 Abbreviation,使用 Tab 或 回车都可自动生成注释,见下方代码

☀️ 补充

Live Templates 中可用的宏定义变量有:

# ${PROJECT_NAME} - 项目名称
# ${NAME} - 新建文件的名称
# ${USER} - 当前用户的登录名
# ${DATE} - 当前系统日期
# ${TIME} - 当前系统时间
# ${YEAR} - 当前年份
# ${MONTH} - 当月
# ${DAY} - 当月的当天
# ${HOUR} - 当前小时
# ${MINUTE} - 当前分钟
# ${MONTH_NAME_SHORT} - 月份名称
# ${MONTH_NAME_FULL} - 月份名称

一般只使用 # -*- coding: utf-8 -*- 作为文件头注释。一是因为某些规范的要求,特别是 PEP8 - Source File Encoding;二是因为非 utf-8 编码情况下,代码可能不识别汉字。

五、一些注释经验

  • 注释不是越多越好。对于一目了然的代码,不需要添加注释。
  • 对于复杂的操作,应该在操作开始前写上相应的注释。
  • 对于不是一目了然的代码,应该在代码之后添加注释。
  • 绝对不要描述代码。一般阅读代码的人都了解Python的语法,只是不知道代码要干什么

Reference

[1] https://www.cnblogs.com/yacker/p/you-ya-de-bian-xiepython-zhu-shi.html

[2] https://blog.csdn.net/Castlehe/article/details/121394771

[3] pyCharm中添加方法注释(Docstring format & Live Templates)

[4] PyCharm设置(注释风格、Pylint等)

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐