流暢的python

流暢的python中有不少奇技淫巧,整本書都在強調如何最大限度地利用Python 標準庫。介紹了不少python的不經常使用的數據類型、操做、庫等,對於入門python後想要提高對python的認識應該有幫助。目前讀一遍記錄了一些有共鳴的操做:html

Python內置序列類型的主要分類:

按可存放的元素類型分爲:容器序列和扁平序列python

  1. 容器序列,就是什麼都能做爲元素往裏放,包括另外一個序列。須要注意的是,若是元素是序列類型,那麼存放的每每是引用,須要當心。

常見的容器序列包括:list,tuple,array.array,collections.deque等。程序員

  1. 扁平序列,存放的都是原子級元素,此時存放的是值而不會是引用。

常見的扁平序列包括:str,bytes,bytearray, memoryview, array.array等。express

按序列可否被修改分爲:可變序列與不可變序列vim

  1. 可變序列:能夠進行增、刪、改等操做的序列,包括list, bytearray, array.array, collections.deque, memoryview等。
  2. 不可變序列:不可進行上述操做的序列,包括tuple, str, bytes等。

字典的變種

標準庫裏collections模塊中提供了不少與字典類型類似的變種。segmentfault

OrderDict: 這個類型在添加鍵的時候,會保存順序,所以鍵的迭代順序老是一致的數組

ChainMap: 該類型能夠容納數個不一樣的映射對像,在進行鍵的查找時,這些對象會被當作一個總體逐個查找,直到鍵被找到爲止安全

Counter: 這個映射類型會給鍵準備一個整數技術器,每次更行一個鍵的時候都會增長這個計數器,因此這個類型能夠用來給散列表對象計數,或者當成多重集來用。多線程

UserDict: 這個類其實就是把標準的dict用Python又寫了一遍。通常用來給程序員想要經過繼承dict建立本身的dict時,代替dict使用的。主要是由於直接繼承原生dict會出現bug。app

defaultdict:處理找不到的鍵的一個選擇
當某個鍵不在映射裏, 咱們也但願也能獲得一個默認值. 這就是 defaultdict , 它是 dict 的子類, 並實現了 missing 方法.

dict的實現以及致使的結果

鍵必須是可散列的:
一個可散列的對象必須知足如下要求。
    (1) 支持 hash() 函數,而且經過 __hash__() 方法所獲得的散列值是不變的。
    (2) 支持經過 __eq__() 方法來檢測相等性。
    (3) 若 a == b 爲真,則 hash(a) == hash(b) 也爲真。
    全部由用戶自定義的對象默認都是可散列的,由於它們的散列值由 id() 來獲取,而
    且它們都是不相等的。
字典在內存上開銷很大(用內存換效率)。
    元組取代字典就能節省空間的緣由有兩個:
    (1) 避免了散列表所耗費的空間,
    (2) 無需把記錄中字段的名字在每一個元素裏都存一遍。
鍵的查詢很快
鍵的次序取決於添加順序
往字典裏添加新鍵可能會改變已有鍵的順序

set的實現以及致使的結果

結合的元素必須是可散列的
集合和消耗內存
能夠很高效的判斷元素是否存在於某個集合
元素的次序取決於被添加到集合裏的順序
往集合裏添加元素,可能會改變集合裏已有的元素次序

collections.namedtuple 能夠用來構建一個帶字段名的元組和一個有名字的類

建立一個具名元組須要兩個參數,一個是類名,另外一個是類的各個字段的名字。後者
能夠是由數個字符串組成的可迭代對象,或者是由空格分隔開的字段名組成的字符串。

>>> from collections import namedtuple
>>> City = namedtuple('City', 'name country population coordinates')
>>> tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667)) 
>>> tokyo
City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722,
139.691667))
>>> tokyo.population 
36.933
>>> tokyo.coordinates
(35.689722, 139.691667)
>>> tokyo[1]
'JP'

>>> City = namedtuple('City_Name', 'name country population coordinates')
>>> tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
>>> tokyo
City_Name(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139.691667))

