導航:首頁 > 編程語言 > 深入python2

深入python2

發布時間:2022-12-20 02:09:25

Ⅰ 深入淺出python怎麼樣

Head First 系列的書籍一直飽受贊譽,這本也不例外。Head First Python主要講述了Python 3的基礎語法知識以及如何使用Python快速地進行Web、手機上的開發。 下面是該書每章結束部分的知識摘要: 第一章 初始Python:人人都愛列表(Lists) 1. 從命令行或者IDLE里都可以運行Python 3; 2. 標識符是指代數據對象的名稱,它本身並沒有「類型」,但是它所指代的數據對象擁有類型; 3. 內置函數print()可以在屏幕上顯示消息; 4. Python中的列表list是用中括弧包住的以逗號分隔的數據集合; 5. list和數組非常相似; 6. list既可以使用內置函數,也可以使用針對列表本身的函數; 7. list的大小按需自動伸縮。數據使用的所有內存都由Python管理; 8. len()內置函數用來計算數據對象的長度或是某個集合(如list)內條目的數量; 9. for循環可以幫助遍歷list,它用起來通常比等價的while循環更方便; 10. if...else...語句幫助在代碼中做出不同的選擇; 11. isinstance()內置函數可用來檢測標識符指代的數據對象是否為指定類型; 12. 使用def定義自定義函數。 第二章 分享代碼:函數模塊 1. 模塊是包含Python代碼的文本文件; 2. 分發工具(distribution utilities)幫助您將模塊變為可共享的包; 3. setup.py程序提供了關於模塊的元數據,他可以用於生成,安裝和上傳分發包; 4. 使用import語句將模塊導入到其他程序中; 5. Python中每個模塊都提供了自己的命名空間。它在使用mole.function()形式調用時用以限定模塊內的函數。 6. 使用形如from mole import function的import語句可以將模塊內特定函數導入當前命名空間; 7. 使用#可以將一行代碼變為注釋或者為程序添加一條精短且在一行內的注釋; 8. 內置函數擁有自己的命名空間,叫做__builtins__,它會自動包含進每個Python程序中。 9. range()內置函數可以和for用在一起進行固定次數的遍歷; 10. 在print()內置函數結尾包含end=''可以關掉輸出時自動添加的換行符; 11. 如果為函數參數提供默認值,那麼它們就為成為可選參數。 第三章 文件和異常:處理錯誤 1. 使用open()內置函數打開磁碟文件並創建一個迭代器來每次從文件中讀取一行數據; 2. readline()方法從一個打開的文件中讀取一行數據; 3. seek()方法可以將文件重新定位到開頭; 4. close()方法關閉上一次打開的文件; 5. split()方法將一個字元串分為許多份組成的列表; 6. Python中不可改變的常量list叫做tuple。一旦列表數據復制給一個tuple之後,tuple中的數據將不能再被改變。Tuple是不能變的(immutable); 7. 當數據與期望的格式有出入時,會產生ValueError; 8. 當數據沒法被正確訪問時(例如數據文件可能已經移動過或者重命名過),會產生IOError; 9. help()內置函數提供在IDLE shell中訪問Python文檔; 10. find()方法可以在一個字元串中查找特定子串; 11. not關鍵字用來否定一個條件; 12. try/except語句提供了異常處理機制,可以保護那些可能導致運行時錯誤的代碼段; 13. pass語句是Python中的空語句,它什麼都不做。 第四章 持久化:將數據存成文件 1. strip()方法移除字元串首尾空白字元; 2. print()內置函數中的file參數可以控制data是讀入或是寫出; 3. 不管try/except語句中是否有異常發生,finally的代碼段總是會被執行; 4. 異常對象會傳入到except代碼段,並且可以使用as關鍵字將其賦值給一個標識符; 5. str()內置函數可以用來訪問任何數據對象的字元串表示,前提是該數據對象支持該轉換; 6. locals()內置函數返回當前作用范圍內的變數集合; 7. in操作符可用於測試成員包含關系; 8. "+"操作符應用於兩個字元串時會得到它們的串聯結果,而應用於數字時會得到它們的相加和; 9. with語句即使在異常發生的情況下,也會自動去關閉所有打開的文件。with語句同樣可以使用as關鍵字; 10. sys.stdout是Python中的標准輸出,它位於標准庫中的sys模塊; 11. 標准庫pickle模塊可以讓輕松高效地保存Python數據對象到磁碟和從磁碟恢復Python數據對象; 12. pickle.mp()函數將數據存檔; 13. pickle.load()函數從磁碟恢復數據。 第五章 理解數據:讓數據動起來 1. sort()方法原地排序列表; 2. sorted()內置函數通過復制排序的方式可以對大多數數據結構進行排序; 3. 傳入sort()或sorted的參數reverse=True可以將數據進行降序排序; 4. 形如下面的代碼段: new_l = [] for t in old_l: new_l.append(len(t)) 可以重寫為列表表達式形式:[len(t) for t in old_l] 5. 使用切片從list中獲取多個數據條目,如:my_lis[3:6]會從索引3的位置訪問到索引6的位置,不包含6。 6. 使用set()工廠方法創建一個集合 第六章 自定義數據對象:圍繞數據編碼 1. 使用dict()工廠函數或使用{}來創建一個空的dictionary; 2. 訪問一個叫做person的dictionary中Name鍵所對應的值,可是使用熟悉的中括弧記法:person['Name']; 3. 同list和set類似,Python的dictionary數據結構也會隨著新元素的加入動態的增長; 4. 填充dictionary的方法有:new_d = {}或new_d = dict(),然後使用d['Name'] = 'Eric Idle';或者直接用一句話new_d = {'Name': 'Eric Idle'}; 5. class關鍵字用來定義類; 6. 類中方法的定義與函數非常相像,都使用def關鍵字; 7. 類中屬性就如同對象實例內部的變數; 8. __init__()方法可以定義在類中用作實例化對象實例; 9. 類中定義的每個方法都必須提供self作為第一個參數; 10. 類中的每個屬性都必須使用self為前綴,以使得數據能與實例關聯在一起; 11. 既可以從頭開始創建類也可以從Python內置或自定義類中繼承; 12. 類可以被放入Python模塊並上傳到PyPI。 第7章 Web開發:信息匯總 1. MVC模式(Model-View-Controller)用一種可維護的方式幫助設計和構建一個Web應用; 2. model存儲Web應用中的數據; 3. view顯示Web應用的用戶界面; 4. controller使用編程邏輯將所有部分連接在一起; 5. 標准庫string模塊中有一個類叫做Template,它支持簡單的字元串替換; 6. 標准庫http.server模塊可以用來在Python中創建一個簡單的Web伺服器; 7. 標准庫cgi模塊提供編寫CGI腳本的支持; 8. 標准庫glob模塊處理文件列表非常好用; 9. 在Linux和Mac OS X上為可執行文件執行chmod+x命令; 10. 標准庫cgitb模塊在激活時可以在瀏覽器中看到CGI的編碼錯誤; 11. 使用cgitb.enable()可以在CGI代碼中打開CGI跟蹤; 12. 使用cgi.FieldStorage()可以訪問發送到Web伺服器請求部分的數據。 第8章 移動應用開發:小型設備 1. json庫模塊可以將Python內置類型轉為JSON數據交換格式; 2. 使用json.mps()可以創建Python類型的字元串版本; 3. 使用json.loads()從JSON字元串中創建Python類型; 4. 使用JSON發布數據需要制定Content-Type為application/json; 5. Python 2中的urllib和urllib2可以用與發送編碼後的數據給Web伺服器(使用urlencode和urlopen函數); 6. sys模塊提供了sys.stdin, sys.stdout和sys.stderr輸入流。 第9章 管理數據:處理輸入 1. 標准庫cgi模塊中的fieldStorage()方法可以訪問CGI腳本中發送給Web伺服器的數據; 2. 標准庫os中包含的environ字典,提供了對環境變數設置的輕松訪問; 3. SQLLite資料庫系統在Python中作為sqlite3標准庫存在; 4. connect()方法建立與資料庫文件的連接; 5. cursor()方法通過一個已有連接與資料庫進行通信; 6. execute()方法通過一個已有游標向資料庫發送SQL查詢; 7. commit()方法對資料庫做出永久性的改變; 8. rollback()方法取消任何針對數據的待定改動; 9. close()方法會關閉資料庫的已有連接; 10. Python代碼中的"?"佔位符可以參數化SQL語句。 第10章 擴展Web應用:變得真實 1. 每個App Engine Web應用都必須有一個叫做app.yaml的配置文件; 2. 使用GAE啟動器啟動、停止、監控、測試、上傳以及部署Web應用; 3. App Engine的模板技術基於Django項目; 4. App Engine也可以使用Django表單驗證框架; 5. 使用self.response對象構造一個GAE Web應答; 6. 使用self.request對象在GAE Web應用中訪問表單數據; 7. 當應答GET請求時,可以子啊get()方法中實現需要的功能; 8. 當應答POST請求時,在post()方法中實現需要的功能; 9. 使用put()方法將數據存儲到App Engine datastore中。 第11章 處理復雜數據 1. input()內置函數提示並接受來自用戶的輸入; 2. 如果發現在使用的是Python2,可以使用原生的_input()函數來取代input()函數; 3. 使用Python內置的列表、集合及字典構建復雜數據結構; 4. 標准庫中的time模塊,有大量函數可以用來轉換不同的時間格式。 書中沒有談到的10件重要的事 #1. 使用專業的IDE 書中推薦的是WingWare Python IDE。我一直在用的是Eclipse + PyDev #2. 積極面對作用域 使用global關鍵字可以強制將全局變數放入當前作用域 #3. 測試 書中提到了兩個用於測試的框架,一個是Python中的unittest模塊;另一個也是標准庫中的doctest #4. 高級語言特性 匿名函數、生成器、自定義異常、函數修飾符、元數據類等 #5. 正則表達式 #6. 更多的Web框架 Django、Zope、TurboGears、Web2py、Pylons等 #7. 對象關系映射(ORM)以及NoSQL ORM工具:SQL Alchemy NoSQL資料庫:CouchDB和MongoDB #8. 用戶界面編程 Python內置的跨平台的GUI構建工具集——tkinter(Tk Interface)。 其他的GUI編程技術有:PyGTK,PyKDE,WxPython和PyQT等。 #9. 避免使用多線程 Python中的全局解釋鎖限定Python只能運行單個解釋進程,即使多核情況下也不行 #10. 書籍推薦 Dive into Python 3 Python Essential Reference Programming in Python Learning Python ...

