zoukankan      html  css  js  c++  java
  • Python规范:提高可读性

    PEP 8 规范

      PEP 是 Python Enhancement Proposal 的缩写,翻译过来叫“Python 增强规范”。

    缩进规范

      PEP 8 规范告诉我们,请选择四个空格的缩进,不要使用 Tab,更不要 Tab 和空格混着用。 第二个要注意的是,每行最大长度请限制在 79 个字符。

    空行规范

      PEP 8 规定,全局的类和函数的上方需要空两个空行,而类的函数之间需要空一个空行。

    空格规范

    1. 函数的参数列表中,调用函数的参数列表中会出现逗号,请注意逗号后要跟一个空格,这是英语的使用习惯,也能让每个参数独立阅读,更清晰。
    2. 冒号后面也要跟一个空格。
    3. 在#后、注释前加一个空格。
    4. 操作符,例如+,-,*,/,&,|,=,==,!=,请在两边都保留空格。不过与此对应,括号内的两端并不需要空格。

    换行规范

      控制每行的最大长度不超过 79 个字符,但是有时候,函数调用逻辑过长而不得不超过这个数字时按以下规范:

    def solve1(this_is_the_first_parameter, this_is_the_second_parameter, this_is_the_third_parameter,
               this_is_the_forth_parameter, this_is_the_fifth_parameter, this_is_the_sixth_parameter):
        return (this_is_the_first_parameter + this_is_the_second_parameter + this_is_the_third_parameter +
                this_is_the_forth_parameter + this_is_the_fifth_parameter + this_is_the_sixth_parameter)
    
    
    def solve2(this_is_the_first_parameter, this_is_the_second_parameter, this_is_the_third_parameter,
               this_is_the_forth_parameter, this_is_the_fifth_parameter, this_is_the_sixth_parameter):
        return this_is_the_first_parameter + this_is_the_second_parameter + this_is_the_third_parameter + 
               this_is_the_forth_parameter + this_is_the_fifth_parameter + this_is_the_sixth_parameter
    
    
    (top_secret_func(param1=12345678, param2=12345678, param3=12345678, param4=12345678, param5=12345678).check()
        .launch_nuclear_missile().wait())
    
    
    top_secret_func(param1=12345678, param2=12345678, param3=12345678, param4=12345678, param5=12345678).check() 
        .launch_nuclear_missile().wait()

      1.通过括号来将过长的运算进行封装.

      2.通过换行符来实现.

    文档规范

    1. import 尽量放在开头.
    2. 不要使用 import 一次导入多个模块.
    3. from module import func 这样的语句,请确保 func 在本文件中不会出现命名冲突。或者通过 from module import func as new_func 来进行重命名,从而避免冲突。

    注释规范

      行注释并不是很推荐的方式。

    文档描述

      docstring 的写法,它是用三个双引号开始、三个双引号结尾。我们首先用一句话简单说明这个函数做什么,然后跟一段话来详细解释;再往后是参数列表、参数格式、返回值格式。

    class SpatialDropout2D(Dropout):
        """Spatial 2D version of Dropout.
        This version performs the same function as Dropout, however it drops
        entire 2D feature maps instead of individual elements. If adjacent pixels
        within feature maps are strongly correlated (as is normally the case in
        early convolution layers) then regular dropout will not regularize the
        activations and will otherwise just result in an effective learning rate
        decrease. In this case, SpatialDropout2D will help promote independence
        between feature maps and should be used instead.
        Arguments:
            rate: float between 0 and 1. Fraction of the input units to drop.
            data_format: 'channels_first' or 'channels_last'.
                In 'channels_first' mode, the channels dimension
                (the depth) is at index 1,
                in 'channels_last' mode is it at index 3.
                It defaults to the `image_data_format` value found in your
                Keras config file at `~/.keras/keras.json`.
                If you never set it, then it will be "channels_last".
        Input shape:
            4D tensor with shape:
            `(samples, channels, rows, cols)` if data_format='channels_first'
            or 4D tensor with shape:
            `(samples, rows, cols, channels)` if data_format='channels_last'.
        Output shape:
            Same as input
        References:
            - [Efficient Object Localization Using Convolutional
              Networks](https://arxiv.org/abs/1411.4280)
      """
        def __init__(self, rate, data_format=None, **kwargs):
            super(SpatialDropout2D, self).__init__(rate, **kwargs)
            if data_format is None:
                data_format = K.image_data_format()
            if data_format not in {'channels_last', 'channels_first'}:
                raise ValueError('data_format must be in '
                               '{"channels_last", "channels_first"}')
            self.data_format = data_format
            self.input_spec = InputSpec(ndim=4)

    命名规范

    1. 变量使用小写,通过下划线串联起来,例如:data_format、input_spec、image_data_set。唯一可以使用单字符的地方是迭代,比如 for i in range(n) 这种,为了精简可以使用。如果是类的私有变量,请记得前面增加两个下划线。
    2. 常量,最好的做法是全部大写,并通过下划线连接,例如:WAIT_TIME、SERVER_ADDRESS、PORT_NUMBER。
    3. 函数名,同样也请使用小写的方式,通过下划线连接起来,例如:launch_nuclear_missile()、check_input_validation()。
    4. 类名,则应该首字母大写,然后合并起来,例如:class SpatialDropout2D()、class FeatureSet()。

    代码分解技巧

      不写重复代码。

      如:

    if i_am_rich:
        money = 100
        send(money)
    else:
        money = 10
        send(money)

      都有send函数,可改为:

    if i_am_rich:
        money = 100
    else:
        money = 10
    send(money)

      代码嵌套过深:

    def send(money):
        if is_server_dead:
            LOG('server dead')
            return
        else:
            if is_server_timed_out:
                LOG('server timed out')
                return
            else:
                result = get_result_from_server()
                if result == MONEY_IS_NOT_ENOUGH:
                    LOG('you do not have enough money')
                    return
                else:
                    if result == TRANSACTION_SUCCEED:
                        LOG('OK')
                        return
                    else:
                        LOG('something wrong')
                        return

      可改为:

    def send(money):
        if is_server_dead:
            LOG('server dead')
            return
    
        if is_server_timed_out:
            LOG('server timed out')
            return
    
        result = get_result_from_server()
    
        if result == MONET_IS_NOT_ENOUGH:
            LOG('you do not have enough money')
            return
    
        if result == TRANSACTION_SUCCEED:
            LOG('OK')
            return
    
        LOG('something wrong')

      以一个简单的二分搜索来举例说明。给定一个非递减整数数组,和一个 target,要求找到数组中最小的一个数 x,可以满足 x*x > target。一旦不存在,则返回 -1。

      代码实现如果如下所示,那么可以再以一个函数只干一件事情的原则再优化下。

    def solve(arr, target):
        l, r = 0, len(arr) - 1
        ret = -1
        while l <= r:
            m = (l + r) // 2
            if arr[m] * arr[m] > target:
                ret = m
                r = m - 1
            else:
                l = m + 1
        if ret == -1:
            return -1
        else:
            return arr[ret]
    
    
    print(solve([1, 2, 3, 4, 5, 6], 8))
    print(solve([1, 2, 3, 4, 5, 6], 9))
    print(solve([1, 2, 3, 4, 5, 6], 0))
    print(solve([1, 2, 3, 4, 5, 6], 40))

      优化如下:

    def comp(x, target):
        return x * x > target
    
    
    def binary_search(arr, target):
        l, r = 0, len(arr) - 1
        ret = -1
        while l <= r:
            m = (l + r) // 2
            if comp(arr[m], target):
                ret = m
                r = m - 1
            else:
                l = m + 1
        return ret
    
    
    def solve(arr, target):
        id = binary_search(arr, target)
    
        if id != -1:
            return arr[id]
        return -1
    
    
    print(solve([1, 2, 3, 4, 5, 6], 8))
    print(solve([1, 2, 3, 4, 5, 6], 9))
    print(solve([1, 2, 3, 4, 5, 6], 0))
    print(solve([1, 2, 3, 4, 5, 6], 40))

      类中属性很多时可以抽出相同特性的单独作为类,如:

    class Person:
        def __init__(self, name, sex, age, job_title, job_description, company_name):
            self.name = name
            self.sex = sex
            self.age = age
            self.job_title = job_title
            self.job_description = description
            self.company_name = company_name

      job_title , job_description , company_name 都与工作有关,表达是同一个意义实体,就可以抽出单独作为类:

    class Person:
        def __init__(self, name, sex, age, job_title, job_description, company_name):
            self.name = name
            self.sex = sex
            self.age = age
            self.job = Job(job_title, job_description, company_name)
    
    class Job:
        def __init__(self, job_title, job_description, company_name):
            
            self.job_title = job_title
            self.job_description = description
            self.company_name = company_name

    参考

      极客时间《Python核心技术与实战》专栏

    极客时间版权所有: https://time.geekbang.org/column/article/104689

  • 相关阅读:
    极客时间课程《数据结构与算法之美》笔记09
    Java 学习笔记02
    极客时间课程《数据结构与算法之美》笔记05
    极客时间课程《数据结构与算法之美》笔记04
    极客时间课程《数据结构与算法之美》笔记03
    极客时间课程《数据结构与算法之美》笔记02
    极客时间课程《数据结构与算法之美》01
    spring data jpa 通过对象传参
    生成流水号
    Java 为实体类动态添加属性
  • 原文地址:https://www.cnblogs.com/xiaoguanqiu/p/11285511.html
Copyright © 2011-2022 走看看