當列表不是首選時

  1. 若是咱們須要一個只包含數字的列表,那麼 array.array 比 list 更高效。數組支持所

有跟可變序列有關的操做,包括 .pop、.insert 和 .extend。另外,數組還提供從文件
讀取和存入文件的更快的方法,如 .frombytes 和 .tofile。

  1. set 專爲檢查元素是否存在作過優化
  2. memoryview 是一個內置類,它能讓用戶在不復制內容的狀況下操做同一個數組的不一樣切

片。

  1. 使用NumPy和SciPy提供的高階數組和矩陣操做
  2. 使用雙向隊列和其餘形式的隊列(collections.deque 雙向隊列類、queue類中的 Queue、LifoQueue和PriorityQueue、multiprocessing. Queue、heapq能夠把可變序列看成堆隊列或者優先隊列來使用)

Python 格式化輸出

在進行格式化輸出時,%r 與 %s 的區別就比如 repr() 函數處理對象與 str() 函數處理對象的差異。

  • %s -> str(),比較智能;
  • %r -> repr(),處理較爲簡單和直接; 處理一些簡單對象時,兩者幾乎沒有差異.

本文重點列舉一些兩者的差別化用法:

  1. 處理字符串時
>> s = 'world'

>> print('hello %s'%s)
hello world
>> print('hello %r'%s)
hello 'world'

>> str(s)
'world'
>> repr(s)
"'world'"
2. datetime 庫中的 datetime 對象
>> from datetime import datetime 
>> timeinfo = datetime.today()

>> timeinfo
datetime.datetime(2016, 6, 7, 21, 17, 34, 925488)
>> type(timeinfo)
datetime.datetime

>> repr(timeinfo)
'datetime.datetime(2016, 6, 7, 21, 17, 34, 925488)'
>> str(timeinfo)
'2016-06-07 21:17:34.925488'

反彙編函數 python opcode

Python dis 模塊支持對Python代碼進行反彙編, 生成字節碼指令。

In[1]: def test():
...         x = 1
...         if x < 3:
...             return "yes"
...         else:
...             return "no"

In[2]: dis.dis(test)
  2           0 LOAD_CONST               1 (1)
              3 STORE_FAST               0 (x)
 
  3           6 LOAD_FAST                0 (x)
              9 LOAD_CONST               2 (3)
             12 COMPARE_OP               0 (<)
             15 POP_JUMP_IF_FALSE       22
 
  4          18 LOAD_CONST               3 ('yes')
             21 RETURN_VALUE        
 
  6     >>   22 LOAD_CONST               4 ('no')
             25 RETURN_VALUE        
             26 LOAD_CONST               0 (None)
             29 RETURN_VALUE        

>>> def add(a, b = 0):
...     return a + b
... 
>>> 

>>> dis.dis(add)
  2           0 LOAD_FAST                0 (a)
              2 LOAD_FAST                1 (b)
              4 BINARY_ADD
              6 RETURN_VALUE
>>>

class memoryview(obj)是python的內置類,若是要用memoryview 去引用一個object, 那麼這個object 必須支持buffer protocol, python3 中原生(built-in) 支持buffer protocol的obj有bytes和bytearray,memoryview可使用不一樣的方式讀取和操做同一塊內存,而且原有的內存字節不會隨意移動。相似於C中的強轉,好處是不會有內存拷貝。

例如,使用memoryview修改一個短整型有符號整數數組的數據。

from array import array
from random import random

numbers = array('h', [-2, -1, 0, 1, 2]) #signed short
memv = memoryview(numbers)      #5個短整型有符號整數的數組建立一個memoryview
print (len(memv))               #打印長度
print (memv.tolist())           #轉換成列表形式

memv_oct = memv.cast('B')       #內存共享 轉換成無符號字符類型
print (memv_oct.tolist())

memv_oct[5] = 4                 #把位置5的字節賦值成4
print (numbers)                 #由於咱們把佔 2 個字節的整數的高位字節改爲了 4,因此這個有符號整數的值就變成了 1024

