1. 程式人生 > >python 程式優化字典(自用)

python 程式優化字典(自用)

這篇文章用來做<流暢的python>體驗備忘錄,也作為日後開發的優化字典實用

  1. 快速的建立一個只有簡單的屬性的class
    用namedtuple構建的class對記憶體的消耗跟元組是一樣的, 因為欄位名都被
    存在對應的class裡面.跟普通的物件例項比起來也要小一些,因為python不
    會用 dict 來存放這些例項的屬性.
#class名為 name ,屬性有 a, b
import collections
Name = collections.namedtuple( 'Name' , ['a' , 'b'])
  1. 靜態方法的建立與使用
#靜態方法就是一個class中定義的一個不使用內部資源的函式, 
#目的可以不經過例項化直接呼叫, 其意義則是一個 namespace
  1. abs的使用,其實質上並不是 |abs| , 而是 abs2後進行開平方運算, 對於多維陣列, 同下
v1 = vector(3, 4)
print (abs( v1 ))
5.0
  1. 對於class作為函式引數傳遞的理解
#對於class的本質上是不接受任何形式的被傳參呼叫的,但是他有很多種特殊方法,使其看起來像是可以被作為引數傳遞進去,例如
# r' '  會隱式呼叫 __repr__ () 方法
# 字串拼接符號 +   則會隱式呼叫  __add__()
#下標訪問 string[num]    則會隱式呼叫 __getiem__()
所以,對於開發者來說,實現一個特殊項功能需要用繼承或者修改原型進行深度自定義, 
但不瞭解的情況下, 最好不要觸碰觸碰這些特殊方法, 否則會導致莫名其妙的bug
  1. 關於len()的獨特性理解
#與其他方法不同, vector , array , list 等容器內往往都有一些特殊的內建屬性, 
有可能是私有屬性, 如 self._len ,他就統計了容器長度, 所以len( array ) 並不需要計算, 
而是直接通過方法來讀取私有屬性, 這樣便走了捷徑.
  1. 內建序列的的理解
#容器序列: list , tuple , collections.deque 等
#扁平序列: str , bytes , bytearray , memoryview , array.array
#容器序列是它們所包含的任意型別的物件的引用,而扁平序列則存放的是值而不是引用,
用棧堆來解釋看, 扁平序列執行會更加效率,扁平序列只能包含原子資料型別.
  1. 列表推導的深入理解,其中坑多,for迴圈的書寫格式直接導致結果的不同和執行效率的差異,跳轉詳情

  2. 元組的意義

#元組是對資料的記錄: 元組中的每個元素都存放了記錄中一個欄位的資料, 外加這個欄位的位置.
#用來組拆包

9.切片的使用誤區

#切片的區間是 [a , b), [0, 10 , -2] 的執行則是 倒著往前切
#對物件進行切片的問題, 內部一定要有特殊方法 __getitem__() 和 __setitem__() ,
對於容器class會有預設的方法,而這種預設方法只能對一維佇列進行切片, 如果需要對多維佇列切片, 
則需要自定義.
  1. 元組 +=的謎題 bug
t = (1, 2 ,[3, 4])
t[2] += [5, 6]
#其執行結果是  TypeError 都是能夠想到的, 然而意想不到的是  t已經被修改成為 (1, 2 , [3, 4, 5, 6]),
但是通過除錯測試不出來的, 只有通過 dis.dis('t[2] += [5, 6]'), 檢視位元組碼可以找到原因.

如果看不懂位元組碼,可以藉助tutor視覺化工具進行檢視,工具很強大.

  1. sort 排序的小技巧
在排序中,list.sort() 是就地排序, 而sorted 則是產生一個新list ,這個雖然都是常識 ,但是 list.sort()同樣有返回值, 
返回None,可以通過其返回值進行有效避免bug的存在
a = [3, 4, 1, 6]
if not a.sort():
    print('後續程式繼續')
    print(a)
  1. 用bisect來管理已排序的序列
    排序很耗時,如果通過append來尾部插入再進行排序的話,無疑是很蠢的行為,
    如果能夠計算出插入元素應該在已排序佇列的位置,再進行插入, bisect模組就可以做到.

  2. array模組的現實意義,二進位制的高效性
    array是一個扁平容器,可以在棧內進行讀寫,本質上它是一個原生的C風格陣列.

from array import  array
from random import random
from time import ctime

print(ctime())
floats = array('d', (random() for i in range(10**8)))
print(floats[-1])
fp = open('floats.bin', 'wb')
floats.tofile(fp)
fp.close()
floats2 = array('d')
fp = open('floats.bin', 'rb')
floats2.fromfile(fp, 10**8)
fp.close()
print(floats2[-1])

print(ctime())

可以通過改用list測驗兩者差別, 實測結果是 不用io的情況下,兩者耗時相近,但是array佔用cpu更低,
而list更容易激起cpu全速,我就跑崩過
用array.fromfile從一個二進位制檔案讀取速度是文字檔案的60倍,因為後者會使用內建的float方法把
每一行文字轉換成浮點數. 另外寫入速度快7倍, 需要的儲存空間則會小一倍以上.
所以二進位制檔案是優選.

  1. 記憶體檢視memoryview
    它能夠讓使用者在不復制內容的情況下,操作同一個陣列的不同切片,也是為效率而生

  2. 數學運算 Numpy 和 Scipy
    比如線性代數的矩陣翻轉, 把一維list轉換成多維等科學計算操作,但是pycharm不自帶,需要自行下載安裝

  3. collections.deque 雙向佇列(堆)
    雖然list的 .append 和 .pop(0)合起來用也可以模擬堆,但是從頭插入或刪除是非常耗時的,
    deque模擬了堆, 可以從頭 尾新增,旋轉等操作, 但是為了實現這些方法, 付出了一定的代價,
    從佇列中間刪除元素的操作慢一些,因為它只對在頭尾的操作進行了優化

from collections import deque
dq = deque(range(10), maxlen=10)
print(dq)
dq.rotate(3)
print(dq)
dq.rotate(-4)
print(dq)
dq.appendleft(-1)
print(dq)
dq.extend([11, 22, 33])
print(dq)
dq.extendleft([44, 55, 66])
print(dq)
deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6], maxlen=10)
deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0], maxlen=10)
deque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
deque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33], maxlen=10)
deque([66, 55, 44, 3, 4, 5, 6, 7, 8, 9], maxlen=10)

17.排序中的演算法效率問題
list.sort , sorter , max , min 函式的key引數, cmp(a, b)的比較引數之間的區別:
key引數可以對容器中每個元素進行求值,再按照這些值的大小進行排序,後者發生在C語言層
cmp(a, b)則發生在python層,所以不僅僅key可以對不同資料型別的容器元素進行排序,
而且在效率上更快.

未完成,施工中…