Ⅱ Python怎麼深入模塊進行學習

6.1. 深入模塊
除了包含函數定義外,模塊也可以包含可執行語句。這些語句一般用來初始化模塊。他們僅在 第一次 被導入的地方執行一次。[1]
每個模塊都有自己私有的符號表,被模塊內所有的函數定義作為全局符號表使用。因此,模塊的作者可以在模塊內部使用全局變數,而無需擔心它與某個用戶的全局變數意外沖突。從另一個方面講,如果你確切的知道自己在做什麼,你可以使用引用模塊函數的表示法訪問模塊的全局變數,modname.itemname。
模塊可以導入其他的模塊。一個(好的)習慣是將所有的 import 語句放在模塊的開始(或者是腳本),這並非強制。被導入的模塊名會放入當前模塊的全局符號表中。
import 語句的一個變體直接從被導入的模塊中導入命名到本模塊的語義表中。例如:
>>> from fibo import fib, fib2
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
這樣不會從局域語義表中導入模塊名(如上所示, fibo 沒有定義)。
甚至有種方式可以導入模塊中的所有定義:
>>> from fibo import *
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
這樣可以導入所有除了以下劃線( _ )開頭的命名。
需要注意的是在實踐中往往不鼓勵從一個模塊或包中使用 * 導入所有,因為這樣會讓代碼變得很難讀。不過,在互動式會話中這樣用很方便省力。

