Python規範:提高可讀性

PEP 8 規範

PEP 是 Python Enhancement Proposal 的縮寫,翻譯過來叫“Python 增強規範”。

縮進規範

  PEP 8 規範告訴我們,請選擇四個空格的縮進,不要使用 Tab,更不要 Tab 和空格混着用。 第二個要注意的是,每行最大長度請限制在 79 個字符。

空行規範

  PEP 8 規定,全局的類和函數的上方需要空兩個空行,而類的函數之間需要空一個空行。

空格規範

函數的參數列表中,調用函數的參數列表中會出現逗號,請注意逗號後要跟一個空格,這是英語的使用習慣,也能讓每個參數獨立閱讀,更清晰。

  • 冒號後面也要跟一個空格。
  • 在#後、註釋前加一個空格。
  • 操作符,例如+,-,*,/,&,|,=,==,!=,請在兩邊都保留空格。不過與此對應,括號內的兩端並不需要空格。

換行規範

  控制每行的最大長度不超過 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.通過換行符來實現.

文檔規範

  • import 儘量放在開頭.
  • 不要使用 import 一次導入多個模塊.
  • 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)

命名規範

變量使用小寫,通過下劃線串聯起來,例如:data_format、input_spec、image_data_set。唯一可以使用單字符的地方是迭代,比如 for i in range(n) 這種,爲了精簡可以使用。如果是類的私有變量,請記得前面增加兩個下劃線。

  • 常量,最好的做法是全部大寫,並通過下劃線連接,例如:WAIT_TIME、SERVER_ADDRESS、PORT_NUMBER。
  • 函數名,同樣也請使用小寫的方式,通過下劃線連接起來,例如:launch_nuclear_missile()、check_input_validation()。
  • 類名,則應該首字母大寫,然後合併起來,例如: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)

代碼嵌套過深:

#Python學習交流QQ羣:857662006
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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章