<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何寫出更具有Python風(fēng)格的代碼

          共 7582字,需瀏覽 16分鐘

           ·

          2020-11-17 02:18

          我們都喜歡 Python,因?yàn)樗尵幊毯屠斫庾兊母鼮楹?jiǎn)單。但是一不小心,我們就會(huì)忽略規(guī)則,以非 Pythonic 方式編寫一堆垃圾代碼,從而浪費(fèi) Python 這個(gè)出色的語(yǔ)言賦予我們的優(yōu)雅。Python 的代碼風(fēng)格是非常優(yōu)雅、明確和簡(jiǎn)單,在 Python 解釋器中執(zhí)行 import this 你可以看到 Tim Peters 編寫的 Python 之禪:

          >>>?import?this
          The?Zen?of?Python,?by?Tim?Peters

          Beautiful?is?better?than?ugly.
          Explicit?is?better?than?implicit.
          Simple?is?better?than?complex.
          Complex?is?better?than?complicated.
          Flat?is?better?than?nested.
          Sparse?is?better?than?dense.
          Readability?counts.
          Special?cases?aren't?special?enough?to?break?the?rules.
          Although?practicality?beats?purity.
          Errors?should?never?pass?silently.
          Unless?explicitly?silenced.
          In?the?face?of?ambiguity,?refuse?the?temptation?to?guess.
          There?should?be?one--?and?preferably?only?one?--obvious?way?to?do?it.
          Although?that?way?may?not?be?obvious?at?first?unless?you're?Dutch.
          Now?is?better?than?never.
          Although?never?is?often?better?than?*right*?now.
          If?the?implementation?is?hard?to?explain,?it's?a?bad?idea.
          If?the?implementation?is?easy?to?explain,?it?may?be?a?good?idea.
          Namespaces?are?one?honking?great?idea?--?let's?do?more?of?those!

          這里我找了目前最好的中文版本:

          美 優(yōu)于 丑

          明確 優(yōu)于 隱晦

          簡(jiǎn)單 優(yōu)于 復(fù)雜

          復(fù)雜 也好過(guò) 繁復(fù)

          扁平 優(yōu)于 嵌套

          稀疏 優(yōu)于 擁擠

          可讀性很重要

          固然代碼實(shí)用與否 比潔癖更重要,

          我們以為的特例也往往沒(méi)有特殊到必須打破上述規(guī)則的程度

          除非刻意地靜默,否則不要無(wú)故忽視異常

          如果遇到模棱兩可的邏輯,請(qǐng)不要自作聰明地瞎猜。

          應(yīng)該提供一種,且最好只提供一種,一目了然的解決方案

          當(dāng)然這是沒(méi)法一蹴而就的,除非你是荷蘭人[1]

          固然,立刻著手 好過(guò) 永遠(yuǎn)不做。

          然而,永遠(yuǎn)不做 也好過(guò) 不審慎思考一擼袖子就莽著干

          如果你的實(shí)現(xiàn)很難解釋,它就一定不是個(gè)好主意

          即使你的實(shí)現(xiàn)簡(jiǎn)單到爆,它也有可能是個(gè)好辦法

          命名空間大法好,不搞不是地球人!

          [1]:本文作者 Tim peters 解釋說(shuō)這里的荷蘭人指的是 Python 的作者 Guido van Rossum.

          以下是用 Python 編寫更好的代碼的 8 種方法:

          一、忘掉類 C 語(yǔ)言風(fēng)格

          如果需要打印列表中的所有元素及其索引,你想到的第一件事是:

          for?i?in?range(len(arr)):
          ????print(i,?arr[i])

          那么你仍然在編寫 C 代碼。擺脫這一點(diǎn),請(qǐng)牢記 Python 關(guān)鍵字 enumerate 。它索引列表/字符串中的所有元素,并且支持設(shè)置索引的起始編號(hào)

          >>>?for?index,?item?in?enumerate(['a','b','c']):?
          ...?????print(index,?item)
          ...?
          0?a
          1?b
          2?c
          >>>?for?index,?item?in?enumerate(['a','b','c'],1):?#這里第二個(gè)參數(shù)可以設(shè)置起始編號(hào)
          ...?????print(index,item)
          ...?
          1?a
          2?b
          3?c

          現(xiàn)在看起來(lái)更好了,而且更加 Pythonic。將列表轉(zhuǎn)換成字符串呢?如果你這樣寫:

          #?The?C?way
          string?=?''
          for?i?in?arr:
          ????string?+=?i

          就是 C 風(fēng)格,如果使用 Python 的關(guān)鍵字 join,不僅效率更高,而且更優(yōu)雅:

          #?The?Python?way
          string?=?''.join(arr)

          就像 join 一樣 ?,Python 有很多神奇的關(guān)鍵字,因此請(qǐng)不要為語(yǔ)言工作,而是使用該語(yǔ)言為你工作。

          二、牢記 PEP8

          我不是要求你完全遵循 PEP8,而是要求遵循其中的大多數(shù)規(guī)則,何況現(xiàn)在有很多自動(dòng)格式化的工具,足以讓你的代碼更加美觀,我們的 Python 之父也說(shuō)過(guò):閱讀代碼的頻率遠(yuǎn)遠(yuǎn)高于寫代碼的頻率,他是如此的正確!因此代碼的可讀性非常重要。

          你是否對(duì)自己曾經(jīng)寫過(guò)的代碼感到好奇?為什么這么寫,這句話為什么在這?好吧,PEP8 是大多數(shù)這類問(wèn)題的答案。盡管代碼注釋是個(gè)好方法,但是代碼的風(fēng)格也需要加以調(diào)整,比如變量 i , j , count 等即使第一次出現(xiàn)時(shí)寫了注釋,也不能保證后面你仍然記得住,這樣來(lái)看就浪費(fèi)了寶貴的時(shí)間。

          任何普通的程序員都可以編寫計(jì)算機(jī)可以理解的代碼。只有好的程序員可以編寫人類可以理解的代碼。

          首選 CamelCase 作為類, UPPER_WITH_UNDERSCORES 作為常量,而 lower_with_underscores 作為變量,方法和模塊名稱。即使使用,也要避免使用單一名稱功能 lambda 。

          三、善用推導(dǎo)式

          常用的推導(dǎo)式有:列表推導(dǎo)式,集合推導(dǎo)式,字典推導(dǎo)式。先說(shuō)下列表推導(dǎo)式。

          列表推導(dǎo)式就是當(dāng)我們需要基于一個(gè)已有的列表創(chuàng)建新的列表時(shí),所使用的語(yǔ)法格式,列表推導(dǎo)式包含以下四個(gè)部分:

          1、一個(gè)輸入序列(Input Sequence) 2、一個(gè)變量,代表著輸入序列的一個(gè)成員(Variable) 3、一個(gè)可選的判定表達(dá)式,表達(dá)這個(gè)變量滿足的條件(Optional Predicate ) 4、一個(gè)輸出序列,根據(jù) 2 和 3 生成一個(gè)輸出序列(Output Expression)

          比如有個(gè)列表既有數(shù)字,又有字符,現(xiàn)在需要計(jì)算數(shù)字的平方,并將結(jié)果放在新的列表中,如果不用列表推導(dǎo)式,寫出的代碼就是這樣的:

          #?bad?code
          a_list?=?[1,?‘4’,?9,?‘a(chǎn)’,?0,?4]

          squared_ints?=?[]
          for?item?in?a_list:
          ????if?type(item)?==?types.IntType:
          ????????squared_ints.append(item**2)

          如果使用列表推導(dǎo)式,只需要兩行代碼,非常的優(yōu)雅:

          a_list?=?[1,?‘4’,?9,?‘a(chǎn)’,?0,?4]
          squared_ints?=?[?e**2?for?e?in?a_list?if?type(e)?==?types.IntType?]

          當(dāng)然,如果你喜歡 map 和 filter,你還可以這樣做,當(dāng)時(shí)這是不推薦的,因?yàn)榭勺x性不好:

          map(lambda?e:?e**2,?filter(lambda?e:?type(e)?==?types.IntType,?a_list))

          比如集合推導(dǎo)式的使用:

          給定輸入

          names?=?[?'Bob',?'JOHN',?'alice',?'bob',?'ALICE',?'J',?'Bob'?]

          希望得到:

          {?'Bob',?'John',?'Alice'?}

          那么集合推導(dǎo)式就是:

          {?name[0].upper()?+?name[1:].lower()?for?name?in?names?if?len(name)?>?1?}

          再比如字典推導(dǎo)式:

          mcase?=?{'a':10,?'b':?34,?'A':?7,?'Z':3}

          mcase_frequency?=?{?k.lower()?:?mcase.get(k.lower(),?0)?+?mcase.get(k.upper(),?0)?for?k?in?mcase.keys()?}

          #?mcase_frequency?==?{'a':?17,?'z':?3,?'b':?34}

          從上面可以看出。推導(dǎo)式風(fēng)格的代碼是優(yōu)雅的,人類易讀的。

          四、你還在顯式的關(guān)閉文件嗎?

          如果你在寫代碼時(shí)仍然在顯式的關(guān)閉文件,就像上圖中的 programmer,你在為編程語(yǔ)言工作,如果你學(xué)會(huì)了使用 with 上下文管理器,那么你就是一個(gè) Python programmer,讓編程語(yǔ)言為你工作:

          with?open('filename.txt',?'w')?as?filename:
          ????filename.write('Hello')

          當(dāng)程序退出 with 塊時(shí),文件會(huì)自動(dòng)關(guān)閉。with 語(yǔ)句的語(yǔ)法格式:

          with?VAR?as?EXPR:
          ????BLOCK

          相當(dāng)于:

          mgr?=?(EXPR)
          exit?=?type(mgr).__exit__??#?Not?calling?it?yet
          value?=?type(mgr).__enter__(mgr)
          exc?=?True
          try:
          ????try:
          ????????VAR?=?value??#?Only?if?"as?VAR"?is?present
          ????????BLOCK
          ????except:
          ????????#?The?exceptional?case?is?handled?here
          ????????exc?=?False
          ????????if?not?exit(mgr,?*sys.exc_info()):
          ????????????raise
          ????????#?The?exception?is?swallowed?if?exit()?returns?true
          finally:
          ????#?The?normal?and?non-local-goto?cases?are?handled?here
          ????if?exc:
          ????????exit(mgr,?None,?None,?None)

          有很多網(wǎng)絡(luò)連接、數(shù)據(jù)庫(kù)連接庫(kù)都會(huì)提供 with 功能。甚至熟悉了 with 的實(shí)現(xiàn)機(jī)制后,可以自行實(shí)現(xiàn) with 功能:

          class?File(object):
          ????def?__init__(self,?file_name,?method):
          ????????self.file_obj?=?open(file_name,?method)
          ????def?__enter__(self):
          ????????return?self.file_obj
          ????def?__exit__(self,?type,?value,?traceback):
          ????????self.file_obj.close()

          只要定義了 __enter__,__exit__方法,就可以使用 with 語(yǔ)句:

          with?File('demo.txt',?'w')?as?opened_file:
          ????opened_file.write('Hola!')

          五、使用迭代器和生成器

          迭代器:iterator 生成器:generator

          迭代器和生成器都是 Python 中功能強(qiáng)大的工具,值得精通。迭代器是一個(gè)更籠統(tǒng)的概念:任何一個(gè)對(duì)象只要它所屬的類具有__next__方法(Python 2是next)和具有返回 self 的__iter__方法都是迭代器。

          每個(gè)生成器都是一個(gè)迭代器,但反之不然。生成器是通過(guò)調(diào)用具有一個(gè)或多個(gè) yield 表達(dá)式的函數(shù)而構(gòu)建的,并且該函數(shù)是滿足上一段對(duì)iterator 的定義的對(duì)象。

          使用區(qū)別:

          網(wǎng)絡(luò)上很多技術(shù)博主都說(shuō)生成器是懶人版的迭代器,比迭代器更節(jié)省內(nèi)存,其實(shí)是錯(cuò)誤的,他們都很節(jié)省內(nèi)存(我會(huì)舉例子)。

          他們真正的區(qū)別是:當(dāng)你需要一個(gè)具有某些復(fù)雜的狀態(tài)維護(hù)行為的類,或者想要公開(kāi)除__next__(和__iter____init__)之外的其他方法時(shí),你就需要自定義迭代器,而不是生成器。

          通常,一個(gè)生成器(有時(shí),對(duì)于足夠簡(jiǎn)單的需求,一個(gè)生成器表達(dá)式)就足夠了,并且它更容易編寫代碼。

          比如說(shuō)計(jì)算正整數(shù) a 到 b (b 遠(yuǎn)遠(yuǎn)大于 a)直接的平方,生成器的話就是:

          def?squares(start,?stop):
          ????for?i?in?range(start,?stop):
          ????????yield?i?*?i

          generator?=?squares(a,?b)

          或者:

          generator?=?(i*i?for?i?in?range(a,?b))

          如果是迭代器,則是這樣:

          class?Squares(object):
          ????def?__init__(self,?start,?stop):
          ???????self.start?=?start
          ???????self.stop?=?stop
          ????def?__iter__(self):?return?self
          ????def?__next__(self):?#?next?in?Python?2
          ???????if?self.start?>=?self.stop:
          ???????????raise?StopIteration
          ???????current?=?self.start?*?self.start
          ???????self.start?+=?1
          ???????return?current

          iterator?=?Squares(a,?b)

          可以看出,迭代器寫起來(lái)稍麻煩,當(dāng)也更為靈活,比如你想提供一個(gè) current 方法時(shí),可以直接添加到 Squares 類中:

          ????def?current(self):
          ???????return?self.start

          從上述可以看出,迭代器并沒(méi)有保存 a 到 b 之間的所有值,所有并不消耗過(guò)多的內(nèi)存,這一點(diǎn)也可以自行測(cè)試,代碼如下:

          >>>?from?collections.abc?import?Iterator
          >>>?from?sys?import?getsizeof
          >>>?a?=?[i?for?i?in?range(1001)]
          >>>?print(type(a))
          <class?'list'>
          >>>?print(getsizeof(a))
          9016
          >>>
          >>>?b?=?iter(a)
          >>>?print(type(b))
          <class?'list_iterator'>
          >>>?print(isinstance(b,Iterator))
          True
          >>>?print(getsizeof(b))
          48
          >>>?c?=?(i?for?i?in?range(1001))
          >>>?print(getsizeof(b))
          48
          >>>?type(c)
          <class?'generator'>
          >>>?type(b)
          <class?'list_iterator'>

          可以看出 b 是 iterator,c 是 generator,它們占用的內(nèi)存大小是一樣的。

          六、善用 itertools

          itertools 模塊標(biāo)準(zhǔn)化了一個(gè)快速、高效利用內(nèi)存的核心工具集,這些工具本身或組合都很有用。它們一起形成了“迭代器代數(shù)”,這使得在純 Python 中有可以創(chuàng)建簡(jiǎn)潔又高效的專用工具。比如,如果你想要字符串中所有字符的組合或列表中數(shù)字的所有組合,則只需編寫

          from?itertools?import?combinations
          names?=?'ABC'
          for?combination?in?combinations(names,?2):
          ????print(combination)
          '''?Output?-
          ????('A',?'B')
          ????('A',?'C')
          ????('B',?'C')
          '''

          這是一個(gè)值得經(jīng)常使用的標(biāo)準(zhǔn)庫(kù),更多詳細(xì)功能請(qǐng)參考官方文檔:https://docs.python.org/zh-cn/3/library/itertools.html[1]

          七、善用 collections

          這又是一個(gè)值得使用的標(biāo)準(zhǔn)庫(kù) collections,它提供替代內(nèi)置的數(shù)據(jù)類型的多個(gè)容器,如 defaultdict、OrderedDict、namedtuple、Counter、deque 等,非常使用,而且比自己實(shí)現(xiàn)要安全穩(wěn)定的多。比如:

          #?frequency?of?all?characters?in?a?string?in?sorted?order
          from?collections?import?(OrderedDict,?Counter)
          string?=?'abcbcaaba'
          freq?=?Counter(string)
          freq_sorted?=?OrderedDict(freq.most_common())
          for?key,?val?in?freq_sorted.items():
          ????print(key,?val)
          '''?Output?-
          ????('a',?4)
          ????('b',?3)
          ????('c',?2)
          '''

          不多說(shuō)了,看官方文檔:https://docs.python.org/3/library/collections.html[2]

          八、不要過(guò)度使用類

          不要過(guò)度使用類。堅(jiān)持用 Java 和 C ++ 的程序員會(huì)經(jīng)常使用類,但是在使用 Python 時(shí),可以在函數(shù)和模塊的幫助下復(fù)用代碼。除非絕對(duì)需要,否則不必創(chuàng)建類。

          本文講述類 8 個(gè)讓你寫出更好 Python 代碼的方法,希望對(duì)你有所幫助。

          推薦閱讀:

          10個(gè)技巧讓你的代碼更優(yōu)雅

          6 個(gè)值得玩味的 Python 代碼

          參考資料

          [1]

          https://docs.python.org/zh-cn/3/library/itertools.html: https://docs.python.org/zh-cn/3/library/itertools.html

          [2]

          https://docs.python.org/3/library/collections.html: https://docs.python.org/3/library/collections.html


          瀏覽 27
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  苍井空在厨房被C的A片 | 狠狠搞狠狠操 | 久久水蜜桃视频 | 超碰操老逼 | 水蜜桃一区二区AV |