日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

流畅的Python之奇技淫巧(一)

發(fā)布時間:2023/12/20 python 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 流畅的Python之奇技淫巧(一) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

第1章 Python數(shù)據(jù)類型

1.3 特殊方法一覽

原文如下

Python 語言參考手冊中的“Data Model”(https://docs.python.org/3/reference/datamodel.html) 一章列出了 83 個特殊方法的名字,其中 47 個用于實現(xiàn)算術運算、位運算和比較操作。 表 1-1 和表 1-2 列出了這些方法的概況。

奇技淫巧之魔法方法的巧妙使用

注! 當交換兩個操作數(shù)的位置時,就會調用反向運算符( b * a 而不是 a * b )。增量賦值運算符則是一種把中綴運算符變成賦值運算的捷徑( a = a * b 就變成了 a *= b )。第 13 章會對這兩者作出詳細解釋。注意標準模板


第2章 序列構成的數(shù)組

2.1 內置序列類型概覽

Python 標準庫用 C 實現(xiàn)了豐富的序列類型,列舉如下。

  • 容器序列
    • list 、 tuple 和 collections.deque 這些序列能存放不同類型的數(shù)據(jù)。
  • 扁平序列
    • str 、 bytes 、 bytearray 、 memoryview 和 array.array ,這類序列只能容納一種類型。
  • 可變序列
    • list 、 bytearray 、 array.array 、 collections.deque 和 memoryview 。
  • 不可變序列
    • tuple 、 str 和 bytes 。

注! 容器序列存放的是它們所包含的任意類型的對象的引用,而扁平序列里存放的是而不是 引用。換句話說,扁平序列其實是一段連續(xù)的內存空間。由此可見扁平序列其實更加緊湊,但是它里面只能存放諸如字符、字節(jié)和數(shù)值這種基礎類型。 序列類型還能按照能否被修改來分類。

圖 2-1 顯示了可變序列( MutableSequence )不可變序列( Sequence )的差異,同時也
能看出前者從后者那里繼承了一些方法。雖然內置的序列類型并不是直接從 Sequence
MutableSequence 這兩個抽象基類(Abstract Base Class,ABC)繼承而來的,但是了解這
些基類可以幫助我們總結出那些完整的序列類型包含了哪些功能

2.2 列表推導和生成器表達式

2.2.1 列表推導和可讀性

Python2中列表推倒式會有變量泄露問題,而Python3中不存在的~

**列表推導不會再有變量泄漏的問題** Python 2.x 中,在列表推導中 for 關鍵詞之后的賦值操作可能會影響列表推導上下文中 的同名變量。像下面這個 Python 2.7 控制臺對話:Python 2.7.6 (default, Mar 22 2014, 22:59:38)[GCC 4.8.2] on linux2Type "help", "copyright", "credits" or "license" for more information.>>> x = 'my precious'>>> dummy = [x for x in 'ABC']>>> x'C' 如你所見, x 原本的值被取代了,但是這種情況在 Python 3 中是不會出現(xiàn)的。 列表推導、生成器表達式,以及同它們很相似的集合( set )推導和字典( dict )推 導,在 Python 3 中都有了自己的局部作用域,就像函數(shù)似的。表達式內部的變量和賦 值只在局部起作用,表達式的上下文里的同名變量還可以被正常引用,局部變量并不 會影響到它們。 這是 Python 3 代碼:>>> x = 'ABC'>>> dummy = [ord(x) for x in x]>>> x ?'ABC'>>> dummy ?[65, 66, 67]>>> ? x 的值被保留了。 ? 列表推導也創(chuàng)建了正確的列表。
2.2.3 笛卡兒積


奇技淫巧之列表推導式的巧妙使用

示例 2-4 使用列表推導計算笛卡兒積>>> colors = ['black', 'white'] >>> sizes = ['S', 'M', 'L'] >>> tshirts = [(color, size) for >>> tshirts [('black', 'S'), ('black', 'M'),('black', 'L'), ('white', 'S'),('white', 'M'), ('white', 'L')] >>> for color in colors: ? ... for size in sizes: ... print((color, size)) ... ('black', 'S') ('black', 'M') ('black', 'L') ('white', 'S') ('white', 'M') ('white', 'L') >>> tshirts = [(color, size) for size in sizes for color in colors]? >>> tshirts [('black', 'S'), ('white', 'S'),('black', 'M'), ('white', 'M'),('black', 'L'), ('white', 'L')] ? 這里得到的結果是先以顏色排列,再以尺碼排列。 ? 注意,這里兩個循環(huán)的嵌套關系和上面列表推導中 for 從句的先后順序一樣。 ? 如果想依照先尺碼后顏色的順序來排列,只需要調整從句的順序。我在這里插入了一個 換行符,這樣順序安排就更明顯了。 在第 1 章的示例 1-1 中,有下面這樣一段程序

注!生成器表達式即將[]換為()即可.

2.3.4 具名元組

collections.namedtuple 是一個工廠函數(shù),它可以用來構建一個帶字段名的元組和一個有名字的類——這個帶名字的類對調試程序有很大幫助。

注!用 namedtuple 構建的類的實例所消耗的內存跟元組是一樣的,因為字段名都被存在對應的類里面。這個實例跟普通的對象實例比起來也要小一些,因為Python 不會用 dict 來存放這些實例的屬性。

示例 2-9 定義和使用具名元組>>> from collections import namedtuple>>> City = namedtuple('City', 'name country population coordinates')?>>> tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))?>>> tokyoCity(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' ? 創(chuàng)建一個具名元組需要兩個參數(shù),一個是類名,另一個是類的各個字段的名字。后者可以是由數(shù)個字符串組成的可迭代對象,或者是由空格分隔開的字段名組成的字符串。 ? 存放在對應字段里的數(shù)據(jù)要以一串參數(shù)的形式傳入到構造函數(shù)中(注意,元組的構造函數(shù)卻只接受單一的可迭代對象)。 ? 你可以通過字段名或者位置來獲取一個字段的信息。 除了從普通元組那里繼承來的屬性之外,具名元組還有一些自己專有的屬性。示例 2-10 中就展示了幾個最有用的: _fields 類屬性、類方法 _make(iterable) 和實例方法 _asdict() 。 示例 2-10 具名元組的屬性和方法(接續(xù)前一個示例)>>> City._fields?('name', 'country', 'population', 'coordinates')>>> LatLong = namedtuple('LatLong', 'lat long')>>> delhi_data = ('Delhi NCR', 'IN', 21.935, LatLong(28.613889, 77.208889))>>> delhi = City._make(delhi_data)?>>> delhi._asdict()?OrderedDict([('name', 'Delhi NCR'), ('country', 'IN'), ('population',21.935), ('coordinates', LatLong(lat=28.613889, long=77.208889))])>>> for key, value in delhi._asdict().items():print(key + ':', value)name: Delhi NCRcountry: INpopulation: 21.935coordinates: LatLong(lat=28.613889, long=77.208889)>>> ? _fields 屬性是一個包含這個類所有字段名稱的元組。 ? 用 _make()通過接受一個可迭代對象來生成這個類的一個示例,它的做工跟City(*delhi_data) 是一樣的。 ? _asdict() 把具名元組以 collections.OrderedDict 的形式返回,我們可以利用它來把元組里的信息友好地呈現(xiàn)出來。
2.3.5 列表與元祖底層實現(xiàn)的魔法方法對比(作為不可變列表的元組)

2.4.3 多維切片和省略
  • 切片
    • []運算符里還可以使用以逗號分開的多個索引或者是切片,外部庫 NumPy 里就用到了這
      個特性,二維的 numpy.ndarray 就可以用 a[i, j] 這種形式來獲取,抑或是用 a[m:n, k:l]
      的方式來得到二維切片。稍后的示例 2-22 會展示這個用法。要正確處理這種[]運算符的
      話,對象的特殊方法 __getitem__ 和 __setitem__ 需要以元組的形式來接收 a[i, j] 中的索
      引。也就是說,如果要得到 a[i, j] 的值,Python 會調用 a.__getitem__((i, j))
  • 省略
    • 省略(ellipsis)的正確書寫方法是三個英語句號( ),而不是 Unicdoe 碼位 U+2026 表示的半個省略號(…)。省略在 Python 解析器眼里是一個符號,而實際上它是 Ellipsis 對象的別名,而 Ellipsis 對象是 ellipsis 類*的單一實例。 2 它可以當作切片規(guī)范的一部分,也可以用在函數(shù)的參數(shù)清單中,比如 f(a, …, z) ,或 a[i:…] 。在 NumPy 中, … 用作多維數(shù)組切片的快捷方式。如果 x 是四維數(shù)組,那么 x[i, …] 就是 x[i, :, :, :] 的縮寫*。如果想了解更多,請參見“Tentative NumPy Tutorial”(http://wiki.scipy.org/Tentative_NumPy_Tutorial)
2.4.4 給切片賦值
>>> l = list(range(10)) >>> l [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 創(chuàng)建出來的列表l>>> l[2:5] = [20, 30] # 1.給切片賦值>>> l [0, 1, 20, 30, 5, 6, 7, 8, 9]>>> del l[5:7] # 2.切片刪除>>> l [0, 1, 20, 30, 5, 8, 9] >>> l[3::2] = [11, 22] # 3.切片賦值>>> l [0, 1, 20, 11, 5, 22, 9] >>> l[2:5] = 100 ? # 錯誤類型展示Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can only assign an iterable >>> l[2:5] = [100] >>> l [0, 1, 100, 22, 9] ? 如果賦值的對象是一個切片,那么賦值語句的右側必須是個可迭代對象。即便只有單獨 一個值,也要把它轉換成可迭代的序列。

2.5 對序列使用 + 和 *

如果想要把一個序列復制幾份然后再拼接起來,更快捷的做法是把這個序列乘以一個整
數(shù)。同樣,這個操作會產(chǎn)生一個新序列

>>> l = [1, 2, 3] >>> l * 5 [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3] >>> 5 * 'abcd' 'abcdabcdabcdabcdabcd'

+ 和 * 都遵循這個規(guī)律,不修改原有的操作對象,而是構建一個全新的序列。

注! 注! 如果在 a * n 這個語句中,序列 a 里的元素是對其他可變對象的引用的話,你就需要格外注意了,因為這個式子的結果可能會出乎意料。比如,你想用my_list = [[]] * 3 來初始化一個由列表組成的列表,但是你得到的列表里包含的 3 個元素其實是 3 個引用,而且這3 個引用指向的都是同一個列表。這可能不是你想要的效果。

示例 2-12 一個包含 3 個列表的列表,嵌套的 3 個列表各自有 3 個元素來代表井字游戲的一行方塊>>> board = [['_'] * 3 for i in range(3)] ?>>> board[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]>>> board[1][2] = 'X' ?>>> board[['_', '_', '_'], ['_', '_', 'X'], ['_', '_', '_']] ? 建立一個包含 3 個列表的列表,被包含的 3 個列表各自有 3 個元素。打印出這個嵌套列表。 ? 把第 1 行第 2 列的元素標記為 X ,再打印出這個列表。 示例 2-13 展示了另一個方法,這個方法看上去是個誘人的捷徑,但實際上它是錯的。 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 示例 2-13 含有 3 個指向同一對象的引用的列表是毫無用處的>>> weird_board = [['_'] * 3] * 3 ?>>> weird_board[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]>>> weird_board[1][2] = 'O' ?>>> weird_board[['_', '_', 'O'], ['_', '_', 'O'], ['_', '_', 'O']] ? 外面的列表其實包含 3 個指向同一個列表的引用。當我們不做修改的時候,看起來都還好。 ? 一旦我們試圖標記第 1 行第 2 列的元素,就立馬暴露了列表內的 3 個引用指向同一個對象的事實。

2.6 序列的增量賦值

  • 增量賦值運算符 += 和 *=

    • += 背后的特殊方法是 __iadd__ (用于“就地加法”)。
      但是如果一個類沒有實現(xiàn)這個方法的話,Python 會退一步調用 __add__

    • eg:–> a += b 如果a 實現(xiàn) 了 __iadd__ 方法,就會調用這個方法。同時對可變序列(例如list、bytearray和array.array)來說, a 會就地改動,就像調用了 a.extend(b) 一樣了:首先計算 a + b ,得到一個新的對象,然后賦值給 a。也就是說,在這個表達式中,變量名會不會被關聯(lián)到新的對象,完全取決于這個類型有沒有實現(xiàn) __iadd__ 這個方法。

    • 類似的*=相對應的是 __imul__和__mul__

接下來有個小例子,展示的是 *= 在可變和不可變序列上的作用:>>> l = [1, 2, 3]>>> id(l)4311953800 # ? 剛開始時列表的ID。>>> l *= 2>>> l[1, 2, 3, 1, 2, 3]>>> id(l)4311953800 # ? 運用增量乘法后,列表的 ID 沒變,新元素追加到列表上。>>> t = (1, 2, 3)>>> id(t)4312681568 # ? 元組最開始的 ID。>>> t *= 2>>> id(t)4301348296 # ? 運用增量乘法后,新的元組被創(chuàng)建。

注!不可變序列進行重復拼接操作的話,效率會很低,因為每次都有一個新對象,而解釋器需要把原來對象中的元素先復制到新的對象里,然后再追加新的元素。(str 是一個例外,因為對字符串做 += 實在是太普遍了,所以 CPython 對它做了優(yōu)化。為 str 初始化內存的時候,程序會為它留出額外的可擴展空間,因此進行增量操作的時候,并不會涉及復制原有字符串到新位置這類操作。)

**一個關于 += 的謎題** 讀完下面的代碼,然后回答這個問題: 示例 2-14 中的兩個表達式到底會產(chǎn)生什么結果? 回答之前不要用控制臺去運行這兩個式子。示例 2-14 一個謎題>>> t = (1, 2, [30, 40])>>> t[2] += [50, 60] 到底會發(fā)生下面 4 種情況中的哪一種?a. t 變成 (1, 2, [30, 40, 50, 60]) 。b. 因為 tuple 不支持對它的元素賦值,所以會拋出 TypeError 異常。c. 以上兩個都不是。d. a 和 b 都是對的。哈哈哈哈~~~~此處插入裘千仞老前輩的棗核之笑^(* ̄(oo) ̄)^ 正確答案為 d! 你答對了嘛 詳情見示例 2-15示例 2-15 沒人料到的結果: t[2] 被改動了,但是也有異常拋出?>>> t = (1, 2, [30, 40])>>> t[2] += [50, 60]Traceback (most recent call last):File "<stdin>", line 1, in <module>TypeError: 'tuple' object does not support item assignment>>> t(1, 2, [30, 40, 50, 60]) ?有讀者提出,如果寫成 t[2].extend([50, 60]) 就能避免這個異常。確實是這樣,但這個例子是為了展示這種奇怪的現(xiàn)象而專門寫的。有興趣的,或者不理解其中的奧秘的,Python Tutor(http://www.pythontutor.com是一個對 Python 運行原理進行可視化分析的工具)進行分析拆解.

奇技淫巧之字節(jié)碼查看代碼執(zhí)行的巧妙使用

示例 2-16 s[a] = b 背后的字節(jié)碼>>> import dis>>> dis.dis('s[a] += b')1 0 LOAD_NAME 0 (s)2 LOAD_NAME 1 (a)4 DUP_TOP_TWO6 BINARY_SUBSCR ?8 LOAD_NAME 2 (b)10 INPLACE_ADD ?12 ROT_THREE14 STORE_SUBSCR ?16 LOAD_CONST 0 (None)18 RETURN_VALUE>>> ? 將 s[a] 的值存入 TOS (Top Of Stack,棧的頂端)。 ? 計算 TOS += b 。這一步能夠完成,是因為 TOS 指向的是一個可變對象(也就是示例 2-15里的列表)。 ? s[a] = TOS 賦值。這一步失敗,是因為 s 是不可變的元組(示例 2-15 中的元組 t )。至此我得到3粒精華。? 不要把可變對象放在元組里面。? 增量賦值不是一個原子操作。我們剛才也看到了,它雖然拋出了異常,但還是完成了操作。? 查看 Python 的字節(jié)碼并不難,而且它對我們了解代碼背后的運行機制很有幫助。

2.7 list.sort() 方法和內置函數(shù) sorted(list)

>>> a = [5, 2, 1, 3, 4, 0] # 定義列表a >>> xx = a.sort() # 對a進行排序 >>> a # 查看a的值 [0, 1, 2, 3, 4, 5] # WC?被改變了 >>> xx # 查看返回值 >>> print(xx) # 返回值為None None ----------- 華麗的分割線之sorted() ---------------- >>> b = [3, 5, 1, 7, 6, 8] # 定義列表b >>> yy = sorted(b) # 對b進行排序 >>> b # 查看b的值 [3, 5, 1, 7, 6, 8] # 嗯哼~ 小伙子立場堅定 >>> yy # 查看返回值, 呦~ 還創(chuàng)造了下一代 [1, 3, 5, 6, 7, 8] >>>

關于list.sort() 和sorted(list)都有的參數(shù)

  • reverse
    • True為被排序的序列里的元素會以降序輸出,默認值是 False 。
  • key
    • eg:–> key=str.lower來實現(xiàn)忽略大小寫的排序,或 key=len 進行基于字符串長度的排序。
下面通過這個小例子來看看這兩個函數(shù)和它們的關鍵字參數(shù):>>> fruits = ['grape', 'raspberry', 'apple', 'banana']>>> sorted(fruits)['apple', 'banana', 'grape', 'raspberry'] ?>>> fruits['grape', 'raspberry', 'apple', 'banana'] ?>>> sorted(fruits, reverse=True)['raspberry', 'grape', 'banana', 'apple'] ?>>> sorted(fruits, key=len)['grape', 'apple', 'banana', 'raspberry'] ?>>> sorted(fruits, key=len, reverse=True)['raspberry', 'banana', 'grape', 'apple'] ?>>> fruits['grape', 'raspberry', 'apple', 'banana'] ?>>> fruits.sort() ?>>> fruits['apple', 'banana', 'grape', 'raspberry'] ?>>> ?新建了一個按照字母排序的字符串列表。 ?原列表并沒有變化。 ?按照字母降序排序。 ?新建一個按照長度排序的字符串列表。因為這個排序算法是穩(wěn)定的,grape 和 apple 的長度都是 5,它們的相對位置跟在原來的列表里是一樣的。 ?按照長度降序排序的結果。結果并不是上面那個結果的完全翻轉,因為用到的排序算法是穩(wěn)定的,也就是說在長度一樣時,grape 和 apple 的相對位置不會改變。 ?直到這一步,原列表 fruits 都沒有任何變化。 ?對原列表就地排序,返回值 None 會被控制臺忽略。 ?此時 fruits 本身被排序。

未完待續(xù)…

!!!版權聲明!!!

本系列為博主學心得與體會,所有內容均為原創(chuàng)(????)

歡迎傳播、復制、修改。引用、轉載等請注明轉載來源。感謝您的配合

用于商業(yè)目的,請與博主采取聯(lián)系,并請與原書版權所有者聯(lián)系,謝謝!\(≧▽≦)/

!!!版權聲明!!!


《流暢的Python》

著????[巴西] Luciano Ramalho

譯????安 道 吳 珂

2017年 5 月北京第 1 次印刷

感謝編、著、譯、等等




生活嘛~ 最重要的就是開心嘍~ O(∩_∩)O~~


總結

以上是生活随笔為你收集整理的流畅的Python之奇技淫巧(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。