寫在前面
Python是一門解釋型的、動態型的OOP語言,結識Python的這幾年來,其語法的簡潔、結構的條理性深刻的吸引了我。下面是我總結出來的一些Python常用知識點。
列表碾平式
需求: 將[[1,2],[3,4]] 轉換為[1,2,3,4],具體實現有以下幾種方法
test_list = [[1,2],[3,4]]
1. from itertools import chain
list(chain.from_iterable(test_list))
結果:[1, 2, 3, 4]
2. from itertools import chain
list(chain(*test_list))
結果:[1, 2, 3, 4]
3. sum(test_list, [])
結果:[1, 2, 3, 4]
4. [x for y in test_list for x in y]
結果:[1, 2, 3, 4]
5. 萬能方法(遞迴)
func = lambda x: [y for t in x for y in func(t)] if type(x) is list else [x]
func(test_list)
結果:[1, 2, 3, 4]複製程式碼
PS: 專案中,難免會有類似的需求,對於結構巢狀一致的情況,上述的1,2,3,4方法都可以很好的解決(不建議用for迴圈巢狀的方式,那是最low的方法,沒有之一);對於結構巢狀不一致的情況,第5種方法就派上了用場,其採用了遞迴的思想,堪稱萬能的方法,屢試不爽。專案中,大家可以根據實際應用場景來挑選最適合自己的方法。肚中有糧,心中不慌;大家可以把上述方法都記下來,以做到有的放矢。
三目操作符
對於Python的三元表示式,想必大家對if else
都不會感到陌生,但是對and or
操作想必是另一種感覺了,不過大家對其他語言的? :
應該不會陌生,沒錯,這次的主角and or
就和? :
有著異曲同工之妙。
程式碼參考:
1 == 1 and 2 or 3 返回2
1 == 2 and 2 or 3 返回3複製程式碼
PS:習慣於if else
的同學偶爾用下and or
是不是會給人耳目一新的感覺。
and or 分開來用
- [x] and 用法如下:
1 and 2 and 3 返回3
1 and 2 and '' 返回''
'' and 2 and 0 返回''
PS:如果都為真則返回最後一個值,如果其中某些值為假,則返回第一個為假的值複製程式碼
- [x] or 用法如下
1 or '' or 0 返回1
'' or 0 or [] 返回[]
PS:如果都為假返回最後一個值,如果其中某些值為真,則返回第一個為真的值複製程式碼
使用場景:在專案中我們經常會有這樣的需求,在將一個字典更新之後還想要返回更新後的字典,這是我們就可以這樣寫:dic = dic1.update(dic2) or dic1
列表推導式
需求:將[1,2,3]中的每一項都加1
good: [x+1 for x in [1,2,3]]
bad: def add_list(goal_list):
tmp_list = []
for x in goal_list:
tmp_list.append(x+1)複製程式碼
PS: 列表推導式底層是用C實現的,其執行速度要比for迴圈快好多
vars() 用法
程式碼參考:
```
def func(a, b, c):
print vars()
執行func(1, 2, 3)
輸出:{"a":1,"b":2,"c":3}
PS: vars()的值為字典,其鍵值對來源於當前作用域的所有變數。
```複製程式碼
使用場景:在呼叫他人介面或方法時,需要將傳入的引數列印以記錄日誌,此刻vars()便派上用場了。
偏函式之partial
程式碼示例:
import functools
def add(a, b):
return a + b
add(4, 2)
6
plus3 = functools.partial(add, 3)
plus5 = functools.partial(add, 5)
plus3(4)
7
plus3(7)
10
plus5(10)
15複製程式碼
實際使用心得:
之前做物件儲存的專案中,我需要同時去呼叫三個一樣的介面(大部分引數一樣)下面是我的部分程式碼,供大家參考
my_thread = functools.partial(myThread, dic, zone_id, start, end, customer_id) my_thread1 = my_thread("day", "gets", "2") my_thread1 = my_thread("day", "original_traffic", "3")複製程式碼
使用場景:
當我們需要同時去呼叫一個函式,並且發現大部分引數一致的時候,便可以採取上述方法,一來程式碼簡潔,二來可讀性高。
Python搭建簡易服務
- Python搭建簡易郵件伺服器:
python -m smtpd -n -c DebuggingServer localhost:1025
Python搭建簡易web伺服器:
- Python2:
python -m SimpleHTTPServer port
- Python3:
python -m http.server port
- Python2:
Python搭建簡易ftp服務
pip install pyftpdlib python -m pyftpdlib -p 21 ftp://localhost:21複製程式碼
遍歷字典
在專案中遍歷字典是很常見的需求,下面介紹下常用的方法並做下比較:
dic = {'name': 'peter', 'age': 27}
1. for key, value in dic.items():
print key, value
2. for key, value in dic.iteritems():
print key, value複製程式碼
PS:iteritems
和items
的區別在於iteritems
採用了生成器的原理,只有在需要的時候才會把值生成,其之間的區別類似於range
和 xrange
;readline
和 xreadline
記憶體管理
Python的記憶體管理主要分為引用計數和垃圾回收機制兩大部分,且看下面程式碼:
[ ] 記憶體分配:
a = 1 b = 1 a is b True --------------------- a = 1000 b = 1000 a is b False複製程式碼
PS: 在Python中,整數和短小的字元,Python都會快取這些物件,以便重複使用。當我們建立多個等於1的引用時,實際上是讓這些引用指向了同一個物件。
[ ] 引用計數:
在Python中,所謂引用計數(reference count)是指所有指向該物件的引用的總數;
我們可以使用
sys
包中的getrefcount()
,來檢視某個物件的引用計數。需要注意的是,當使用該函式檢視某個物件的引用計數時,實際上是臨時建立了該物件的一個新的引用,所有使用getrefcount()
所得到的結果,會比期望的值多1。from sys import getrefcount aa = 'test refcount' print(getrefcount(a)) bb = aa print(getrefcount(a))複製程式碼
PS: 由於上述原因,兩個
getrefcount()
將返回2和3,並不是期望的1和2.[ ] 引用減少
引用減少大致分為兩類:
指向該物件的引用指向了其他物件
from sys import getrefcount aa = 'test refcount' bb = aa print(getrefcount(aa)) 3 bb = 1 print(getrefcount(aa)) 2複製程式碼
使用
del
關鍵字顯示的刪除某個引用from sys import getrefcount aa = 'test refcount' bb = aa print(getrefcount(aa)) 3 del bb print(getrefcount(aa)) 2複製程式碼
[ ] 垃圾回收
不斷的建立物件,如果不及時銷燬的話,那Python的體積會越來越大,再大的記憶體也會有耗完的時候;不用像C語言那樣,需要手動的去管理記憶體、Python已經幫我們做好了(Python的垃圾回收機制),你只需要去關心你的業務邏輯即可,其他的都交給Python來處理。
從原理上講,當Python中某個物件的引用計數降為0時,該物件就應該被回收。但是頻繁的啟動垃圾回收機制畢竟是個很耗時的問題;因此Python只有在特定條件下(當Python中被分配物件和取消分配物件的次數之間的差值達到某個閾值時),Python會自動啟動垃圾回收機制。
我們可以通過
gc
模組的get_threshold()
方法,檢視該閾值:import gc print(gc.get_threshold())複製程式碼
該方法會返回
(700, 10, 10)
,後面的倆10是與分代回收相關的,稍後講解。700便是垃圾回收機制啟動的閾值。可以通過gc
模組中的set_threshold()
方法重新設定該值。當然了,我們也可以手動啟動垃圾回收機制,使用
gc.collect()
即可。[ ] 分代回收
Python同時採用了分代回收的機制,設想一下:存活越久的物件、越不可能是垃圾物件。程式在執行時,往往會產生大量的臨時物件,程式結束之後,這些臨時物件的生命週期也就隨之告一段落。但有一些物件會被長期佔用,垃圾回收機制在啟動的時候會減少掃描到他們的頻率。
Python將所有物件分為0,1,2三代。所有新建立的物件都是0代,當垃圾回收機制在啟動多次0代機制並掃描到他們的時候,這些物件如果依然存活在記憶體的話,他們就會被歸入下一代物件,以此類推。
剛才上面所提到的
(700, 10, 10)
三個引數後面的倆10所代表的意思是:每10次0代垃圾回收,會配合1次1代的垃圾回收;而每10次1代的垃圾回收會配合1次的2代垃圾回收。當然我們同樣可以使用
set_threshold()
來調整此策略的比例,比如對1代物件進行更頻繁的掃描。import gc gc.set_threshold(700, 5, 10)複製程式碼
新式類、經典類
[ ] 新式類: 顯示的繼承了
object
的類class A(object): attr = 1 class B(A): pass class C(A): attr = 3 class D(B, C): pass if __name__ == '__main__': d = D() print 'attr = ', d.attr # attr = 3複製程式碼
[ ] 經典類:沒有繼承自
object
的類class A(): attr = 1 class B(A): pass class C(A): attr = 3 class D(B, C): pass if __name__ == '__main__': d = D() print 'attr = ', d.attr # attr = 1複製程式碼
PS: 通過以上程式碼的輸出結果可以看出,新式類會廣度搜尋,也就是一層層的向上搜尋;經典類是深度優先,即遇到一個超類點就向上搜尋。
裝飾器
Python的裝飾器被稱為Python的語法糖,哪裡需要粘哪裡。
程式碼示例:
@makeh1
@makeeitalic
def say():
return 'Peter'
我們希望輸出結果為:<h1><i>Peter</i></h1>複製程式碼
去看看官方文件,答案就看下面:
def makeh1(func):
def wrp():
return "<h1>" + func() + "</h1>"
return wrp
def makeeitalic(func):
def wrp():
return "<i>" + func() + "</i>"
return wrp
@makeh1
@makeeitalic
def say():
return 'Hello Peter'
print say()
輸出:<h1><i>Hello Peter</i></h1>複製程式碼
實際應用場景:
使用過django
的小夥伴想必都用過login_required
裝飾器,但是如果使用者沒登入的話login_required
會重定向到登入頁面;在做web開發的過程中,我們會經常用
ajax非同步提交資料到後臺,這時如果再繼續使用原有的login_required
裝飾器肯定是不行了(該裝飾器不會重定向到登入頁面,ajax也沒有任何返回結果),下面我們改變下原有程式碼:
from django.shortcuts import HttpResponse
import json
def is_authenticat(func):
def wrp(req, **kwargs):
if req.user.is_authenticated():
return func(req, **kwargs)
else:
json_str = {'status': 0, 'msg': u'請登入'}
return HttpResponse(json.dumps(json_str), content_type='application/json')
return wrp複製程式碼
上述程式碼便很好的解決了問題,也算是對Python裝飾器的一個很好的使用場景。
寫在結語
Python的奧妙遠不止於此
Python的深度還需要繼續探索
以上就是平時工作中所總結出來的常用的知識點
希望對大家以後的工作會有所幫助