輸出以下:

5                       #數組長度
[-2, -1, 0, 1, 2]       #列表形式顯示
[254, 255, 255, 255, 0, 0, 1, 0, 2, 0]#長度擴大一倍 轉換爲無符號字符類型
array('h', [-2, -1, 1024, 1, 2])   #原來的數組被修改

bytearray是可變(mutable)的字節序列,相對於Python2中的str,但str是不可變(immutable)的。
在Python3中因爲str默認是unicode編碼,因此只有經過bytearray才能按字節訪問。
下面兩種行爲的對比:
簡單點就是,str和bytearray的切片操做會產生新的切片str和bytearry並拷貝數據,使用memoryview以後不會。

python2中的例子

不使用memoryview
>> a = 'aaaaaa'
>> b = a[:2]    # 會產生新的字符串

>> a = bytearray('aaaaaa')
>> b = a[:2]    # 會產生新的bytearray
>> b[:2] = 'bb' # 對b的改動不影響a
>> a
bytearray(b'aaaaaa')
>> b
bytearray(b'bb')
使用memoryview
>> a = 'aaaaaa'
>> ma = memoryview(a)
>> ma.readonly  # 只讀的memoryview
True
>> mb = ma[:2]  # 不會產生新的字符串

>> a = bytearray('aaaaaa')
>> ma = memoryview(a)
>> ma.readonly  # 可寫的memoryview
False
>> mb = ma[:2]      # 不會會產生新的bytearray
>> mb[:2] = 'bb'    # 對mb的改動就是對ma的改動
>> mb.tobytes()
'bb'
>> ma.tobytes()
'bbaaaa'

Python 中有各類各樣可調用的類型,所以判斷置的 callable() 函數:

>>> abs, str, 13
(<built-in function abs>, <class 'str'>, 13)
>>> [callable(obj) for obj in (abs, str, 13)]
[True, True, False]
random.shuffle 打亂序列
>>> import random
>>> a=range(10)
>>> random.shuffle(a)
>>> a
[1, 0, 8, 5, 6, 7, 9, 3, 2, 4]
>>> random.shuffle(a)
>>> a
[7, 5, 6, 2, 1, 8, 9, 0, 3, 4]

vim經常使用快捷

  • 0 → 數字零,到行頭
  • $ → 到本行行尾
  • a → 在光標後插入
  • o → 在當前行後插入一個新行
  • O → 在當前行前插入一個新行
  • cw → 替換從光標所在位置後到一個單詞結尾的字符
  • . → (小數點) 能夠重複上一次的命令
  • NG → 到第 N 行 (注意命令中的G是大寫的,另我通常使用 : N 到第N行,如 :137 到第137行)
  • gg → 到第一行。(至關於1G,或 :1)
  • G → 到最後一行。
  • 在 Insert 模式下,你能夠輸入一個詞的開頭,而後按<Ctrl-p>或是<Ctrl-n>,自動補齊功能就出現了…

內置函數

Math
Function    Description
abs()    Returns absolute value of a number
divmod()    Returns quotient and remainder of integer division
max()    Returns the largest of the given arguments or items in an iterable
min()    Returns the smallest of the given arguments or items in an iterable
pow()    Raises a number to a power
round()    Rounds a floating-point value
sum()    Sums the items of an iterable

Type Conversion
Function    Description
ascii()    Returns a string containing a printable representation of an object
bin()    Converts an integer to a binary string
bool()    Converts an argument to a Boolean value
chr()    Returns string representation of character given by integer argument
complex()    Returns a complex number constructed from arguments
float()    Returns a floating-point object constructed from a number or string
hex()    Converts an integer to a hexadecimal string
int()    Returns an integer object constructed from a number or string
oct()    Converts an integer to an octal string
ord()    Returns integer representation of a character
repr()    Returns a string containing a printable representation of an object
str()    Returns a string version of an object
type()    Returns the type of an object or creates a new type object

