摘要:流暢的中有很多奇技淫巧,整本書(shū)都在強(qiáng)調(diào)如何最大限度地利用標(biāo)準(zhǔn)庫(kù)。常見(jiàn)的扁平序列包括,,等。數(shù)組支持所有跟可變序列有關(guān)的操作,包括和。和用于指定列表的區(qū)間,默認(rèn)是使用整個(gè)列表。但是元組的賦值不被允許,當(dāng)異發(fā)生時(shí)
流暢的python中有很多奇技淫巧,整本書(shū)都在強(qiáng)調(diào)如何最大限度地利用Python 標(biāo)準(zhǔn)庫(kù)。介紹了很多python的不常用的數(shù)據(jù)類(lèi)型、操作、庫(kù)等,對(duì)于入門(mén)python后想要提升對(duì)python的認(rèn)識(shí)應(yīng)該有幫助。目前讀一遍記錄了一些有共鳴的操作:
Python內(nèi)置序列類(lèi)型的主要分類(lèi):按可存放的元素類(lèi)型分為:容器序列和扁平序列
容器序列,就是什么都能作為元素往里放,包括另一個(gè)序列。需要注意的是,如果元素是序列類(lèi)型,那么存放的往往是引用,需要小心。
常見(jiàn)的容器序列包括:list,tuple,array.array,collections.deque等。
扁平序列,存放的都是原子級(jí)元素,此時(shí)存放的是值而不會(huì)是引用。
常見(jiàn)的扁平序列包括:str,bytes,bytearray, memoryview, array.array等。
按序列能否被修改分為:可變序列與不可變序列
可變序列:可以進(jìn)行增、刪、改等操作的序列,包括list, bytearray, array.array, collections.deque, memoryview等。
不可變序列:不可進(jìn)行上述操作的序列,包括tuple, str, bytes等。
字典的變種標(biāo)準(zhǔn)庫(kù)里collections模塊中提供了很多與字典類(lèi)型相似的變種。
OrderDict: 這個(gè)類(lèi)型在添加鍵的時(shí)候,會(huì)保存順序,因此鍵的迭代順序總是一致的
ChainMap: 該類(lèi)型可以容納數(shù)個(gè)不同的映射對(duì)像,在進(jìn)行鍵的查找時(shí),這些對(duì)象會(huì)被當(dāng)做一個(gè)整體逐個(gè)查找,直到鍵被找到為止
Counter: 這個(gè)映射類(lèi)型會(huì)給鍵準(zhǔn)備一個(gè)整數(shù)技術(shù)器,每次更行一個(gè)鍵的時(shí)候都會(huì)增加這個(gè)計(jì)數(shù)器,所以這個(gè)類(lèi)型可以用來(lái)給散列表對(duì)象計(jì)數(shù),或者當(dāng)成多重集來(lái)用。
UserDict: 這個(gè)類(lèi)其實(shí)就是把標(biāo)準(zhǔn)的dict用Python又寫(xiě)了一遍。一般用來(lái)給程序員想要通過(guò)繼承dict創(chuàng)建自己的dict時(shí),代替dict使用的。主要是因?yàn)橹苯永^承原生dict會(huì)出現(xiàn)bug。
defaultdict:處理找不到的鍵的一個(gè)選擇
當(dāng)某個(gè)鍵不在映射里, 我們也希望也能得到一個(gè)默認(rèn)值. 這就是 defaultdict , 它是 dict 的子類(lèi), 并實(shí)現(xiàn)了 missing 方法.
鍵必須是可散列的: 一個(gè)可散列的對(duì)象必須滿(mǎn)足以下要求。 (1) 支持 hash() 函數(shù),并且通過(guò) __hash__() 方法所得到的散列值是不變的。 (2) 支持通過(guò) __eq__() 方法來(lái)檢測(cè)相等性。 (3) 若 a == b 為真,則 hash(a) == hash(b) 也為真。 所有由用戶(hù)自定義的對(duì)象默認(rèn)都是可散列的,因?yàn)樗鼈兊纳⒘兄涤?id() 來(lái)獲取,而 且它們都是不相等的。 字典在內(nèi)存上開(kāi)銷(xiāo)很大(用內(nèi)存換效率)。 元組取代字典就能節(jié)省空間的原因有兩個(gè): (1) 避免了散列表所耗費(fèi)的空間, (2) 無(wú)需把記錄中字段的名字在每個(gè)元素里都存一遍。 鍵的查詢(xún)很快 鍵的次序取決于添加順序 往字典里添加新鍵可能會(huì)改變已有鍵的順序set的實(shí)現(xiàn)以及導(dǎo)致的結(jié)果
結(jié)合的元素必須是可散列的 集合和消耗內(nèi)存 可以很高效的判斷元素是否存在于某個(gè)集合 元素的次序取決于被添加到集合里的順序 往集合里添加元素,可能會(huì)改變集合里已有的元素次序collections.namedtuple 可以用來(lái)構(gòu)建一個(gè)帶字段名的元組和一個(gè)有名字的類(lèi)
創(chuàng)建一個(gè)具名元組需要兩個(gè)參數(shù),一個(gè)是類(lèi)名,另一個(gè)是類(lèi)的各個(gè)字段的名字。后者
可以是由數(shù)個(gè)字符串組成的可迭代對(duì)象,或者是由空格分隔開(kāi)的字段名組成的字符串。
>>> 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))當(dāng)列表不是首選時(shí)
如果我們需要一個(gè)只包含數(shù)字的列表,那么 array.array 比 list 更高效。數(shù)組支持所
有跟可變序列有關(guān)的操作,包括 .pop、.insert 和 .extend。另外,數(shù)組還提供從文件
讀取和存入文件的更快的方法,如 .frombytes 和 .tofile。
set 專(zhuān)為檢查元素是否存在做過(guò)優(yōu)化
memoryview 是一個(gè)內(nèi)置類(lèi),它能讓用戶(hù)在不復(fù)制內(nèi)容的情況下操作同一個(gè)數(shù)組的不同切
片。
使用NumPy和SciPy提供的高階數(shù)組和矩陣操作
使用雙向隊(duì)列和其他形式的隊(duì)列(collections.deque 雙向隊(duì)列類(lèi)、queue類(lèi)中的 Queue、LifoQueue和PriorityQueue、multiprocessing. Queue、heapq可以把可變序列當(dāng)作堆隊(duì)列或者優(yōu)先隊(duì)列來(lái)使用)
Python 格式化輸出在進(jìn)行格式化輸出時(shí),%r 與 %s 的區(qū)別就好比 repr() 函數(shù)處理對(duì)象與 str() 函數(shù)處理對(duì)象的差別。
%s -> str(),比較智能;
%r -> repr(),處理較為簡(jiǎn)單和直接; 處理一些簡(jiǎn)單對(duì)象時(shí),二者幾乎沒(méi)有差別.
本文重點(diǎn)列舉一些二者的差異化用法:
處理字符串時(shí)
>> s = "world" >> print("hello %s"%s) hello world >> print("hello %r"%s) hello "world" >> str(s) "world" >> repr(s) ""world"" 2. datetime 庫(kù)中的 datetime 對(duì)象 >> 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"反匯編函數(shù) python opcode
Python dis 模塊支持對(duì)Python代碼進(jìn)行反匯編, 生成字節(jié)碼指令。
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的內(nèi)置類(lèi),如果要用memoryview 去引用一個(gè)object, 那么這個(gè)object 必須支持buffer protocol, python3 中原生(built-in) 支持buffer protocol的obj有bytes和bytearray,memoryview可以使用不同的方式讀取和操作同一塊內(nèi)存,并且原有的內(nèi)存字節(jié)不會(huì)隨意移動(dòng)。類(lèi)似于C中的強(qiáng)轉(zhuǎn),好處是不會(huì)有內(nèi)存拷貝。
例如,使用memoryview修改一個(gè)短整型有符號(hào)整數(shù)數(shù)組的數(shù)據(jù)。
from array import array from random import random numbers = array("h", [-2, -1, 0, 1, 2]) #signed short memv = memoryview(numbers) #5個(gè)短整型有符號(hào)整數(shù)的數(shù)組創(chuàng)建一個(gè)memoryview print (len(memv)) #打印長(zhǎng)度 print (memv.tolist()) #轉(zhuǎn)換成列表形式 memv_oct = memv.cast("B") #內(nèi)存共享 轉(zhuǎn)換成無(wú)符號(hào)字符類(lèi)型 print (memv_oct.tolist()) memv_oct[5] = 4 #把位置5的字節(jié)賦值成4 print (numbers) #因?yàn)槲覀儼颜?2 個(gè)字節(jié)的整數(shù)的高位字節(jié)改成了 4,所以這個(gè)有符號(hào)整數(shù)的值就變成了 1024 輸出如下: 5 #數(shù)組長(zhǎng)度 [-2, -1, 0, 1, 2] #列表形式顯示 [254, 255, 255, 255, 0, 0, 1, 0, 2, 0]#長(zhǎng)度擴(kuò)大一倍 轉(zhuǎn)換為無(wú)符號(hào)字符類(lèi)型 array("h", [-2, -1, 1024, 1, 2]) #原來(lái)的數(shù)組被修改
bytearray是可變(mutable)的字節(jié)序列,相對(duì)于Python2中的str,但str是不可變(immutable)的。
在Python3中由于str默認(rèn)是unicode編碼,所以只有通過(guò)bytearray才能按字節(jié)訪問(wèn)。
下面兩種行為的對(duì)比:
簡(jiǎn)單點(diǎn)就是,str和bytearray的切片操作會(huì)產(chǎn)生新的切片str和bytearry并拷貝數(shù)據(jù),使用memoryview之后不會(huì)。
python2中的例子
>> a = "aaaaaa" >> b = a[:2] # 會(huì)產(chǎn)生新的字符串 >> a = bytearray("aaaaaa") >> b = a[:2] # 會(huì)產(chǎn)生新的bytearray >> b[:2] = "bb" # 對(duì)b的改動(dòng)不影響a >> a bytearray(b"aaaaaa") >> b bytearray(b"bb")
>> a = "aaaaaa" >> ma = memoryview(a) >> ma.readonly # 只讀的memoryview True >> mb = ma[:2] # 不會(huì)產(chǎn)生新的字符串 >> a = bytearray("aaaaaa") >> ma = memoryview(a) >> ma.readonly # 可寫(xiě)的memoryview False >> mb = ma[:2] # 不會(huì)會(huì)產(chǎn)生新的bytearray >> mb[:2] = "bb" # 對(duì)mb的改動(dòng)就是對(duì)ma的改動(dòng) >> mb.tobytes() "bb" >> ma.tobytes() "bbaaaa"
Python 中有各種各樣可調(diào)用的類(lèi)型,因此判斷置的 callable() 函數(shù):
>>> abs, str, 13 (, , 13) >>> [callable(obj) for obj in (abs, str, 13)] [True, True, False]
>>> 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 → 數(shù)字零,到行頭
$ → 到本行行尾
a → 在光標(biāo)后插入
o → 在當(dāng)前行后插入一個(gè)新行
O → 在當(dāng)前行前插入一個(gè)新行
cw → 替換從光標(biāo)所在位置后到一個(gè)單詞結(jié)尾的字符
. → (小數(shù)點(diǎn)) 可以重復(fù)上一次的命令
NG → 到第 N 行 (注意命令中的G是大寫(xiě)的,另我一般使用 : N 到第N行,如 :137 到第137行)
gg → 到第一行。(相當(dāng)于1G,或 :1)
G → 到最后一行。
在 Insert 模式下,你可以輸入一個(gè)詞的開(kāi)頭,然后按
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跟運(yùn)算符無(wú)關(guān)的特殊方法
類(lèi)別 方法名 字符串 / 字節(jié)序列表示形式 __repr__、__str__、__format__、__bytes__ 數(shù)值轉(zhuǎn)換 __abs__、__bool__、__complex__、__int__、__float__、__hash__、__index__ 集合模擬 __len__、__getitem__、__setitem__、__delitem__、__contains__ 迭代枚舉 __iter__、__reversed__、__next__ 可調(diào)用模擬 __call__ 上下文管理 __enter__、__exit__ 實(shí)例創(chuàng)建和銷(xiāo)毀 __new__、__init__、__del__ 屬性管理 __getattr__、__getattribute__、__setattr__、__delattr__、__dir__ 屬性描述符 __get__、__set__、__delete__ 跟類(lèi)相關(guān)的服務(wù) __prepare__、__instancecheck__、__subclasscheck__Bisect模塊管理有序的序列
bisect.bisect_left(a,x, lo=0, hi=len(a)) : 查找在有序列表 a 中插入 x 的index。lo 和 hi 用于指定列表的區(qū)間,默認(rèn)是使用整個(gè)列表。如果 x 已經(jīng)存在,在其左邊插入。返回值為 index。 bisect.bisect_right(a,x, lo=0, hi=len(a)) bisect.bisect(a, x,lo=0, hi=len(a)) : 這2個(gè)函數(shù)和 bisect_left 類(lèi)似,但如果 x 已經(jīng)存在,在其右邊插入。 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 類(lèi)似,但如果 x 已經(jīng)存在,在其右邊插入。 Bisect 模塊提供的函數(shù)可以分兩類(lèi): bisect* 只用于查找 index, 不進(jìn)行實(shí)際的插入;而 insort* 則用于實(shí)際插入。當(dāng)list不是最優(yōu)選擇時(shí),dict是python的核心類(lèi)型,但它是以空間換時(shí)間的結(jié)果,比較占內(nèi)存,tuple是dict結(jié)構(gòu)比較好的替代,set用來(lái)做是否包含和去重很合適。
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 == floatsPython_內(nèi)置四種隊(duì)列
from queue import Queue #LILO隊(duì)列 q = Queue() #創(chuàng)建隊(duì)列對(duì)象 q.put(0) #在隊(duì)列尾部插入元素 q.put(1) q.put(2) print("LILO隊(duì)列",q.queue) #查看隊(duì)列中的所有元素 print(q.get()) #返回并刪除隊(duì)列頭部元素 print(q.queue) from queue import LifoQueue #LIFO隊(duì)列 lifoQueue = LifoQueue() lifoQueue.put(1) lifoQueue.put(2) lifoQueue.put(3) print("LIFO隊(duì)列",lifoQueue.queue) lifoQueue.get() #返回并刪除隊(duì)列尾部元素 lifoQueue.get() print(lifoQueue.queue) from queue import PriorityQueue #優(yōu)先隊(duì)列 priorityQueue = PriorityQueue() #創(chuàng)建優(yōu)先隊(duì)列對(duì)象 priorityQueue.put(3) #插入元素 priorityQueue.put(78) #插入元素 priorityQueue.put(100) #插入元素 print(priorityQueue.queue) #查看優(yōu)先級(jí)隊(duì)列中的所有元素 priorityQueue.put(1) #插入元素 priorityQueue.put(2) #插入元素 print("優(yōu)先級(jí)隊(duì)列:",priorityQueue.queue) #查看優(yōu)先級(jí)隊(duì)列中的所有元素 priorityQueue.get() #返回并刪除優(yōu)先級(jí)最低的元素 print("刪除后剩余元素",priorityQueue.queue) priorityQueue.get() #返回并刪除優(yōu)先級(jí)最低的元素 print("刪除后剩余元素",priorityQueue.queue) #刪除后剩余元素 priorityQueue.get() #返回并刪除優(yōu)先級(jí)最低的元素 print("刪除后剩余元素",priorityQueue.queue) #刪除后剩余元素 priorityQueue.get() #返回并刪除優(yōu)先級(jí)最低的元素 print("刪除后剩余元素",priorityQueue.queue) #刪除后剩余元素 priorityQueue.get() #返回并刪除優(yōu)先級(jí)最低的元素 print("全部被刪除后:",priorityQueue.queue) #查看優(yōu)先級(jí)隊(duì)列中的所有元素 from collections import deque #雙端隊(duì)列 dequeQueue = deque(["Eric","John","Smith"]) print(dequeQueue) dequeQueue.append("Tom") #在右側(cè)插入新元素 dequeQueue.appendleft("Terry") #在左側(cè)插入新元素 print(dequeQueue) dequeQueue.rotate(2) #循環(huán)右移2次 print("循環(huán)右移2次后的隊(duì)列",dequeQueue) dequeQueue.popleft() #返回并刪除隊(duì)列最左端元素 print("刪除最左端元素后的隊(duì)列:",dequeQueue) dequeQueue.pop() #返回并刪除隊(duì)列最右端元素 print("刪除最右端元素后的隊(duì)列:",dequeQueue) 以上隊(duì)列在多線程中可以使用的且線程安全,但在多進(jìn)程中都不能用于通信。在多進(jìn)程中,需要這樣使用: 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關(guān)鍵字
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 # 錯(cuò)誤:NameError: global name "a" is not defined aaaa()
動(dòng)態(tài)地進(jìn)行變量賦值時(shí),locals() 看到的, 的確是函數(shù)的局部命名空間的內(nèi)容, 但是它本身不能代表局部命名空間, 這就好像一個(gè)代理, 它收集了A, B, C的東西, 展示給我看, 但是我卻不能簡(jiǎn)單的通過(guò)改變這個(gè)代理, 來(lái)改變A, B, C真正擁有的東西!
這也就是為什么, 當(dāng)我們通過(guò)locals()[i] = 1的方式去動(dòng)態(tài)賦值時(shí), print a卻觸發(fā)了NameError異常, 而相反的, globals()確實(shí)真正的全局命名空間,
所以一般會(huì)說(shuō)locals() 只讀, globals() 可讀可寫(xiě)。
對(duì)于一般不可變類(lèi)型的變量來(lái)說(shuō)這兩個(gè)方法沒(méi)啥區(qū)別,但對(duì)于可變類(lèi)型如list(列表),dict(字典)就有區(qū)別了,x += y 就地改變了list的值,而x = x + y創(chuàng)建了一個(gè)新的list并重新將x綁定上去,通過(guò)id(x)就可以看出。
l = l + [3, 4, 5] 這種背后就是BINARY_ADD l += [3, 4, 5] 這種背后就是INPLACE_ADD
+=實(shí)際上應(yīng)該能算是一個(gè)加強(qiáng)版的+, 因?yàn)樗?多了一個(gè)寫(xiě)回本身的功能.不過(guò)是否能夠?qū)懟乇旧? 還是得看對(duì)象自身是否支持, 也就是說(shuō)是否具備Py_NotImplemented標(biāo)識(shí), 是否支持sq_inplace_concat, 如果具備, 才能實(shí)現(xiàn), 否則, 也就是和 + 效果一樣而已.
不僅僅是這些,當(dāng)混合使用可變類(lèi)型和不可變類(lèi)型的時(shí)候,你會(huì)有更加驚奇的發(fā)現(xiàn):
>>> t = ([],) >>> t[0] += [2, 3] Traceback (most recent call last): File "", line 1, in ? TypeError: object doesn"t support item assignment >>> t ([2, 3],)
明顯的,元組不支持對(duì)其中元素的賦值——但是在對(duì)他使用+=后,元組里的list確實(shí)改變了!原因依然是+=就地改變list的值。但是元組的賦值不被允許,當(dāng)異發(fā)生時(shí),元組中的list已經(jīng)被就地改變了。
這就是一個(gè)我個(gè)人覺(jué)得非常致命的陷阱。
解決方法:干脆避免使用+=,或者僅僅在整數(shù)時(shí)使用它。
>>> a=(1) # 錯(cuò)誤姿勢(shì) >>> type(a)Python的list循環(huán)遍歷中,刪除數(shù)據(jù)的正確方法>>> a=(1,) # 正確姿勢(shì) >>> type(a)
通用的解決方案:
num_list = [1, 2, 3, 4, 5, 2, 2, 4] 1. 倒序循環(huán)遍歷 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。對(duì)于過(guò)大的list,拷貝后可能很占內(nèi)存,可以用倒序遍歷的方法來(lái)實(shí)現(xiàn)。 for item in num_list[:]: # 保證可以把num_list從頭遍歷到尾 if item == 2: num_list.remove(item) # 從頭刪除遇到的第一個(gè)item print(num_list) 3. 對(duì)原來(lái)的列表做過(guò)濾,生成一個(gè)新的列表(假設(shè)determine(x)為判斷條件的函數(shù)): list = [x for x in list if not determine(x)] 4. 在原來(lái)列表上做切片,僅保留需要的元素 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對(duì)列表的修改會(huì)反應(yīng)到其他對(duì)此列表的引用上。作用域解析是基于LEGB規(guī)則,分別是Local、Enclosing、Global、Built-in 函數(shù)內(nèi)定義的局部變量必須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
空間換時(shí)間
盡量使用局部變量# -*- coding:utf-8 -*- import timeit test_dict = {} class dome(object): def test_class(self): num = 100 self.test_dict = {} # 為了公平,每次執(zhí)行都同樣初始化新的 {} for i in range(num): self.test_dict[i] = i def test_local(self): num = 100 test_dict = {} # 為了公平,每次執(zhí)行都同樣初始化新的 {} 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 = {} # 為了公平,每次執(zhí)行都同樣初始化新的 {} 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. 訪問(wèn)局部變量速度要快很多 2. 循環(huán)之外能做的事不要放在循環(huán)內(nèi) 在一些會(huì)頻繁操作 類(lèi)/實(shí)例屬性 的情況下,應(yīng)該是先把 屬性 取出來(lái)存到 局部變量,然后用 局部變量 來(lái)完成操作。最后視情況把變動(dòng)更新到 屬性 上。 """拼接字符串列表時(shí)使用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/51719892if is True 對(duì)比 if == True,列表推導(dǎo)。
# -*- 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循環(huán)時(shí)盡量分析條件減少循環(huán)次數(shù)
# -*- 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
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/42472.html
摘要:于是打算看一下流暢的。第一章是講數(shù)據(jù)模型,主要是的魔術(shù)方法特殊方法,它們以雙下劃線開(kāi)頭和結(jié)束,能讓我們自己寫(xiě)的類(lèi)擁有類(lèi)似內(nèi)置對(duì)象那樣的屬性和方法。第三個(gè)出場(chǎng)的的是,把對(duì)象用字符串的形式表示出來(lái)。第六個(gè)是,用于實(shí)現(xiàn)自己定義的布爾值。 接觸 Python 有一段時(shí)間了,但是到現(xiàn)在也沒(méi)怎么用 Python 寫(xiě)過(guò)一些有用的東西?;A(chǔ)雖然還行,但更深入的就不怎么了解了。于是打算看一下《流暢的 P...
摘要:不同編碼器編碼的相同的字符,最終的字節(jié)大小可能會(huì)不同。對(duì)于和,是由于對(duì)應(yīng)編碼不能處理字符串字節(jié)導(dǎo)致的。在另外兩個(gè)規(guī)范化形式和的首字母縮略詞中,字母表示兼容性。最后是雙模,同一函數(shù)能接受字符串和字節(jié)進(jìn)行操作。 對(duì)于字符串,我們接觸得挺多的。而編碼問(wèn)題,也不時(shí)令人頭疼的。 由于一開(kāi)始接觸的就是 Python3,所以一些在 Python2 上的編碼上的坑我沒(méi)遇到,甚至在 Python3 上都...
摘要:今天深入接觸了中的函數(shù),發(fā)現(xiàn)函數(shù)比我想象的要高深。介紹的幾個(gè)高階函數(shù)有內(nèi)置的和函數(shù),模塊中的??烧{(diào)用對(duì)象即能被調(diào)用運(yùn)算符應(yīng)用的對(duì)象,可使用內(nèi)置的函數(shù)檢測(cè)。函數(shù)的三個(gè)屬性和放置了函數(shù)對(duì)象參數(shù)的一些信息。 今天深入接觸了 Python 中的函數(shù),發(fā)現(xiàn)函數(shù)比我想象的要高深。 Python 中萬(wàn)物皆對(duì)象,這一章就介紹了函數(shù)作為對(duì)象的一些屬性。首先是測(cè)試所有對(duì)象共有的屬性__doc__,可以看到...
摘要:第一章數(shù)據(jù)類(lèi)型隱式方法利用快速生成類(lèi)方法方法通過(guò)下標(biāo)找元素自動(dòng)支持切片操作可迭代方法與如果是一個(gè)自定義類(lèi)的對(duì)象,那么會(huì)自己去調(diào)用其中由你實(shí)現(xiàn)的方法。若返回,則會(huì)返回否則返回。一個(gè)對(duì)象沒(méi)有函數(shù),解釋器會(huì)用作為替代。 第一章 python數(shù)據(jù)類(lèi)型 1 隱式方法 利用collections.namedtuple 快速生成類(lèi) import collections Card = collec...
摘要:第一章數(shù)據(jù)類(lèi)型隱式方法利用快速生成字典方法方法通過(guò)下標(biāo)找元素自動(dòng)支持切片操作可迭代方法與如果是一個(gè)自定義類(lèi)的對(duì)象,那么會(huì)自己去調(diào)用其中由你實(shí)現(xiàn)的方法。若返回,則會(huì)返回否則返回。一個(gè)對(duì)象沒(méi)有函數(shù),解釋器會(huì)用作為替代。 第一章 python數(shù)據(jù)類(lèi)型 1 隱式方法 利用collections.namedtuple 快速生成字典 import collections Card = coll...
閱讀 3070·2021-11-23 09:51
閱讀 1051·2021-09-02 15:21
閱讀 3017·2019-08-30 13:56
閱讀 1840·2019-08-29 14:12
閱讀 716·2019-08-29 13:53
閱讀 1677·2019-08-29 11:32
閱讀 1340·2019-08-29 11:25
閱讀 1504·2019-08-28 17:51