Ⅲ 哪些專業會深入學習到python

就我所知的專業需要學習python專業課的有(基本上數據結構學得越深,python就學得越深):軟體工程、通信工程、物聯網、機器人、信息管理、信息技術、計算機科學……

Ⅳ Python類的多重繼承問題深入分析

Python類的多重繼承問題深入分析
首先得說明的是,Python的類分為經典類 和 新式類
經典類是python2.2之前的東西,但是在2.7還在兼容,但是在3之後的版本就只承認新式類了
新式類在python2.2之後的版本中都可以使用
經典類和新式類的區別在於:
經典類是默認沒有派生自某個基類的,而新式類是默認派生自object這個基類的:
代碼如下:
# old style
class A():pass
# new style
class A(obejct):pass
2.經典類在類多重繼承的時候是採用從左到右深度優先原則匹配方法的..而新式類是採用C3演算法(不同於廣度優先)進行匹配的
3.經典類是沒有__MRO__和instance.mro()調用的,而新式類是有的.
為什麼不用經典類,要更換到新式類
因為在經典類中的多重繼承會有些問題...可能導致在繼承樹中的方法查詢繞過後面的父類:
代碼如下:
class A():
def foo1(self):
print "A"
class B(A):
def foo2(self):
pass
class C(A):
def foo1(self):
print "C"
class D(B, C):
pass
d = D()
d.foo1()
按照經典類的查找順序從左到右深度優先的規則,在訪問d.foo1()的時候,D這個類是沒有的..那麼往上查找,先找到B,裡面沒有,深度優先,訪問A,找到了foo1(),所以這時候調用的是A的foo1(),從而導致C重寫的foo1()被繞過.
所以python引入了新式類的概念,每個基類都繼承自object並且,他的匹配規則也從深度優先換到了C3
C3演算法
C3演算法是怎麼做匹配的呢..在問答版塊上面討論之後,歸結如下:
C3演算法的一個核心是merge.
在merge列表中,如果第一個序列mro的第一個類是出現在其它序列,並且也是第一個,或者不出現其它序列,那麼這個類就會從這些序列中刪除,並合到訪問順序列表中
比如:(引用問題中zhuangzebo的回答@zhuangzebo)
代碼如下:
class A(O):pass
class B(O):pass
class C(O):pass
class D(A,B):pass
class E(C,D):pass