Iterables and Iterators
Function    Description
all()    Returns True if all elements of an iterable are true
any()    Returns True if any elements of an iterable are true
enumerate()    Returns a list of tuples containing indices and values from an iterable
filter()    Filters elements from an iterable
iter()    Returns an iterator object
len()    Returns the length of an object
map()    Applies a function to every item of an iterable
next()    Retrieves the next item from an iterator
range()    Generates a range of integer values
reversed()    Returns a reverse iterator
slice()    Returns a slice object
sorted()    Returns a sorted list from an iterable
zip()    Creates an iterator that aggregates elements from iterables

Composite Data Type
Function    Description
bytearray()    Creates and returns an object of the bytearray class
bytes()    Creates and returns a bytes object (similar to bytearray, but immutable)
dict()    Creates a dict object
frozenset()    Creates a frozenset object
list()    Constructs a list object
object()    Returns a new featureless object
set()    Creates a set object
tuple()    Creates a tuple object

Classes, Attributes, and Inheritance
Function    Description
classmethod()    Returns a class method for a function
delattr()    Deletes an attribute from an object
getattr()    Returns the value of a named attribute of an object
hasattr()    Returns True if an object has a given attribute
isinstance()    Determines whether an object is an instance of a given class
issubclass()    Determines whether a class is a subclass of a given class
property()    Returns a property value of a class
setattr()    Sets the value of a named attribute of an object
super()    Returns a proxy object that delegates method calls to a parent or sibling class

Input/Output
Function    Description
format()    Converts a value to a formatted representation
input()    Reads input from the console
open()    Opens a file and returns a file object
print()    Prints to a text stream or the console

Variables, References, and Scope
Function    Description
dir()    Returns a list of names in current local scope or a list of object attributes
globals()    Returns a dictionary representing the current global symbol table
id()    Returns the identity of an object
locals()    Updates and returns a dictionary representing current local symbol table
vars()    Returns __dict__ attribute for a module, class, or object

Miscellaneous
Function    Description
callable()    Returns True if object appears callable
compile()    Compiles source into a code or AST object
eval()    Evaluates a Python expression
exec()    Implements dynamic execution of Python code
hash()    Returns the hash value of an object
help()    Invokes the built-in help system
memoryview()    Returns a memory view object
staticmethod()    Returns a static method for a function
__import__()    Invoked by the import statement

跟運算符無關的特殊方法

類別 方法名
字符串 / 字節序列表示形式 __repr__、__str__、__format__、__bytes__
數值轉換 __abs__、__bool__、__complex__、__int__、__float__、__hash__、__index__
集合模擬 __len__、__getitem__、__setitem__、__delitem__、__contains__
迭代枚舉 __iter__、__reversed__、__next__
可調用模擬 __call__
上下文管理 __enter__、__exit__
實例建立和銷燬 __new__、__init__、__del__
屬性管理 __getattr__、__getattribute__、__setattr__、__delattr__、__dir__
屬性描述符 __get__、__set__、__delete__
跟類相關的服務 __prepare__、__instancecheck__、__subclasscheck__

Bisect模塊管理有序的序列

bisect.bisect_left(a,x, lo=0, hi=len(a)) :
查找在有序列表 a 中插入 x 的index。lo 和 hi 用於指定列表的區間,默認是使用整個列表。若是 x 已經存在,在其左邊插入。返回值爲 index。
bisect.bisect_right(a,x, lo=0, hi=len(a))
bisect.bisect(a, x,lo=0, hi=len(a)) :
這2個函數和 bisect_left 相似,但若是 x 已經存在,在其右邊插入。
bisect.insort_left(a,x, lo=0, hi=len(a)) :
在有序列表 a 中插入 x。和 a.insert(bisect.bisect_left(a,x, lo, hi), x) 的效果相同。
bisect.insort_right(a,x, lo=0, hi=len(a))
bisect.insort(a, x,lo=0, hi=len(a)) :
和 insort_left 相似,但若是 x 已經存在,在其右邊插入。
Bisect 模塊提供的函數能夠分兩類: bisect* 只用於查找 index, 不進行實際的插入;而 insort* 則用於實際插入。

