Python 中那些令人防不勝防的坑

来源:https://www.cnblogs.com/bianchenjiaoshou/archive/2019/11/23/11919685.html
-Advertisement-
Play Games

前言文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯繫我們以作處理。 作者: Rocky0429 在學習 Python 的過程中,我為它的簡潔優雅而痴迷,但它又是如此的調皮,在提供了很多舒服的功能特性之外,又悄悄挖了很多帶有迷惑性的坑,令人防不勝防 ...


前言
文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯繫我們以作處理。

作者: Rocky0429

在學習 Python 的過程中,我為它的簡潔優雅而痴迷,但它又是如此的調皮,在提供了很多舒服的功能特性之外,又悄悄挖了很多帶有迷惑性的坑,令人防不勝防…

人不能兩次踏入同一條河流,在無數次踩進同樣的坑裡之後,我覺得我有必要整理一下,一為自警,二為給大家提個醒,希望你不要和我犯相同的錯誤。

0x00 走丟的外部變數

首先我們先來看這麼一個例子:


e = 429

try:
   raise Exception()
except Exception as e:
   pass

print(e)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

PS:except Exception as e 可以捕獲除了與程式退出(sys.exit())相關之外的所有異常。

PS:如果你缺乏最新python實戰教程,可以去小編的Python技術.裙 :一久五其二二流一思(數字的諧音)轉換下可以找到了

在繼續向下看之前,你可以先思考一下上述例子可能出現的結果是什麼,也可以自己嘗試著在編譯器里輸入一下。思考完了請繼續往下看。

出現的結果如下:


Traceback (most recent call last):
 File "test.py", line 8, in <module>
   print(e)
NameError: name 'e' is not defined
  • 1
  • 2
  • 3
  • 4

竟然報錯了,那麼這到底是為什麼呢? 

其實這是因為在 Python3 中使用 as 分配異常的時候,在 except 的末尾將會把這個異常清除掉(在 Python2 中則不會出現這樣的情況)。這就好像將上面的示例變成下麵的樣子:


e = 429

try:
   raise Exception()
except Exception as e:
   try:
       pass
   finally:
       del e

print(e)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

通過上面的變形代碼,我們可以很清楚的看明白髮生這一切的根源是什麼:因為 e 被刪除了。這也變相的告訴我們,如果想要在 except 後面引用 e,必須將它先賦值給其它變數。 

這樣看來,是變數 e 執行了 except 子句而被刪除,但是為什麼 e 會去執行 except 子句呢?僅僅是因為 e 和 as 後面的 e 長的一毛一樣?


答案是否定的,其實這個是因為子句在 Python 中沒有獨立的作用域,所以上述示例中的所有內容都處於同一個作用域里,所以變數 e 會因為執行了 except 子句而被刪除。



0x01 同樣是加,卻不一定等價

在我們來表示「加」這個概念的時候,一般我們會用兩種方式:a = a + b或者是 a += b 。在很多人的概念里這兩個其實就是一種,不分彼此,比如之前我就是這麼認為的,直到有一天有人拿著下麵的坑過來讓我踩... 

首先我們先來看第一個例子:


>>> a = [1,2,3]
>>> b = a
>>> a = a + [4,5,6]
  • 1
  • 2
  • 3

一個很簡單的例子,你知道此時的 a 和 b 分別是多少麽?請先自己思考一下再繼續向下看:


>>> a
[1, 2, 3, 4, 5, 6]
>>> b
[1, 2, 3]
  • 1
  • 2
  • 3
  • 4

估計很多人都會答對,表達式 a = a + [4,5,6] ,等號右邊其實是形成了一個新的列表,最後讓 a 引用了這個新的列表,而 b = a 引用的是之前的 a,所以 b 保持不變。 

明白了上面的例子,我們接下來再看一個稍微有點區別的例子:


>>> a = [1,2,3]
>>> b = a
>>> a += [4,5,6]
  • 1
  • 2
  • 3

上面的例子和文章開頭的例子區別在從 + 變成了 +=,按照我們慣性思維去想,肯定以為這倆例子就是一個東西的兩種不同寫法而已,可實際上真的是這樣嗎?讓我們來看一下此時的 a,b: 
>>> a
[1, 2, 3, 4, 5, 6]
>>> b
[1, 2, 3, 4, 5, 6]
  • 1
  • 2
  • 3
  • 4

咦?同樣是印象里的「加」,好像真的哪裡有點不一樣誒。。 

通過上面我們就可以看出 a = a + b 和 a += b 並不總是表現相同,起碼在列表上就是這麼表現的。在這裡的 a += [4,5,6] 實際上使用的是 extend 函數,所以 a 和 b 仍然指向已被修改的同一列表。


既然在這裡說到了 + 和 +=,索性再多補充一點:在使用「加」的概念來連接字元串的時候,+= 其實比 + 的速度更快。


下麵我們來實際的演示一下用 + 連接三個字元串:


>>> import timeit
>>> timeit.timeit("a = a + b + c", setup="a='a'*10000;b='b'*10000;c='c'*10000",number=100)
0.07921688999340404
>>> timeit.timeit("a += b + c", setup="a='a'*10000;b='b'*10000;c='c'*10000",number=100)
0.002059974998701364
  • 1
  • 2
  • 3
  • 4
  • 5

