<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 使用和高性能技巧總結(jié)

          共 7949字,需瀏覽 16分鐘

           ·

          2022-01-17 02:33

          點(diǎn)擊上方“程序員大白”,選擇“星標(biāo)”公眾號(hào)

          重磅干貨,第一時(shí)間送達(dá)


          1. 易混淆操作

          本節(jié)對(duì)一些 Python 易混淆的操作進(jìn)行對(duì)比。

          1.1 有放回隨機(jī)采樣和無(wú)放回隨機(jī)采樣

          import random
          random.choices(seq, k=1) # 長(zhǎng)度為k的list,有放回采樣
          random.sample(seq, k) # 長(zhǎng)度為k的list,無(wú)放回采樣

          1.2 lambda 函數(shù)的參數(shù)

          func = lambda y: x + y          # x的值在函數(shù)運(yùn)行時(shí)被綁定
          func = lambda y, x=x: x + y # x的值在函數(shù)定義時(shí)被綁定

          1.3 copy 和 deepcopy

          import copy
          y = copy.copy(x) # 只復(fù)制最頂層
          y = copy.deepcopy(x) # 復(fù)制所有嵌套部分

          復(fù)制和變量別名結(jié)合在一起時(shí),容易混淆:

          a = [1, 2, [3, 4]]

          # Alias.
          b_alias = a
          assert b_alias == a and b_alias is a

          # Shallow copy.
          b_shallow_copy = a[:]
          assert b_shallow_copy == a and b_shallow_copy is not a and b_shallow_copy[2] is a[2]

          # Deep copy.
          import copy
          b_deep_copy = copy.deepcopy(a)
          assert b_deep_copy == a and b_deep_copy is not a and b_deep_copy[2] is not a[2]

          對(duì)別名的修改會(huì)影響原變量,(淺)復(fù)制中的元素是原列表中元素的別名,而深層復(fù)制是遞歸的進(jìn)行復(fù)制,對(duì)深層復(fù)制的修改不影響原變量。

          1.4 == 和 is

          x == y  # 兩引用對(duì)象是否有相同值
          x is y # 兩引用是否指向同一對(duì)象

          1.5 判斷類(lèi)型

          type(a) == int      # 忽略面向?qū)ο笤O(shè)計(jì)中的多態(tài)特征
          isinstance(a, int) # 考慮了面向?qū)ο笤O(shè)計(jì)中的多態(tài)特征

          1.6 字符串搜索

          str.find(sub, start=None, end=None); str.rfind(...)     # 如果找不到返回-1
          str.index(sub, start=None, end=None); str.rindex(...) # 如果找不到拋出ValueError異常

          1.7 List 后向索引

          這個(gè)只是習(xí)慣問(wèn)題,前向索引時(shí)下標(biāo)從0開(kāi)始,如果反向索引也想從0開(kāi)始可以使用~。

          print(a[-1], a[-2], a[-3])
          print(a[~0], a[~1], a[~2])

          2. C/C++ 用戶(hù)使用指南

          不少 Python 的用戶(hù)是從以前 C/C++ 遷移過(guò)來(lái)的,這兩種語(yǔ)言在語(yǔ)法、代碼風(fēng)格等方面有些不同,本節(jié)簡(jiǎn)要進(jìn)行介紹。

          2.1 很大的數(shù)和很小的數(shù)

          C/C++ 的習(xí)慣是定義一個(gè)很大的數(shù)字,Python 中有 inf 和 -inf:

          a = float('inf')
          b = float('-inf')

          2.2 布爾值

          C/C++ 的習(xí)慣是使用 0 和非 0 值表示 True 和 False, Python 建議直接使用 True 和 False 表示布爾值。

          a = True
          b = False

          2.3 判斷為空

          C/C++ 對(duì)空指針判斷的習(xí)慣是 if (a) 和 if (!a)。Python 對(duì)于 None 的判斷是:

          if x is None:
          pass

          如果使用 if not x,則會(huì)將其他的對(duì)象(比如長(zhǎng)度為 0 的字符串、列表、元組、字典等)都會(huì)被當(dāng)做 False。

          2.4 交換值

          C/C++ 的習(xí)慣是定義一個(gè)臨時(shí)變量,用來(lái)交換值。利用 Python 的 Tuple 操作,可以一步到位。

          a, b = b, a

          2.5 比較

          C/C++ 的習(xí)慣是用兩個(gè)條件。利用 Python 可以一步到位。

          if 0 < a < 5:
          pass

          2.6 類(lèi)成員的 Set 和 Get

          C/C++ 的習(xí)慣是把類(lèi)成員設(shè)為 private,通過(guò)一系列的 Set 和 Get 函數(shù)存取其中的值。在 Python 中雖然也可以通過(guò) @property、@setter、@deleter 設(shè)置對(duì)應(yīng)的 Set 和 Get 函數(shù),我們應(yīng)避免不必要的抽象,這會(huì)比直接訪問(wèn)慢 4 - 5 倍。

          2.7 函數(shù)的輸入輸出參數(shù)

          C/C++ 的習(xí)慣是把輸入輸出參數(shù)都列為函數(shù)的參數(shù),通過(guò)指針改變輸出參數(shù)的值,函數(shù)的返回值是執(zhí)行狀態(tài),函數(shù)調(diào)用方對(duì)返回值進(jìn)行檢查,判斷是否成功執(zhí)行。在 Python 中,不需要函數(shù)調(diào)用方進(jìn)行返回值檢查,函數(shù)中遇到特殊情況,直接拋出一個(gè)異常。

          2.8 讀文件

          相比 C/C++,Python 讀文件要簡(jiǎn)單很多,打開(kāi)后的文件是一個(gè)可迭代對(duì)象,每次返回一行內(nèi)容。

          with open(file_path, 'rt', encoding='utf-8') as f:
          for line in f:
          print(line) # 末尾的\n會(huì)保留

          2.9 文件路徑拼接

          C/C++ 的習(xí)慣通常直接用 + 將路徑拼接,這很容易出錯(cuò),Python 中的 os.path.join 會(huì)自動(dòng)根據(jù)操作系統(tǒng)不同補(bǔ)充路徑之間的 / 或 \ 分隔符:

          import os
          os.path.join('usr', 'lib', 'local')

          2.10 解析命令行選項(xiàng)

          雖然 Python 中也可以像 C/C++ 一樣使用 sys.argv 直接解析命令行選擇,但是使用 argparse 下的 ArgumentParser 工具更加方便,功能更加強(qiáng)大。

          2.11 調(diào)用外部命令

          雖然 Python 中也可以像 C/C++ 一樣使用 os.system 直接調(diào)用外部命令,但是使用 subprocess.check_output 可以自由選擇是否執(zhí)行 Shell,也可以獲得外部命令執(zhí)行結(jié)果。

          import subprocess
          # 如果外部命令返回值非0,則拋出subprocess.CalledProcessError異常
          result = subprocess.check_output(['cmd', 'arg1', 'arg2']).decode('utf-8')
          # 同時(shí)收集標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤
          result = subprocess.check_output(['cmd', 'arg1', 'arg2'], stderr=subprocess.STDOUT).decode('utf-8')
          # 執(zhí)行shell命令(管道、重定向等),可以使用shlex.quote()將參數(shù)雙引號(hào)引起來(lái)
          result = subprocess.check_output('grep python | wc > out', shell=True).decode('utf-8')

          2.12 不重復(fù)造輪子

          不要重復(fù)造輪子,Python稱(chēng)為batteries included即是指Python提供了許多常見(jiàn)問(wèn)題的解決方案。

          3. 常用工具

          3.1 讀寫(xiě) CSV 文件

          import csv
          # 無(wú)header的讀寫(xiě)
          with open(name, 'rt', encoding='utf-8', newline='') as f: # newline=''讓Python不將換行統(tǒng)一處理
          for row in csv.reader(f):
          print(row[0], row[1]) # CSV讀到的數(shù)據(jù)都是str類(lèi)型
          with open(name, mode='wt') as f:
          f_csv = csv.writer(f)
          f_csv.writerow(['symbol', 'change'])

          # 有header的讀寫(xiě)
          with open(name, mode='rt', newline='') as f:
          for row in csv.DictReader(f):
          print(row['symbol'], row['change'])
          with open(name, mode='wt') as f:
          header = ['symbol', 'change']
          f_csv = csv.DictWriter(f, header)
          f_csv.writeheader()
          f_csv.writerow({'symbol': xx, 'change': xx})

          注意,當(dāng) CSV 文件過(guò)大時(shí)會(huì)報(bào)錯(cuò):_csv.Error: field larger than field limit (131072),通過(guò)修改上限解決

          import sys
          csv.field_size_limit(sys.maxsize)

          csv 還可以讀以 \t 分割的數(shù)據(jù)

          f = csv.reader(f, delimiter='\t')

          3.2 迭代器工具

          itertools 中定義了很多迭代器工具,例如子序列工具:

          import itertools
          itertools.islice(iterable, start=None, stop, step=None)
          # islice('ABCDEF', 2, None) -> C, D, E, F

          itertools.filterfalse(predicate, iterable) # 過(guò)濾掉predicate為False的元素
          # filterfalse(lambda x: x < 5, [1, 4, 6, 4, 1]) -> 6

          itertools.takewhile(predicate, iterable) # 當(dāng)predicate為False時(shí)停止迭代
          # takewhile(lambda x: x < 5, [1, 4, 6, 4, 1]) -> 1, 4

          itertools.dropwhile(predicate, iterable) # 當(dāng)predicate為False時(shí)開(kāi)始迭代
          # dropwhile(lambda x: x < 5, [1, 4, 6, 4, 1]) -> 6, 4, 1

          itertools.compress(iterable, selectors) # 根據(jù)selectors每個(gè)元素是True或False進(jìn)行選擇
          # compress('ABCDEF', [1, 0, 1, 0, 1, 1]) -> A, C, E, F

          序列排序:

          sorted(iterable, key=None, reverse=False)

          itertools.groupby(iterable, key=None) # 按值分組,iterable需要先被排序
          # groupby(sorted([1, 4, 6, 4, 1])) -> (1, iter1), (4, iter4), (6, iter6)

          itertools.permutations(iterable, r=None) # 排列,返回值是Tuple
          # permutations('ABCD', 2) -> AB, AC, AD, BA, BC, BD, CA, CB, CD, DA, DB, DC

          itertools.combinations(iterable, r=None) # 組合,返回值是Tuple
          itertools.combinations_with_replacement(...)
          # combinations('ABCD', 2) -> AB, AC, AD, BC, BD, CD

          多個(gè)序列合并:

          itertools.chain(*iterables)                        # 多個(gè)序列直接拼接
          # chain('ABC', 'DEF') -> A, B, C, D, E, F

          import heapq
          heapq.merge(*iterables, key=None, reverse=False) # 多個(gè)序列按順序拼接
          # merge('ABF', 'CDE') -> A, B, C, D, E, F

          zip(*iterables) # 當(dāng)最短的序列耗盡時(shí)停止,結(jié)果只能被消耗一次
          itertools.zip_longest(*iterables, fillvalue=None) # 當(dāng)最長(zhǎng)的序列耗盡時(shí)停止,結(jié)果只能被消耗一次

          3.3 計(jì)數(shù)器

          計(jì)數(shù)器可以統(tǒng)計(jì)一個(gè)可迭代對(duì)象中每個(gè)元素出現(xiàn)的次數(shù)。

          import collections
          # 創(chuàng)建
          collections.Counter(iterable)

          # 頻次
          collections.Counter[key] # key出現(xiàn)頻次
          # 返回n個(gè)出現(xiàn)頻次最高的元素和其對(duì)應(yīng)出現(xiàn)頻次,如果n為None,返回所有元素
          collections.Counter.most_common(n=None)

          # 插入/更新
          collections.Counter.update(iterable)
          counter1 + counter2; counter1 - counter2 # counter加減

          # 檢查兩個(gè)字符串的組成元素是否相同
          collections.Counter(list1) == collections.Counter(list2)

          3.4 帶默認(rèn)值的 Dict

          當(dāng)訪問(wèn)不存在的 Key 時(shí),defaultdict 會(huì)將其設(shè)置為某個(gè)默認(rèn)值。

          import collections
          collections.defaultdict(type) # 當(dāng)?shù)谝淮卧L問(wèn)dict[key]時(shí),會(huì)無(wú)參數(shù)調(diào)用type,給dict[key]提供一個(gè)初始值

          3.5 有序 Dict

          import collections
          collections.OrderedDict(items=None) # 迭代時(shí)保留原始插入順序

          4. 高性能編程和調(diào)試

          4.1 輸出錯(cuò)誤和警告信息

          向標(biāo)準(zhǔn)錯(cuò)誤輸出信息

          import sys
          sys.stderr.write('')

          輸出警告信息

          import warnings
          warnings.warn(message, category=UserWarning)
          # category的取值有DeprecationWarning, SyntaxWarning, RuntimeWarning, ResourceWarning, FutureWarning

          控制警告消息的輸出

          $ python -W all     # 輸出所有警告,等同于設(shè)置warnings.simplefilter('always')
          $ python -W ignore # 忽略所有警告,等同于設(shè)置warnings.simplefilter('ignore')
          $ python -W error # 將所有警告轉(zhuǎn)換為異常,等同于設(shè)置warnings.simplefilter('error')

          4.2 代碼中測(cè)試

          有時(shí)為了調(diào)試,我們想在代碼中加一些代碼,通常是一些 print 語(yǔ)句,可以寫(xiě)為:

          # 在代碼中的debug部分
          if __debug__:
          pass

          一旦調(diào)試結(jié)束,通過(guò)在命令行執(zhí)行 -O 選項(xiàng),會(huì)忽略這部分代碼:

          $ python -0 main.py

          4.3 代碼風(fēng)格檢查

          使用 pylint 可以進(jìn)行不少的代碼風(fēng)格和語(yǔ)法檢查,能在運(yùn)行之前發(fā)現(xiàn)一些錯(cuò)誤

          pylint main.py

          4.4 代碼耗時(shí)

          耗時(shí)測(cè)試

          $ python -m cProfile main.py

          測(cè)試某代碼塊耗時(shí)

          # 代碼塊耗時(shí)定義
          from contextlib import contextmanager
          from time import perf_counter

          @contextmanager
          def timeblock(label):
          tic = perf_counter()
          try:
          yield
          finally:
          toc = perf_counter()
          print('%s : %s' % (label, toc - tic))

          # 代碼塊耗時(shí)測(cè)試
          with timeblock('counting'):
          pass

          代碼耗時(shí)優(yōu)化的一些原則

          • 專(zhuān)注于優(yōu)化產(chǎn)生性能瓶頸的地方,而不是全部代碼。
          • 避免使用全局變量。局部變量的查找比全局變量更快,將全局變量的代碼定義在函數(shù)中運(yùn)行通常會(huì)快 15%-30%。
          • 避免使用.訪問(wèn)屬性。使用 from module import name 會(huì)更快,將頻繁訪問(wèn)的類(lèi)的成員變量 self.member 放入到一個(gè)局部變量中。
          • 盡量使用內(nèi)置數(shù)據(jù)結(jié)構(gòu)。str, list, set, dict 等使用 C 實(shí)現(xiàn),運(yùn)行起來(lái)很快。
          • 避免創(chuàng)建沒(méi)有必要的中間變量,和 copy.deepcopy()。
          • 字符串拼接,例如 a + ':' + b + ':' + c 會(huì)創(chuàng)造大量無(wú)用的中間變量,':',join([a, b, c]) 效率會(huì)高不少。另外需要考慮字符串拼接是否必要,例如 print(':'.join([a, b, c])) 效率比 print(a, b, c, sep=':') 低。

          5. Python 其他技巧

          5.1 argmin 和 argmax

          items = [2, 1, 3, 4]
          argmin = min(range(len(items)), key=items.__getitem__)

          argmax同理。

          5.2 轉(zhuǎn)置二維列表

          A = [['a11', 'a12'], ['a21', 'a22'], ['a31', 'a32']]
          A_transpose = list(zip(*A)) # list of tuple
          A_transpose = list(list(col) for col in zip(*A)) # list of list

          5.3 一維列表展開(kāi)為二維列表

          A = [1, 2, 3, 4, 5, 6]

          # Preferred.
          list(zip(*[iter(A)] * 2))


          作者:張皓

          https://zhuanlan.zhihu.com/p/48293468


          13個(gè)你一定要知道的PyTorch特性

          解讀:為什么要做特征歸一化/標(biāo)準(zhǔn)化?

          一文搞懂 PyTorch 內(nèi)部機(jī)制

          張一鳴:每個(gè)逆襲的年輕人,都具備的底層能力


          關(guān)


          學(xué)西學(xué)學(xué)運(yùn)營(yíng)護(hù)號(hào)樂(lè)質(zhì)結(jié)識(shí)關(guān)[]學(xué)習(xí)進(jìn)


          瀏覽 119
          點(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>
                  久久久久有精品国产白浆天美传媒 | 国产一级片免费播放 | 国产成人黄色在线观看 | 操屄操屄操屄操屄 | 成人毛片18女人毛片真水 |