當list不是最優選擇時,dict是python的核心類型,但它是以空間換時間的結果,比較佔內存,tuple是dict結構比較好的替代,set用來作是否包含和去重很合適。

from array import array  
from random import random
floats = array('d', (random() for i in range(10**7)))  
fp = open('floats.bin', 'wb')
floats.tofile(fp)  
fp.close()
floats2 = array('d')  
fp = open('floats.bin', 'rb')
floats2.fromfile(fp, 10**7)  
fp.close()
floats2 == floats

Python_內置四種隊列

from queue import Queue #LILO隊列
q = Queue() #建立隊列對象
q.put(0)    #在隊列尾部插入元素
q.put(1)
q.put(2)
print('LILO隊列',q.queue)  #查看隊列中的全部元素
print(q.get())  #返回並刪除隊列頭部元素
print(q.queue)

from queue import LifoQueue #LIFO隊列
lifoQueue = LifoQueue()
lifoQueue.put(1)
lifoQueue.put(2)
lifoQueue.put(3)
print('LIFO隊列',lifoQueue.queue)
lifoQueue.get() #返回並刪除隊列尾部元素
lifoQueue.get()
print(lifoQueue.queue)

from queue import PriorityQueue #優先隊列
priorityQueue = PriorityQueue() #建立優先隊列對象
priorityQueue.put(3)    #插入元素
priorityQueue.put(78)   #插入元素
priorityQueue.put(100)  #插入元素
print(priorityQueue.queue)  #查看優先級隊列中的全部元素
priorityQueue.put(1)    #插入元素
priorityQueue.put(2)    #插入元素
print('優先級隊列:',priorityQueue.queue)  #查看優先級隊列中的全部元素
priorityQueue.get() #返回並刪除優先級最低的元素
print('刪除後剩餘元素',priorityQueue.queue)
priorityQueue.get() #返回並刪除優先級最低的元素
print('刪除後剩餘元素',priorityQueue.queue)  #刪除後剩餘元素
priorityQueue.get() #返回並刪除優先級最低的元素
print('刪除後剩餘元素',priorityQueue.queue)  #刪除後剩餘元素
priorityQueue.get() #返回並刪除優先級最低的元素
print('刪除後剩餘元素',priorityQueue.queue)  #刪除後剩餘元素
priorityQueue.get() #返回並刪除優先級最低的元素
print('所有被刪除後:',priorityQueue.queue)  #查看優先級隊列中的全部元素

from collections import deque   #雙端隊列
dequeQueue = deque(['Eric','John','Smith'])
print(dequeQueue)
dequeQueue.append('Tom')    #在右側插入新元素
dequeQueue.appendleft('Terry')  #在左側插入新元素
print(dequeQueue)
dequeQueue.rotate(2)    #循環右移2次
print('循環右移2次後的隊列',dequeQueue)
dequeQueue.popleft()    #返回並刪除隊列最左端元素
print('刪除最左端元素後的隊列:',dequeQueue)
dequeQueue.pop()    #返回並刪除隊列最右端元素
print('刪除最右端元素後的隊列:',dequeQueue)


以上隊列在多線程中可使用的且線程安全,但在多進程中都不能用於通訊。在多進程中,須要這樣使用:
from multiprocessing import Process, Queue
myqueue = Queue(100)


## 參考

https://blog.csdn.net/sinat_38682860/article/details/80392493 
https://www.cnblogs.com/cmnz/p/6936181.html

關鍵字

from keyword import kwlist
print(kwlist)

builtins模塊

import builtins
dir(builtins)

Python locals() 的陷阱

https://segmentfault.com/a/1190000012724861

def test():
    globals()['a2'] = 4
test()
print a2   # 輸出 4


def aaaa():
    print locals()
    for i in ['a', 'b', 'c']:
        locals()[i] = 1
    print locals()
    print a # 錯誤:NameError: global name 'a' is not defined