首先需要知道 O(object)的mro(method resolution order)列表是[O,]
那麼接下來是:
代碼如下:
mro(A) = [A, O]
mro(B) = [B, O]
mro(C) = [C, O]
mro(D) = [D] + merge(mro(A), mro(B), [A, B])
= [D] + merge([A, O], [B, O], [A, B])
= [D, A] + merge([O], [B, O], [B])
= [D, A, B] + merge([O], [O])
= [D, A, B, O]
mro(E) = [E] + merge(mro(C), mro(D), [C, D])
= [E] + merge([C, O], [D, A, B, O], [C, D])
= [E, C] + merge([O], [D, A, B, O], [D])
= [E, C, D] + merge([O], [A, B, O])
= [E, C, D, A, B] + merge([O], [O])
= [E, C, D, A, B, O]

然後還有一種特殊情況:
比如:
merge(DO,CO,C) 先merge的是D
merge(DO,CO,C) 先merge的是C
意思就是.當出現有 一個類出現在兩個序列的頭(比如C) 這種情況和 這個類只有在一個序列的頭(比如D) 這種情況同時出現的時候,按照順序方式匹配。
新式類生成的訪問序列被存儲在一個叫MRO的只讀列表中..
你可以使用instance.__MRO__或者instance.mro()來訪問
最後匹配的時候就按照MRO序列的順序去匹配了
C3和廣度優先的區別:
舉個例子就完全明白了:
代碼如下:
class A(object):pass
class B(A):pass
class C(B):pass
class D(A):pass
class E(D):pass
class F(C, E):pass

按照廣度優先遍歷,F的MRO序列應該是[F,C,E,B,D,A]
但是C3是[F,E,D,C,B,A]
意思是你可以當做C3是在一條鏈路上深度遍歷到和另外一條鏈路的交叉點,然後去深度遍歷另外一條鏈路,最後遍歷交叉點
新式類和經典類的super和按類名訪問問題
在經典類中,你如果要訪問父類的話,是用類名來訪問的..
代碼如下:
class A():
def __init__(self):
print "A"
class B(A):
def __init__(self):
print "B"
A.__init__(self) #python不會默認調用父類的初始化函數的

這樣子看起來沒三問題,但是如果類的繼承結構比較復雜,會導致代碼的可維護性很差..
所以新式類推出了super這個東西...
代碼如下:
class A():
def __init__(self):
print "A"
class B(A):
def __init__(self):
print "B"
super(B,self).__init__()

這時候,又有一個問題:當類是多重繼承的時候,super訪問的是哪一個類呢?
super實際上是通過__MRO__序列來確定訪問哪一個類的...實際上就是調用__MRO__中此類後面的一個類的方法.
比如序列為[F,E,D,C,B,A]那麼F中的super就是E,E的就是D
super和按照類名訪問 混合使用帶來的坑
代碼如下:
class A(object):
def __init__(self):
print "enter A"
print "leave A"
class B(object):
def __init__(self):
print "enter B"
print "leave B"
class C(A):
def __init__(self):
print "enter C"
super(C, self).__init__()
print "leave C"
class D(A):
def __init__(self):
print "enter D"
super(D, self).__init__()
print "leave D"
class E(B, C):
def __init__(self):
print "enter E"
B.__init__(self)
C.__init__(self)
print "leave E"
class F(E, D):
def __init__(self):
print "enter F"
E.__init__(self)
D.__init__(self)
print "leave F"
這時候列印出來是:
代碼如下:
enter F
enter E
enter B
leave B
enter C
enter D
enter A
leave A
leave D
leave C
leave E
enter D
enter A
leave A
leave D
leave F

可以看出來D和A的初始化函數被亂入了兩次!
按類名訪問就相當於C語言之前的GOTO語句...亂跳,然後再用super按順序訪問..就有問題了
所以建議就是要麼一直用super,要麼一直用按照類名訪問
最佳實現:
避免多重繼承
super使用一致
不要混用經典類和新式類
調用父類的時候注意檢查類層次
以上便是本人對於python類的繼承的認識了,希望對大家能有所幫助

Ⅳ 深入理解python中的排序sort

進行一個簡單的升序排列直接調用sorted()函數,函數將會返回一個排序後的列表:

sorted函數不會改變原有的list,而是返回一個新的排好序的list

如果你想使用就地排序,也就是改變原list的內容,那麼可以使用list.sort()的方法,這個方法的返回值是None。

另一個區別是,list.sort()方法只是list也就是列表類型的方法,只可以在列表類型上調用。而sorted方法則是可以接受任何可迭代對象。

list.sort()和sorted()函數都有一個key參數,可以用來指定一個函數來確定排序的一個優先順序。比如,這個例子就是根據大小寫的優先順序進行排序:

key參數的值應該是一個函數,這個函數接受一個參數然後返回以一個key,這個key就被用作進行排序。這個方法很高效,因為對於每一個輸入的記錄只需要調用一次key函數。
一個常用的場景就是當我們需要對一個復雜對象的某些屬性進行排序時:

再如:

前面我們看到的利用key-function來自定義排序,同時Python也可以通過operator庫來自定義排序,而且通常這種方法更好理解並且效率更高。
operator庫提供了 itemgetter(), attrgetter(), and a methodcaller()三個函數

