自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

5年Python功力,總結了10個開發(fā)技巧

新聞 后端
查看函數(shù)的源代碼,我們通常會使用 IDE 來完成。比如在 PyCharm 中,你可以 Ctrl + 鼠標點擊 進入函數(shù)的源代碼。

 [[329607]]

1. 如何在運行狀態(tài)查看源代碼?

查看函數(shù)的源代碼,我們通常會使用 IDE 來完成。

比如在 PyCharm 中,你可以 Ctrl + 鼠標點擊 進入函數(shù)的源代碼。

那如果沒有 IDE 呢?

當我們想使用一個函數(shù)時,如何知道這個函數(shù)需要接收哪些參數(shù)呢?

當我們在使用函數(shù)時出現(xiàn)問題的時候,如何通過閱讀源代碼來排查問題所在呢?

這時候,我們可以使用 inspect 來代替 IDE 幫助你完成這些事。

  1. # demo.py 
  2. import inspect 
  3.  
  4.  
  5. def add(x, y): 
  6. return x + y 
  7.  
  8. print("==================="
  9. print(inspect.getsource(add)) 
  10. 運行結果如下 
  11.  
  12. $ python demo.py 
  13. =================== 
  14. def add(x, y): 
  15. return x + y 

2. 如何關閉異常自動關聯(lián)上下文?

當你在處理異常時,由于處理不當或者其他問題,再次拋出另一個異常時,往外拋出的異常也會攜帶原始的異常信息。

就像這樣子。

  1. try
  2. print(1 / 0
  3. except Exception as exc: 
  4. raise RuntimeError("Something bad happened"

從輸出可以看到兩個異常信息

  1. Traceback (most recent call last): 
  2. File "demo.py", line 2, in <module> 
  3. print(1 / 0
  4. ZeroDivisionError: division by zero 
  5.  
  6. During handling of the above exception, another exception occurred: 
  7.  
  8. Traceback (most recent call last): 
  9. File "demo.py", line 4, in <module> 
  10. raise RuntimeError("Something bad happened"
  11. RuntimeError: Something bad happened 

如果在異常處理程序或 finally 塊中引發(fā)異常,默認情況下,異常機制會隱式工作會將先前的異常附加為新異常的 __context__屬性。這就是 Python 默認開啟的自動關聯(lián)異常上下文。如果你想自己控制這個上下文,可以加個 from 關鍵字(from語法會有個限制,就是第二個表達式必須是另一個異常類或實例。),來表明你的新異常是直接由哪個異常引起的。

  1. try
  2. print(1 / 0
  3. except Exception as exc: 
  4. raise RuntimeError("Something bad happened") from exc 

輸出如下

  1. Traceback (most recent call last): 
  2. File "demo.py", line 2, in <module> 
  3. print(1 / 0
  4. ZeroDivisionError: division by zero 
  5.  
  6. The above exception was the direct cause of the following exception: 
  7.  
  8. Traceback (most recent call last): 
  9. File "demo.py", line 4, in <module> 
  10. raise RuntimeError("Something bad happened") from exc 
  11. RuntimeError: Something bad happened 

當然,你也可以通過with_traceback方法為異常設置上下文__context__屬性,這也能在traceback更好的顯示異常信息。

  1. try
  2. print(1 / 0
  3. except Exception as exc: 
  4. raise RuntimeError("bad thing").with_traceback(exc) 

最后,如果我想徹底關閉這個自動關聯(lián)異常上下文的機制?有什么辦法呢?

可以使用 raise...from None,從下面的例子上看,已經沒有了原始異常

  1. $ cat demo.py 
  2. try
  3. print(1 / 0
  4. except Exception as exc: 
  5. raise RuntimeError("Something bad happened") from None 
  6. $ python demo.py 
  7. Traceback (most recent call last): 
  8. File "demo.py", line 4, in <module> 
  9. raise RuntimeError("Something bad happened") from None 
  10. RuntimeError: Something bad happened 
  11. (PythonCodingTime) 

3. 最快查看包搜索路徑的方式

當你使用 import 導入一個包或模塊時,Python 會去一些目錄下查找,而這些目錄是有優(yōu)先級順序的,正常人會使用 sys.path 查看。

  1. >>> import sys 
  2. >>> from pprint import pprint 
  3. >>> pprint(sys.path) 
  4. [''
  5. '/usr/local/Python3.7/lib/python37.zip'
  6. '/usr/local/Python3.7/lib/python3.7'
  7. '/usr/local/Python3.7/lib/python3.7/lib-dynload'
  8. '/home/wangbm/.local/lib/python3.7/site-packages'
  9. '/usr/local/Python3.7/lib/python3.7/site-packages'
  10. >>> 

那有沒有更快的方式呢?

我這有一種連 console 模式都不用進入的方法呢?

你可能會想到這種,但這本質上與上面并無區(qū)別

  1. [wangbm@localhost ~]$ python -c "print('\n'.join(__import__('sys').path))" 
  2.  
  3. /usr/lib/python2.7/site-packages/pip-18.1-py2.7.egg 
  4. /usr/lib/python2.7/site-packages/redis-3.0.1-py2.7.egg 
  5. /usr/lib64/python27.zip 
  6. /usr/lib64/python2.7 
  7. /usr/lib64/python2.7/plat-linux2 
  8. /usr/lib64/python2.7/lib-tk 
  9. /usr/lib64/python2.7/lib-old 
  10. /usr/lib64/python2.7/lib-dynload 
  11. /home/wangbm/.local/lib/python2.7/site-packages 
  12. /usr/lib64/python2.7/site-packages 
  13. /usr/lib64/python2.7/site-packages/gtk-2.0 
  14. /usr/lib/python2.7/site-packages 

這里我要介紹的是比上面兩種都方便的多的方法,一行命令即可解決

  1. [wangbm@localhost ~]$ python3 -m site 
  2. sys.path = [ 
  3. '/home/wangbm'
  4. '/usr/local/Python3.7/lib/python37.zip'
  5. '/usr/local/Python3.7/lib/python3.7'
  6. '/usr/local/Python3.7/lib/python3.7/lib-dynload'
  7. '/home/wangbm/.local/lib/python3.7/site-packages'
  8. '/usr/local/Python3.7/lib/python3.7/site-packages'
  9. USER_BASE: '/home/wangbm/.local' (exists) 
  10. USER_SITE: '/home/wangbm/.local/lib/python3.7/site-packages' (exists) 
  11. ENABLE_USER_SITE: True 

從輸出你可以發(fā)現(xiàn),這個列的路徑會比 sys.path 更全,它包含了用戶環(huán)境的目錄。

4. 將嵌套 for 循環(huán)寫成單行

我們經常會如下這種嵌套的 for 循環(huán)代碼

  1. list1 = range(1,3
  2. list2 = range(4,6
  3. list3 = range(7,9
  4. for item1 in list1: 
  5. for item2 in list2: 
  6. for item3 in list3: 
  7. print(item1+item2+item3) 

這里僅僅是三個 for 循環(huán),在實際編碼中,有可能會有更層。

這樣的代碼,可讀性非常的差,很多人不想這么寫,可又沒有更好的寫法。

這里介紹一種我常用的寫法,使用 itertools 這個庫來實現(xiàn)更優(yōu)雅易讀的代碼。

  1. from itertools import product 
  2. list1 = range(1,3
  3. list2 = range(4,6
  4. list3 = range(7,9
  5. for item1,item2,item3 in product(list1, list2, list3): 
  6. print(item1+item2+item3) 

輸出如下

  1. $ python demo.py 
  2. 12 
  3. 13 
  4. 13 
  5. 14 
  6. 13 
  7. 14 
  8. 14 
  9. 15 

5. 如何使用 print 輸出日志

初學者喜歡使用 print 來調試代碼,并記錄程序運行過程。

但是 print 只會將內容輸出到終端上,不能持久化到日志文件中,并不利于問題的排查。

如果你熱衷于使用 print 來調試代碼(雖然這并不是最佳做法),記錄程序運行過程,那么下面介紹的這個 print 用法,可能會對你有用。

Python 3 中的 print 作為一個函數(shù),由于可以接收更多的參數(shù),所以功能變?yōu)楦訌姶?,指定一些參?shù)可以將 print 的內容輸出到日志文件中

代碼如下:

  1. >>> with open('test.log', mode='w') as f: 
  2. ... print('hello, python', file=f, flush=True) 
  3. >>> exit 
  4.  
  5. $ cat test.log 
  6. hello, python 

6. 如何快速計算函數(shù)運行時間

計算一個函數(shù)的運行時間,你可能會這樣子做

  1. import time 
  2.  
  3. start = time.time 
  4.  
  5. # run the function 
  6.  
  7. end = time.time 
  8. print(end-start) 

你看看你為了計算函數(shù)運行時間,寫了幾行代碼了。

有沒有一種方法可以更方便的計算這個運行時間呢?

有。

有一個內置模塊叫 timeit

使用它,只用一行代碼即可

  1. import time 
  2. import timeit 
  3.  
  4. def run_sleep(second): 
  5. print(second) 
  6. time.sleep(second) 
  7.  
  8. # 只用這一行 
  9. print(timeit.timeit(lambda :run_sleep(2), number=5)) 

運行結果如下

  1. 2 
  2. 2 
  3. 2 
  4. 2 
  5. 2 
  6. 10.020059824 

7. 利用自帶的緩存機制提高效率

緩存是一種將定量數(shù)據(jù)加以保存,以備迎合后續(xù)獲取需求的處理方式,旨在加快數(shù)據(jù)獲取的速度。

數(shù)據(jù)的生成過程可能需要經過計算,規(guī)整,遠程獲取等操作,如果是同一份數(shù)據(jù)需要多次使用,每次都重新生成會大大浪費時間。所以,如果將計算或者遠程請求等操作獲得的數(shù)據(jù)緩存下來,會加快后續(xù)的數(shù)據(jù)獲取需求。

為了實現(xiàn)這個需求,Python 3.2 + 中給我們提供了一個機制,可以很方便的實現(xiàn),而不需要你去寫這樣的邏輯代碼。

這個機制實現(xiàn)于 functool 模塊中的 lru_cache 裝飾器。

  1. @functools.lru_cache(maxsize=None, typed=False) 

參數(shù)解讀:

  • maxsize:最多可以緩存多少個此函數(shù)的調用結果,如果為None,則無限制,設置為 2 的冪時,性能最佳

  • typed:若為 True,則不同參數(shù)類型的調用將分別緩存。

舉個例子

  1. from functools import lru_cache 
  2.  
  3. @lru_cache(None) 
  4. def add(x, y): 
  5. print("calculating: %s + %s" % (x, y)) 
  6. return x + y 
  7.  
  8. print(add(12)) 
  9. print(add(12)) 
  10. print(add(23)) 

輸出如下,可以看到第二次調用并沒有真正的執(zhí)行函數(shù)體,而是直接返回緩存里的結果

  1. calculating: 1 + 2 
  2. 3 
  3. 3 
  4. calculating: 2 + 3 
  5. 5 

下面這個是經典的斐波那契數(shù)列,當你指定的 n 較大時,會存在大量的重復計算

  1. def fib(n): 
  2. if n < 2
  3. return n 
  4. return fib(n - 2) + fib(n - 1

第六點介紹的 timeit,現(xiàn)在可以用它來測試一下到底可以提高多少的效率。

不使用 lru_cache 的情況下,運行時間 31 秒

  1. import timeit 
  2.  
  3. def fib(n): 
  4. if n < 2
  5. return n 
  6. return fib(n - 2) + fib(n - 1
  7.  
  8.  
  9.  
  10. print(timeit.timeit(lambda :fib(40), number=1)) 
  11. # output: 31.2725698948 

由于使用了 lru_cache 后,運行速度實在太快了,所以我將 n 值由 30 調到 500,可即使是這樣,運行時間也才 0.0004 秒。提高速度非常顯著。

  1. import timeit 
  2. from functools import lru_cache 
  3.  
  4. @lru_cache(None) 
  5. def fib(n): 
  6. if n < 2
  7. return n 
  8. return fib(n - 2) + fib(n - 1
  9.  
  10. print(timeit.timeit(lambda :fib(500), number=1)) 
  11. # output: 0.0004921059880871326 

8. 在程序退出前執(zhí)行代碼的技巧

使用 atexit 這個內置模塊,可以很方便的注冊退出函數(shù)。

不管你在哪個地方導致程序崩潰,都會執(zhí)行那些你注冊過的函數(shù)。

示例如下

5年Python功力,總結了10個開發(fā)技巧

如果clean函數(shù)有參數(shù),那么你可以不用裝飾器,而是直接調用atexit.register(clean_1, 參數(shù)1, 參數(shù)2, 參數(shù)3='xxx')

可能你有其他方法可以處理這種需求,但肯定比上不使用 atexit 來得優(yōu)雅,來得方便,并且它很容易擴展。

但是使用 atexit 仍然有一些局限性,比如:

  • 如果程序是被你沒有處理過的系統(tǒng)信號殺死的,那么注冊的函數(shù)無法正常執(zhí)行。

  • 如果發(fā)生了嚴重的 Python 內部錯誤,你注冊的函數(shù)無法正常執(zhí)行。

  • 如果你手動調用了os._exit,你注冊的函數(shù)無法正常執(zhí)行。

9. 實現(xiàn)類似 defer 的延遲調用

在 Golang 中有一種延遲調用的機制,關鍵字是 defer,例如下面的示例

  1. import "fmt" 
  2.  
  3. func myfunc { 
  4. fmt.Println("B"
  5.  
  6. func main { 
  7. defer myfunc 
  8. fmt.Println("A"

輸出如下,myfunc 的調用會在函數(shù)返回前一步完成,即使你將 myfunc 的調用寫在函數(shù)的第一行,這就是延遲調用。

那么在 Python 中否有這種機制呢?

當然也有,只不過并沒有 Golang 這種簡便。

在 Python 可以使用 上下文管理器達到這種效果

  1. import contextlib 
  2.  
  3. def callback: 
  4. print('B'
  5.  
  6. with contextlib.ExitStack as stack: 
  7. stack.callback(callback) 
  8. print('A'

輸出如下

 

10. 如何流式讀取數(shù)G超大文件

使用 with...open... 可以從一個文件中讀取數(shù)據(jù),這是所有 Python 開發(fā)者都非常熟悉的操作。

但是如果你使用不當,也會帶來很大的麻煩。

比如當你使用了 read 函數(shù),其實 Python 會將文件的內容一次性的全部載入內存中,如果文件有 10 個G甚至更多,那么你的電腦就要消耗的內存非常巨大。

  1. # 一次性讀取 
  2. with open("big_file.txt""r") as fp: 
  3. content = fp.read 

對于這個問題,你也許會想到使用 readline 去做一個生成器來逐行返回。

  1. def read_from_file(filename): 
  2. with open(filename, "r") as fp: 
  3. yield fp.readline 

可如果這個文件內容就一行呢,一行就 10個G,其實你還是會一次性讀取全部內容。

最優(yōu)雅的解決方法是,在使用 read 方法時,指定每次只讀取固定大小的內容,比如下面的代碼中,每次只讀取 8kb 返回。

  1. def read_from_file(filename, block_size = 1024 * 8): 
  2. with open(filename, "r") as fp: 
  3. while True: 
  4. chunk = fp.read(block_size) 
  5. if not chunk: 
  6. break 
  7.  
  8. yield chunk 

上面的代碼,功能上已經沒有問題了,但是代碼看起來代碼還是有些臃腫。

借助偏函數(shù) 和 iter 函數(shù)可以優(yōu)化一下代碼

  1. from functools import partial 
  2.  
  3. def read_from_file(filename, block_size = 1024 * 8): 
  4. with open(filename, "r") as fp: 
  5. for chunk in iter(partial(fp.read, block_size), ""): 
  6. yield chunk 

 

責任編輯:張燕妮 來源: Python編程時光
相關推薦

2020-06-07 16:16:01

Python開發(fā)工具

2019-12-02 14:39:14

密碼登陸體驗

2020-06-30 08:28:29

Vue開發(fā)前端

2021-11-19 16:54:11

Python代碼開發(fā)

2020-06-09 10:55:16

Python編程代碼

2023-07-17 11:43:07

2021-05-17 09:31:58

爬蟲偽裝技巧

2018-05-21 09:55:09

Java編程技巧

2019-07-31 14:33:23

UI設計UI界面動畫

2020-06-23 08:28:26

前端開發(fā)技巧

2015-07-27 09:36:09

storyboard

2019-03-15 10:25:00

技術研發(fā)指標

2020-06-08 07:52:31

Python開發(fā)工具

2015-06-04 10:44:59

WebAPP開發(fā)技巧

2015-06-17 10:28:10

WebAPP開發(fā)技巧

2013-04-18 10:19:40

iOS開發(fā)Xcode調試

2014-07-03 16:35:38

WebApp開發(fā)技巧總結

2009-08-27 16:54:59

C#開發(fā)技巧

2010-01-22 16:35:41

C++開發(fā)

2020-07-10 14:25:32

Python編程代碼
點贊
收藏

51CTO技術棧公眾號