aaaa()

動態地進行變量賦值時,locals() 看到的, 的確是函數的局部命名空間的內容, 可是它自己不能表明局部命名空間, 這就好像一個代理, 它收集了A, B, C的東西, 展現給我看, 可是我卻不能簡單的經過改變這個代理, 來改變A, B, C真正擁有的東西!
這也就是爲何, 當咱們經過locals()[i] = 1的方式去動態賦值時, print a卻觸發了NameError異常, 而相反的, globals()確實真正的全局命名空間,
因此通常會說locals() 只讀, globals() 可讀可寫。

x += y vs x = x + y

對於通常不可變類型的變量來講這兩個方法沒啥區別,但對於可變類型如list(列表),dict(字典)就有區別了,x += y 就地改變了list的值,而x = x + y建立了一個新的list並從新將x綁定上去,經過id(x)就能夠看出。

l = l + [3, 4, 5]    這種背後就是BINARY_ADD
l += [3, 4, 5]     這種背後就是INPLACE_ADD

+=實際上應該能算是一個增強版的+, 由於它比+多了一個寫回自己的功能.不過是否可以寫回自己, 仍是得看對象自身是否支持, 也就是說是否具有Py_NotImplemented標識, 是否支持sq_inplace_concat, 若是具有, 才能實現, 不然, 也就是和 + 效果同樣而已.

不只僅是這些,當混合使用可變類型和不可變類型的時候,你會有更加驚奇的發現:

>>> t = ([],)
>>> t[0] += [2, 3]
Traceback (most recent call last):
  File "<input>", line 1, in ?
TypeError: object doesn't support item assignment
>>> t
([2, 3],)

明顯的,元組不支持對其中元素的賦值——可是在對他使用+=後,元組裏的list確實改變了!緣由依然是+=就地改變list的值。可是元組的賦值不被容許,當異發生時,元組中的list已經被就地改變了。
這就是一個我我的以爲很是致命的陷阱。
解決方法:乾脆避免使用+=,或者僅僅在整數時使用它。

使用()建立tuple

>>> a=(1) # 錯誤姿式
>>> type(a)
<type 'int'>

>>> a=(1,) # 正確姿式
>>> type(a)
<type 'tuple'>

Python的list循環遍歷中,刪除數據的正確方法

通用的解決方案:

num_list = [1, 2, 3, 4, 5, 2, 2, 4]

1. 倒序循環遍歷

for i in range(len(num_list) - 1, -1, -1):  # 講究
    if num_list[i] == 2:
        num_list.pop(i)
print(num_list)

2. 遍歷拷貝的list,操做原始的list。對於過大的list,拷貝後可能很佔內存,能夠用倒序遍歷的方法來實現。

for item in num_list[:]:    # 保證能夠把num_list從頭遍歷到尾
    if item == 2:
        num_list.remove(item) # 從頭刪除遇到的第一個item
print(num_list)


3. 對原來的列表作過濾,生成一個新的列表(假設determine(x)爲判斷條件的函數):

list = [x for x in list if not determine(x)]

4. 在原來列表上作切片,僅保留須要的元素

list[:] = [x for x in list if not determine(x)]

5. python2.x ifilterfalse()方法

from itertools import ifilterfalse()
list[:] = ifilterfalse(determine, list)

6. Python3 filterfalse()方法

from itertools import filterfalse
list[:] = filterfalse(determine, list)

方法5,6對列表的修改會反應到其餘對此列表的引用上。

做用域解析是基於LEGB規則,分別是Local、Enclosing、Global、Built-in

函數內定義的局部變量必須global申明才能使用全局變量

def local_var_err():
    b += [3]  # UnboundLocalError: local variable 'b' referenced before assignment
    b = b + [2]  # UnboundLocalError: local variable 'b' referenced before assignment

不遍歷狀況下迭代器與生成器的性能比較