同時還支持多層排序

list.sort()和sorted()都有一個boolean類型的reverse參數,可以用來指定升序和降序排列,默認為false,也就是升序排序,如果需要降序排列,則需將reverse參數指定為true。

排序的穩定性指,有相同key值的多個記錄進行排序之後,原始的前後關系保持不變

我們可以看到python中的排序是穩定的。

我們可以利用這個穩定的特性來進行一些復雜的排序步驟,比如,我們將學生的數據先按成績降序然後年齡升序。當排序是穩定的時候,我們可以先將年齡升序,再將成績降序會得到相同的結果。

傳統的DSU(Decorate-Sort-Undecorate)的排序方法主要有三個步驟:

因為元組是按字典序比較的,比較完grade之後,會繼續比較i。
添加index的i值不是必須的,但是添加i值有以下好處:

現在python3提供了key-function,所以DSU方法已經不常用了

python2.x版本中,是利用cmp參數自定義排序。
python3.x已經將這個方法移除了,但是我們還是有必要了解一下cmp參數
cmp參數的使用方法就是指定一個函數,自定義排序的規則,和java等其他語言很類似

也可以反序排列

python3.x中可以用如下方式:

Ⅵ 零基礎學習python需要怎麼入手

編程零基礎的學習Python全棧可以按照以下內容來:
階段一:Python開發基礎
Python全棧開發與人工智慧之Python開發基礎知識學習內容包括:Python基礎語法、數據類型、字元編碼、文件操作、函數、裝飾器、迭代器、內置方法、常用模塊等。
階段二:Python高級編程和資料庫開發
Python全棧開發與人工智慧之Python高級編程和資料庫開發知識學習內容包括:面向對象開發、Socket網路編程、線程、進程、隊列、IO多路模型、Mysql資料庫開發等。
階段三:前端開發
Python全棧開發與人工智慧之前端開發知識學習內容包括:Html、CSS、JavaScript開發、Jquery&bootstrap開發、前端框架VUE開發等。
階段四:WEB框架開發
Python全棧開發與人工智慧之WEB框架開發學習內容包括:Django框架基礎、Django框架進階、BBS+Blog實戰項目開發、緩存和隊列中間件、Flask框架學習、Tornado框架學習、Restful API等。
階段五:爬蟲開發
Python全棧開發與人工智慧之爬蟲開發學習內容包括:爬蟲開發實戰。
階段六:全棧項目實戰
Python全棧開發與人工智慧之全棧項目實戰學習內容包括:企業應用工具學習、CRM客戶關系管理系統開發、路飛學城在線教育平台開發等。
階段七:數據分析
Python全棧開發與人工智慧之數據分析學習內容包括:金融量化分析。
階段八:人工智慧
Python全棧開發與人工智慧之人工智慧學習內容包括:機器學習、圖形識別、無人機開發、無人駕駛等。
階段九:自動化運維&開發
Python全棧開發與人工智慧之自動化運維&開發學習內容包括:CMDB資產管理系統開發、IT審計+主機管理系統開發、分布式主機監控系統開發等。
階段十:高並發語言GO開發
Python全棧開發與人工智慧之高並發語言GO開發學習內容包括:GO語言基礎、數據類型與文件IO操作、函數和面向對象、並發編程等。

Ⅶ 深入解析Python中的線程同步方法

深入解析Python中的線程同步方法
同步訪問共享資源
在使用線程的時候,一個很重要的問題是要避免多個線程對同一變數或其它資源的訪問沖突。一旦你稍不留神,重疊訪問、在多個線程中修改(共享資源)等這些操作會導致各種各樣的問題;更嚴重的是,這些問題一般只會在比較極端(比如高並發、生產伺服器、甚至在性能更好的硬體設備上)的情況下才會出現。
比如有這樣一個情況:需要追蹤對一事件處理的次數
counter = 0

def process_item(item):
global counter
... do something with item ...
counter += 1
如果你在多個線程中同時調用這個函數,你會發現counter的值不是那麼准確。在大多數情況下它是對的,但有時它會比實際的少幾個。
出現這種情況的原因是,計數增加操作實際上分三步執行:
解釋器獲取counter的當前值計算新值將計算的新值回寫counter變數
考慮一下這種情況:在當前線程獲取到counter值後,另一個線程搶佔到了CPU,然後同樣也獲取到了counter值,並進一步將counter值重新計算並完成回寫;之後時間片重新輪到當前線程(這里僅作標識區分,並非實際當前),此時當前線程獲取到counter值還是原來的,完成後續兩步操作後counter的值實際只加上1。
另一種常見情況是訪問不完整或不一致狀態。這類情況主要發生在一個線程正在初始化或更新數據時,另一個進程卻嘗試讀取正在更改的數據。
原子操作
實現對共享變數或其它資源的同步訪問最簡單的方法是依靠解釋器的原子操作。原子操作是在一步完成執行的操作,在這一步中其它線程無法獲得該共享資源。
通常情況下,這種同步方法只對那些只由單個核心數據類型組成的共享資源有效,譬如,字元串變數、數字、列表或者字典等。下面是幾個線程安全的操作:
讀或者替換一個實例屬性讀或者替換一個全局變數從列表中獲取一項元素原位修改一個列表(例如:使用append增加一個列表項)從字典中獲取一項元素原位修改一個字典(例如:增加一個字典項、調用clear方法)
注意,上面提到過,對一個變數或者屬性進行讀操作,然後修改它,最終將其回寫不是線程安全的。因為另外一個線程會在這個線程讀完卻沒有修改或回寫完成之前更改這個共享變數/屬性。