上面的兩個結果很容易看出來,在處理速度上,+= 比 + 處理的速度要快的多。出現這樣現象的原因是 += 執行的是追加操作,追加操作的話就會比 + 少了一個銷毀然後新建的動作,比如在 a += b + c 上 a 就不會被銷毀。 

0x02 不一般的小括弧

很多學過別的編程語言的同學,很容易會忽略小括弧 “()” 在 Python 中的一個重要表現,那就是小括弧還能表示“元組” 這一不可變數據類型。


>>> type(())
<class 'tuple'>
>>> tur = (1, 2)
>>> type(tur)
<class 'tuple'>
  • 1
  • 2
  • 3
  • 4
  • 5

但是如果小括弧內只有一個元素的話,比如像下麵這樣,它就是小括弧內的元素類型: 
>>> tur = (1)
>>> type(tur)
<class 'int'>
  • 1
  • 2
  • 3

天吶個天... 

那麼如果想要表示一個元素的元組咋整呢?要像下麵這樣:


>>> tur = (1, )
>>> type(tur)
<class 'tuple'>
  • 1
  • 2
  • 3

加個逗號 “,” 就 ok 啦... 

0x03 列表的刪除沒有那麼簡單

假如我們有一個列表,我想刪除列表中的元素: 
>>> lst = [1, 2, 3, 4, 5]
>>> for i in lst:
... lst.remove(i)
  • 1
  • 2
  • 3

在剛開始學習 Python 之初,這是很多同學容易想到的做法,然而我們來看一下程式運行完以後的結果: 
>>> lst
[2, 4]
  • 1
  • 2

看到這個結果,我...

在這裡插入圖片描述


這是為啥子呢?是因為在 for 迴圈中,如果我們刪除了 index = 0 (即 1)的值,原本 index = 1 及其之後的值會向前補位,所以當前 index = 1 的值為之前 index = 2 的值。


列表的刪除操作我們經常要用,所以大家要打起十二分的精神來對它。



0x04 is not 不分家

is not 在 Python 中是一伙的,用的時候要靠在一起,分開以後就是兩個東西,結果會不一樣…


>>> [1, 2, 3] is not None
True
>>> [1, 2, 3] is (not None)
False
 
  • 1
  • 2
  • 3
  • 4

這就在於,is not 是個單獨的二元運算符,當它兩側的變數指向同一個對象的時候,結果為 False,否則結果為 True,希望引起大家的註意.
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文適合JAVA新人,想瞭解RabbitMQ又不想去看官網文檔的人(英語水看的頭疼(◎﹏◎),但建議有能力還是去看官網文檔)。 消息隊列MQ(一) MQ全稱為Message Queue,消息隊列是應用程式和應用程式之間的通信方法。 先引入一下常見的通訊方案。 為什麼使用MQ? 在項目中,可將一些無需 ...
  • 前言 "《【源碼解析】憑什麼?spring boot 一個 jar 就能開發 web 項目》 " 中有讀者反應: 部署後運維很不方便,比較修改一個 IP 配置,需要重新打包。 這一點我是深有體會,17 年自學,並很大膽的直接在生產環境用的時候,我都是讓產品經理(此時他充當我們的運維,嘿嘿)用壓縮軟體 ...
  • Spring Cloud Stream 是一個構建消息驅動微服務的框架,該框架在Spring Boot的基礎上整合了Spring Integrationg來連接消息代理中間件(RabbitMQ, Kafka等),提供了個性化的自動化配置實現,並引入了發佈-訂閱、消費組、分區這三個核心概念。 應用程... ...
  • 這是我以前解決問題時,收集在印象筆記里的內容,為了以後整理方便,把它轉移至這裡。以下內容,均來自微軟官方網站相關。 問題:C++控制台閃回 解決辦法: 1,在程式結尾添加system("pause");[若有return語句則寫在return之前] 解析:system(const char *com ...
  • 有序化 以小說章節目錄的數字為文件名,一章一個文件(但上千章就得有上千個文件) 在每次獲取小說章節里的內容時,給item添加新的標識,添加對應的章節的數字,全部存入資料庫,然後根據這個數字標識排序取出數據即可 去空行 利用splitlines()和strip() str.splitlines([ke ...
  • 題目:無重覆字元的最長子串。 給定一個字元串,請你找出其中不含有重覆字元的 最長子串 的長度。 示例 1: 輸入: “abcabcbb” 輸出: 3 解釋: 因為無重覆字元的最長子串是 “abc”,所以其長度為 3。 示例 2: 輸入: “bbbbb” 輸出: 1 解釋: 因為無重覆字元的最長子串是 ...
  • 數據的排序是在解決實際問題時經常用到的步驟,也是數據結構的考點之一,下麵介紹10種經典的排序方法。 首先,排序方法可以大體分為插入排序、選擇排序、交換排序、歸併排序和桶排序四大類,其中,插入排序又分為直接插入排序、二分插入排序和希爾排序,選擇排序分為直接選擇排序和堆排序,交換排序分為冒泡排序和快速排 ...
  • 在Python函數中,傳遞的參數如果預設有一個為 列表(list),那麼就要註意了,此處有坑. 入坑 挖坑 預期結果 執行結果 出坑 當定義函數時,會保存函數中預設參數 list 的值,也就是列表 li=[]; 在每次調用的時候如果傳遞了新的列表,則使用傳遞的列表,沒有傳遞,使用定義函數時保存的預設 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...