In [109]: %timeit -n100 a = (i for i in range(100000))
100 loops, best of 3: 659 µs per loop

In [110]: %timeit -n100 b = [i for i in range(100000)]
100 loops, best of 3: 2.68 ms per loop

遍歷狀況下迭代器與生成器的性能比較

In [112]: %timeit -n100 for x in (i for i in range(100000)):pass
100 loops, best of 3: 4.23 ms per loop

In [113]: %timeit -n100 for x in [i for i in range(100000)]:pass
100 loops, best of 3: 3.49 ms per loop

空間換時間

儘可能使用局部變量

# -*- coding:utf-8 -*-
import timeit

test_dict = {}

class dome(object):
    def test_class(self):
        num = 100
        self.test_dict = {}        # 爲了公平,每次執行都一樣初始化新的 {}
        for i in range(num):
            self.test_dict[i] = i

    def test_local(self):
        num = 100
        test_dict = {}             # 爲了公平,每次執行都一樣初始化新的 {}
        for i in range(num):
            test_dict[i] = i
        self.test_dict = test_dict

    def test_global(self):
        num = 100
        global test_dict
        test_dict = {}              # 爲了公平,每次執行都一樣初始化新的 {}
        for i in range(num):
            test_dict[i] = i

s = dome()

print(timeit.timeit(stmt=s.test_class))    # 9.75976037823
print(timeit.timeit(stmt=s.test_local))    # 7.17526431985
print(timeit.timeit(stmt=s.test_global))   # 7.57540534177

"""
1. 訪問局部變量速度要快不少
2. 循環以外能作的事不要放在循環內
在一些會頻繁操做 類/實例屬性 的狀況下,應該是先把 屬性 取出來存到 局部變量,而後用 局部變量 來完成操做。最後視狀況把變更更新到 屬性 上。
"""

拼接字符串列表時使用join

a=list(str(range(1000)))

In [126]: %%timeit
s=""
for x in a:
    s+=x
   .....: 
1000 loops, best of 3: 304 µs per loop

In [127]: %%timeit
   .....: s="".join(a)
   .....: 
10000 loops, best of 3: 59.3 µs per loop

參考博客 https://blog.csdn.net/xdhstc/article/details/51719892

if is True 對比 if == True,列表推導。

# -*- coding:utf-8 -*-
import timeit

def test_1():
    a = [True] * 100
    s = []
    for i in a:
        if i == True:
            s.append(i)
    return s


def test_2():
    a = [True] * 100
    return [i for i in a if i is True]


def test_3():
    a = [True] * 100
    return [i for i in a if i == True]


def test_4():
    a = [True] * 100
    return [i for i in a if i]


print(timeit.timeit(stmt=test_1))  # 11.5888194259
print(timeit.timeit(stmt=test_2))  # 6.00562291202
print(timeit.timeit(stmt=test_3))  # 7.15504198257
print(timeit.timeit(stmt=test_4))  # 4.29275713242

使用**而不是pow

In [145]: %timeit -n100000 c = pow(2,20)
100000 loops, best of 3: 89.3 ns per loop

In [146]: %timeit -n100000 c = 2**20
100000 loops, best of 3: 22.2 ns per loop

帶有條件判斷的嵌套for循環時儘可能分析條件減小循環次數

# -*- coding:utf-8 -*-
import timeit


def test1():
    s = []
    for z in range(10):
        for y in range(100):
            for x in range(1000):
                if x > 100 and y > 50 and z > 5:
                    return s
                s.append((x, y, z))



def test2():
    s = []
    for x in range(1000):
        for y in range(100):
            for z in range(10):
                if x > 100 and y > 50 and z > 5:
                    return s
                s.append((x, y, z))



print(timeit.timeit(stmt=test1, number=100))    # 14.1777687741
print(timeit.timeit(stmt=test2, number=100))    # 2.03417086749
print(sorted(test1()) == sorted(test2()))       # False
print(len(test1()))                             # 651101
print(len(test2()))                             # 101516
相關文章
相關標籤/搜索