鎖是Python的threading模塊提供的最基本的同步機制。在任一時刻,一個鎖對象可能被一個線程獲取,或者不被任何線程獲取。如果一個線程嘗試去獲取一個已經被另一個線程獲取到的鎖對象,那麼這個想要獲取鎖對象的線程只能暫時終止執行直到鎖對象被另一個線程釋放掉。
鎖通常被用來實現對共享資源的同步訪問。為每一個共享資源創建一個Lock對象,當你需要訪問該資源時,調用acquire方法來獲取鎖對象(如果其它線程已經獲得了該鎖,則當前線程需等待其被釋放),待資源訪問完後,再調用release方法釋放鎖:
lock = Lock()

lock.acquire() #: will block if lock is already held
... access shared resource
lock.release()

注意,即使在訪問共享資源的過程中出錯了也應該釋放鎖,可以用try-finally來達到這一目的:
lock.acquire()
try:
... access shared resource
finally:
lock.release() #: release lock, no matter what

在Python 2.5及以後的版本中,你可以使用with語句。在使用鎖的時候,with語句會在進入語句塊之前自動的獲取到該鎖對象,然後在語句塊執行完成後自動釋放掉鎖:
from __future__ import with_statement #: 2.5 only

with lock:
... access shared resource

acquire方法帶一個可選的等待標識,它可用於設定當有其它線程佔有鎖時是否阻塞。如果你將其值設為False,那麼acquire方法將不再阻塞,只是如果該鎖被佔有時它會返回False:
if not lock.acquire(False):
... 鎖資源失敗
else:
try:
... access shared resource
finally:
lock.release()

你可以使用locked方法來檢查一個鎖對象是否已被獲取,注意不能用該方法來判斷調用acquire方法時是否會阻塞,因為在locked方法調用完成到下一條語句(比如acquire)執行之間該鎖有可能被其它線程佔有。
if not lock.locked():
#: 其它線程可能在下一條語句執行之前佔有了該鎖
lock.acquire() #: 可能會阻塞

簡單鎖的缺點
標準的鎖對象並不關心當前是哪個線程佔有了該鎖;如果該鎖已經被佔有了,那麼任何其它嘗試獲取該鎖的線程都會被阻塞,即使是佔有鎖的這個線程。考慮一下下面這個例子:
lock = threading.Lock()

def get_first_part():
lock.acquire()
try:
... 從共享對象中獲取第一部分數據
finally:
lock.release()
return data

def get_second_part():
lock.acquire()
try:
... 從共享對象中獲取第二部分數據
finally:
lock.release()
return data

示例中,我們有一個共享資源,有兩個分別取這個共享資源第一部分和第二部分的函數。兩個訪問函數都使用了鎖來確保在獲取數據時沒有其它線程修改對應的共享數據。
現在,如果我們想添加第三個函數來獲取兩個部分的數據,我們將會陷入泥潭。一個簡單的方法是依次調用這兩個函數,然後返回結合的結果:

def get_both_parts():
first = get_first_part()
seconde = get_second_part()
return first, second

這里的問題是,如有某個線程在兩個函數調用之間修改了共享資源,那麼我們最終會得到不一致的數據。最明顯的解決方法是在這個函數中也使用lock:
def get_both_parts():
lock.acquire()
try:
first = get_first_part()
seconde = get_second_part()
finally:
lock.release()
return first, second

然而,這是不可行的。裡面的兩個訪問函數將會阻塞,因為外層語句已經佔有了該鎖。為了解決這個問題,你可以通過使用標記在訪問函數中讓外層語句釋放鎖,但這樣容易失去控制並導致出錯。幸運的是,threading模塊包含了一個更加實用的鎖實現:re-entrant鎖。
Re-Entrant Locks (RLock)

RLock類是簡單鎖的另一個版本,它的特點在於,同一個鎖對象只有在被其它的線程佔有時嘗試獲取才會發生阻塞;而簡單鎖在同一個線程中同時只能被佔有一次。如果當前線程已經佔有了某個RLock鎖對象,那麼當前線程仍能再次獲取到該RLock鎖對象。
lock = threading.Lock()
lock.acquire()
lock.acquire() #: 這里將會阻塞

lock = threading.RLock()
lock.acquire()
lock.acquire() #: 這里不會發生阻塞

RLock的主要作用是解決嵌套訪問共享資源的問題,就像前面描述的示例。要想解決前面示例中的問題,我們只需要將Lock換為RLock對象,這樣嵌套調用也會OK.
lock = threading.RLock()

def get_first_part():
... see above

def get_second_part():
... see above

def get_both_parts():
... see above

這樣既可以單獨訪問兩部分數據也可以一次訪問兩部分數據而不會被鎖阻塞或者獲得不一致的數據。
注意RLock會追蹤遞歸層級,因此記得在acquire後進行release操作。
Semaphores

信號量是一個更高級的鎖機制。信號量內部有一個計數器而不像鎖對象內部有鎖標識,而且只有當佔用信號量的線程數超過信號量時線程才阻塞。這允許了多個線程可以同時訪問相同的代碼區。
semaphore = threading.BoundedSemaphore()
semaphore.acquire() #: counter減小

... 訪問共享資源
semaphore.release() #: counter增大

當信號量被獲取的時候,計數器減小;當信號量被釋放的時候,計數器增大。當獲取信號量的時候,如果計數器值為0,則該進程將阻塞。當某一信號量被釋放,counter值增加為1時,被阻塞的線程(如果有的話)中會有一個得以繼續運行。
信號量通常被用來限制對容量有限的資源的訪問,比如一個網路連接或者資料庫伺服器。在這類場景中,只需要將計數器初始化為最大值,信號量的實現將為你完成剩下的事情。
max_connections = 10

semaphore = threading.BoundedSemaphore(max_connections)

如果你不傳任何初始化參數,計數器的值會被初始化為1.
Python的threading模塊提供了兩種信號量實現。Semaphore類提供了一個無限大小的信號量,你可以調用release任意次來增大計數器的值。為了避免錯誤出現,最好使用BoundedSemaphore類,這樣當你調用release的次數大於acquire次數時程序會出錯提醒。
線程同步

鎖可以用在線程間的同步上。threading模塊包含了一些用於線程間同步的類。
Events

一個事件是一個簡單的同步對象,事件表示為一個內部標識(internal flag),線程等待這個標識被其它線程設定,或者自己設定、清除這個標識。
event = threading.Event()

#: 一個客戶端線程等待flag被設定
event.wait()

#: 服務端線程設置或者清除flag
event.set()
event.clear()

一旦標識被設定,wait方法就不做任何處理(不會阻塞),當標識被清除時,wait將被阻塞直至其被重新設定。任意數量的線程可能會等待同一個事件。
Conditions

條件是事件對象的高級版本。條件表現為程序中的某種狀態改變,線程可以等待給定條件或者條件發生的信號。
下面是一個簡單的生產者/消費者實例。首先你需要創建一個條件對象:

#: 表示一個資源的附屬項
condition = threading.Condition()
生產者線程在通知消費者線程有新生成資源之前需要獲得條件:
#: 生產者線程
... 生產資源項
condition.acquire()
... 將資源項添加到資源中
condition.notify() #: 發出有可用資源的信號
condition.release()
消費者必須獲取條件(以及相關聯的鎖),然後嘗試從資源中獲取資源項:
#: 消費者線程
condition.acquire()
while True:
...從資源中獲取資源項
if item:
break
condition.wait() #: 休眠,直至有新的資源
condition.release()
... 處理資源

wait方法釋放了鎖,然後將當前線程阻塞,直到有其它線程調用了同一條件對象的notify或者notifyAll方法,然後又重新拿到鎖。如果同時有多個線程在等待,那麼notify方法只會喚醒其中的一個線程,而notifyAll則會喚醒全部線程。
為了避免在wait方法處阻塞,你可以傳入一個超時參數,一個以秒為單位的浮點數。如果設置了超時參數,wait將會在指定時間返回,即使notify沒被調用。一旦使用了超時,你必須檢查資源來確定發生了什麼。
注意,條件對象關聯著一個鎖,你必須在訪問條件之前獲取這個鎖;同樣的,你必須在完成對條件的訪問時釋放這個鎖。在生產代碼中,你應該使用try-finally或者with.
可以通過將鎖對象作為條件構造函數的參數來讓條件關聯一個已經存在的鎖,這可以實現多個條件公用一個資源:
lock = threading.RLock()
condition_1 = threading.Condition(lock)
condition_2 = threading.Condition(lock)

互斥鎖同步
我們先來看一個例子:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time, threading

# 假定這是你的銀行存款:
balance = 0
muxlock = threading.Lock()

def change_it(n):
# 先存後取,結果應該為0:
global balance
balance = balance + n
balance = balance - n

def run_thread(n):
# 循環次數一旦多起來,最後的數字就變成非0
for i in range(100000):
change_it(n)

t1 = threading.Thread(target=run_thread, args=(5,))
t2 = threading.Thread(target=run_thread, args=(8,))
t3 = threading.Thread(target=run_thread, args=(9,))
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
print balance

結果 :

[/data/web/test_python]$ python multhread_threading.py
0
[/data/web/test_python]$ python multhread_threading.py
61
[/data/web/test_python]$ python multhread_threading.py
0
[/data/web/test_python]$ python multhread_threading.py
24

上面的例子引出了多線程編程的最常見問題:數據共享。當多個線程都修改某一個共享數據的時候,需要進行同步控制。
線程同步能夠保證多個線程安全訪問競爭資源,最簡單的同步機制是引入互斥鎖。互斥鎖為資源引入一個狀態:鎖定/非鎖定。某個線程要更改共享數據時,先將其鎖定,此時資源的狀態為「鎖定」,其他線程不能更改;直到該線程釋放資源,將資源的狀態變成「非鎖定」,其他的線程才能再次鎖定該資源。互斥鎖保證了每次只有一個線程進行寫入操作,從而保證了多線程情況下數據的正確性。

threading模塊中定義了Lock類,可以方便的處理鎖定:
#創建鎖mutex = threading.Lock()
#鎖定mutex.acquire([timeout])
#釋放mutex.release()

其中,鎖定方法acquire可以有一個超時時間的可選參數timeout。如果設定了timeout,則在超時後通過返回值可以判斷是否得到了鎖,從而可以進行一些其他的處理。
使用互斥鎖實現上面的例子的代碼如下:
balance = 0
muxlock = threading.Lock()

def change_it(n):
# 獲取鎖,確保只有一個線程操作這個數
muxlock.acquire()
global balance
balance = balance + n
balance = balance - n
# 釋放鎖,給其他被阻塞的線程繼續操作
muxlock.release()

def run_thread(n):
for i in range(10000):
change_it(n)

加鎖後的結果,就能確保數據正確:
[/data/web/test_python]$ python multhread_threading.py
0
[/data/web/test_python]$ python multhread_threading.py
0
[/data/web/test_python]$ python multhread_threading.py
0
[/data/web/test_python]$ python multhread_threading.py
0

Ⅷ 小白學Python:Python從基礎到深入(第2版)

使用網路網盤免費分享給你,鏈接:https://pan..com/s/1tQMIEGn7Vo53AyG_AIeHtg

提取碼:vf97

Ⅸ 如何深入了解python原理

第一步閱讀python所有內置模塊的代碼
第二步閱讀python的C/C++源代碼

Ⅹ python深入學習那個方向比較好

一、Python網路爬蟲
學習目標
1.掌握Python網路爬蟲基礎及進階
2.掌握基本的網路爬蟲項目
3.編寫復雜的爬蟲項目
4.掌握反爬蟲技術

二、Python人工智慧
學習目標
1. 掌握Python機器學習與數據挖掘、深度學習基礎
2. 學會用Python做數據處理
3. 掌握數據挖掘、機器學習與深度學習的核心知識點
4. 深入理解常見機器學習與數據挖掘演算法的底層原理,並通過Python實現
5. 深入理解神經網路與深度學習演算法的底層原理,並通過Python實現
6. 熟練使用深度學習的各種框架
7. 成為優秀的Python數據分析師

三、Python WEB開發
學習目標
1.了解Python網路開發知識
2.熟悉Python網路編程
3.為工作實戰打下基礎

四、Python自動化運維/測試
學習目標
1. 了解自動化運維/測試技術
2. 熟練使用Ansible、selenium等運維/測試工具
3. 熟悉掌握互聯網企業運維/測試流程;能夠自主搭建B/S自動化運維/測試平台
4. 通過Python實現對集群伺服器進行批量自動化運維
5、自動化測試:介面自動化測試、web自動化測試等
6、輔助測試工具:性能測試工具、輔助測試工具等

閱讀全文

與深入python2相關的資料

熱點內容
dvd光碟存儲漢子演算法 瀏覽:757
蘋果郵件無法連接伺服器地址 瀏覽:963
phpffmpeg轉碼 瀏覽:671
長沙好玩的解壓項目 瀏覽:145
專屬學情分析報告是什麼app 瀏覽:564
php工程部署 瀏覽:833
android全屏透明 瀏覽:737
阿里雲伺服器已開通怎麼辦 瀏覽:803
光遇為什麼登錄時伺服器已滿 瀏覽:302
PDF分析 瀏覽:485
h3c光纖全工半全工設置命令 瀏覽:143
公司法pdf下載 瀏覽:382
linuxmarkdown 瀏覽:350
華為手機怎麼多選文件夾 瀏覽:683
如何取消命令方塊指令 瀏覽:350
風翼app為什麼進不去了 瀏覽:778
im4java壓縮圖片 瀏覽:362
數據查詢網站源碼 瀏覽:150
伊克塞爾文檔怎麼進行加密 瀏覽:892
app轉賬是什麼 瀏覽:163