Python學習基礎方便查詢

本節內容php

  1. Python介紹
  2. 發展史
  3. Python 2 or 3?
  4. 安裝
  5. Hello World程序
  6. 變量
  7. 用戶輸入
  8. 模塊初識
  9. .pyc是個什麼鬼?
  10. 數據類型初識
  11. 數據運算
  12. 表達式if ...else語句
  13. 表達式for 循環
  14. break and continue 
  15. 表達式while 循環
  16. 做業需求
  17. 列表、元組操做
  18. 字符串操做
  19. 字典操做
  20. 集合操做
  21. 文件操做
  22. 字符編碼與轉碼 
  23. 函數基本語法及特性
  24. 參數與局部變量
  25. 返回值
  26. 嵌套函數
  27. 遞歸
  28. 匿名函數
  29. 函數式編程介紹
  30. 高階函數
  31. 內置函數
  32. 迭代器&生成器
  33. 裝飾器
  34. Json & pickle 數據序列化
  35. 軟件目錄結構規範
  36. 做業:ATM項目開發
  37. 模塊介紹
  38. time &datetime模塊
  39. random
  40. os
  41. sys
  42. shutil
  43. json & picle
  44. shelve
  45. xml處理
  46. yaml處理
  47. configparser
  48. hashlib
  49. subprocess
  50. logging模塊
  51. re正則表達式

 

1、 Python介紹

python的創始人爲吉多·範羅蘇姆(Guido van Rossum)。1989年的聖誕節期間,吉多·範羅蘇姆爲了在阿姆斯特丹打發時間,決心開發一個新的腳本解釋程序,做爲ABC語言的一種繼承。  html

最新的TIOBE排行榜,Python趕超PHP佔據第五, Python崇尚優美、清晰、簡單,是一個優秀並普遍使用的語言。java

由上圖可見,Python總體呈上升趨勢,反映出Python應用愈來愈普遍而且也逐漸獲得業內的承認!!!node

Python能夠應用於衆多領域,如:數據分析、組件集成、網絡服務、圖像處理、數值計算和科學計算等衆多領域。目前業內幾乎全部大中型互聯網企業都在使用Python,如:Youtube、Dropbox、BT、Quora(中國知乎)、豆瓣、知乎、Google、Yahoo!、Facebook、NASA、百度、騰訊、汽車之家、美團等。python

目前Python主要應用領域:mysql

  • 雲計算: 雲計算最火的語言, 典型應用OpenStack
  • WEB開發: 衆多優秀的WEB框架,衆多大型網站均爲Python開發,Youtube, Dropbox, 豆瓣。。。, 典型WEB框架有Django
  • 科學運算、人工智能: 典型庫NumPy, SciPy, Matplotlib, Enthought librarys,pandas
  • 系統運維: 運維人員必備語言
  • 金融:量化交易,金融分析,在金融工程領域,Python不但在用,且用的最多,並且重要性逐年提升。緣由:做爲動態語言的Python,語言結構清晰簡單,庫豐富,成熟穩定,科學計算和統計分析都很牛逼,生產效率遠遠高於c,c++,java,尤爲擅長策略回測
  • 圖形GUI: PyQT, WxPython,TkInter

Python在一些公司的應用: linux

  • 谷歌:Google App Engine 、code.google.com 、Google earth 、谷歌爬蟲、Google廣告等項目都在大量使用Python開發
  • CIA: 美國中情局網站就是用Python開發的
  • NASA: 美國航天局(NASA)大量使用Python進行數據分析和運算
  • YouTube:世界上最大的視頻網站YouTube就是用Python開發的
  • Dropbox:美國最大的在線雲存儲網站,所有用Python實現,天天網站處理10億個文件的上傳和下載
  • Instagram:美國最大的圖片分享社交網站,天天超過3千萬張照片被分享,所有用python開發
  • Facebook:大量的基礎庫均經過Python實現的
  • Redhat: 世界上最流行的Linux發行版本中的yum包管理工具就是用python開發的
  • 豆瓣: 公司幾乎全部的業務均是經過Python開發的
  • 知乎: 國內最大的問答社區,經過Python開發(國外Quora)
  • 春雨醫生:國內知名的在線醫療網站是用Python開發的
  • 除上面以外,還有搜狐、金山、騰訊、盛大、網易、百度、阿里、淘寶 、土豆、新浪、果殼等公司都在使用Python完成各類各樣的任務。 

Python 是一門什麼樣的語言?

編程語言主要從如下幾個角度爲進行分類,編譯型和解釋型、靜態語言和動態語言、強類型定義語言和弱類型定義語言,每一個分類表明什麼意思呢,咱們一塊兒來看一下。ios

編譯和解釋的區別是什麼?

編譯器是把源程序的每一條語句都編譯成機器語言,並保存成二進制文件,這樣運行時計算機能夠直接以機器語言來運行此程序,速度很快; nginx

解釋器則是隻在執行程序時,才一條一條的解釋成機器語言給計算機來執行,因此運行速度是不如編譯後的程序運行的快的. c++

這是由於計算機不能直接認識並執行咱們寫的語句,它只能認識機器語言(是二進制的形式)

 

1、低級語言與高級語言

最初的計算機程序都是用0和1的序列表示的,程序員直接使用的是機器指令,無需翻譯,從紙帶打孔輸入便可執行獲得結果。後來爲了方便記憶,就將用0、1序列表示的機器指令都用符號助記,這些與機器指令一一對應的助記符就成了彙編指令,從而誕生了彙編語言。不管是機器指令仍是彙編指令都是面向機器的,統稱爲低級語言。由於是針對特定機器的機器指令的助記符,因此彙編語言是沒法獨立於機器(特定的CPU體系結構)的。但彙編語言也是要通過翻譯成機器指令才能執行的,因此也有將運行在一種機器上的彙編語言翻譯成運行在另外一種機器上的機器指令的方法,那就是交叉彙編技術。

高級語言是從人類的邏輯思惟角度出發的計算機語言,抽象程度大大提升,須要通過編譯成特定機器上的目標代碼才能執行,一條高級語言的語句每每須要若干條機器指令來完成。高級語言獨立於機器的特性是靠編譯器爲不一樣機器生成不一樣的目標代碼(或機器指令)來實現的。那具體的說,要將高級語言編譯到什麼程度呢,這又跟編譯的技術有關了,既能夠編譯成直接可執行的目標代碼,也能夠編譯成一種中間表示,而後拿到不一樣的機器和系統上去執行,這種狀況一般又須要支撐環境,好比解釋器或虛擬機的支持,Java程序編譯成bytecode,再由不一樣平臺上的虛擬機執行就是很好的例子。因此,說高級語言不依賴於機器,是指在不一樣的機器或平臺上高級語言的程序自己不變,而經過編譯器編譯獲得的目標代碼去適應不一樣的機器。從這個意義上來講,經過交叉彙編,一些彙編程序也能夠得到不一樣機器之間的可移植性,但這種途徑得到的移植性遠遠不如高級語言來的方便和實用性大。


2、編譯與解釋

編譯是將源程序翻譯成可執行的目標代碼,翻譯與執行是分開的;而解釋是對源程序的翻譯與執行一次性完成,不生成可存儲的目標代碼。這只是表象,兩者背後的最大區別是:對解釋執行而言,程序運行時的控制權在解釋器而不在用戶程序;對編譯執行而言,運行時的控制權在用戶程序。

解釋具備良好的動態特性和可移植性,好比在解釋執行時能夠動態改變變量的類型、對程序進行修改以及在程序中插入良好的調試診斷信息等,而將解釋器移植到不一樣的系統上,則程序不用改動就能夠在移植瞭解釋器的系統上運行。同時解釋器也有很大的缺點,好比執行效率低,佔用空間大,由於不只要給用戶程序分配空間,解釋器自己也佔用了寶貴的系統資源。

編譯器是把源程序的每一條語句都編譯成機器語言,並保存成二進制文件,這樣運行時計算機能夠直接以機器語言來運行此程序,速度很快;
而解釋器則是隻在執行程序時,才一條一條的解釋成機器語言給計算機來執行,因此運行速度是不如編譯後的程序運行的快的.

 

編譯型和解釋型
咱們先看看編譯型,其實它和彙編語言是同樣的:也是有一個負責翻譯的程序來對咱們的源代碼進行轉換,生成相對應的可執行代碼。這個過程說得專業一點,就稱爲編譯(Compile),而負責編譯的程序天然就稱爲編譯器(Compiler)。若是咱們寫的程序代碼都包含在一個源文件中,那麼一般編譯以後就會直接生成一個可執行文件,咱們就能夠直接運行了。但對於一個比較複雜的項目,爲了方便管理,咱們一般把代碼分散在各個源文件中,做爲不一樣的模塊來組織。這時編譯各個文件時就會生成目標文件(Object   file)而不是前面說的可執行文件。通常一個源文件的編譯都會對應一個目標文件。這些目標文件裏的內容基本上已是可執行代碼了,但因爲只是整個項目的一部分,因此咱們還不能直接運行。待全部的源文件的編譯都大功告成,咱們就能夠最後把這些半成品的目標文件「打包」成一個可執行文件了,這個工做由另外一個程序負責完成,因爲此過程好像是把包含可執行代碼的目標文件鏈接裝配起來,因此又稱爲連接(Link),而負責連接的程序就叫……就叫連接程序(Linker)。連接程序除了連接目標文件外,可能還有各類資源,像圖標文件啊、聲音文件啊什麼的,還要負責去除目標文件之間的冗餘重複代碼,等等,因此……也是挺累的。連接完成以後,通常就能夠獲得咱們想要的可執行文件了。 

上面咱們大概地介紹了編譯型語言的特色,如今再看看解釋型。噢,從字面上看,「編譯」和「解釋」的確都有「翻譯」的意思,它們的區別則在於翻譯的時機安排不大同樣。打個比方:假如你打算閱讀一本外文書,而你不知道這門外語,那麼你能夠找一名翻譯,給他足夠的時間讓他從頭至尾把整本書翻譯好,而後把書的母語版交給你閱讀;或者,你也馬上讓這名翻譯輔助你閱讀,讓他一句一句給你翻譯,若是你想往回看某個章節,他也得從新給你翻譯。 

兩種方式,前者就至關於咱們剛纔所說的編譯型:一次把全部的代碼轉換成機器語言,而後寫成可執行文件;然後者就至關於咱們要說的解釋型:在程序運行的前一刻,還只有源程序而沒有可執行程序;而程序每執行到源程序的某一條指令,則會有一個稱之爲解釋程序的外殼程序將源代碼轉換成二進制代碼以供執行,總言之,就是不斷地解釋、執行、解釋、執行……因此,解釋型程序是離不開解釋程序的。像早期的BASIC就是一門經典的解釋型語言,要執行BASIC程序,就得進入BASIC環境,而後才能加載程序源文件、運行。解釋型程序中,因爲程序老是以源代碼的形式出現,所以只要有相應的解釋器,移植幾乎不成問題。編譯型程序雖然源代碼也能夠移植,但前提是必須針對不一樣的系統分別進行編譯,對於複雜的工程來講,的確是一件不小的時間消耗,何況極可能一些細節的地方仍是要修改源代碼。並且,解釋型程序省卻了編譯的步驟,修改調試也很是方便,編輯完畢以後便可當即運行,沒必要像編譯型程序同樣每次進行小小改動都要耐心等待漫長的Compiling…Linking…這樣的編譯連接過程。不過凡事有利有弊,因爲解釋型程序是將編譯的過程放到執行過程當中,這就決定了解釋型程序註定要比編譯型慢上一大截,像幾百倍的速度差距也是不足爲奇的。 

編譯型與解釋型,二者各有利弊。前者因爲程序執行速度快,同等條件下對系統要求較低,所以像開發操做系統、大型應用程序、數據庫系統等時都採用它,像C/C++、Pascal/Object   Pascal(Delphi)、VB等基本均可視爲編譯語言,而一些網頁腳本、服務器腳本及輔助開發接口這樣的對速度要求不高、對不一樣系統平臺間的兼容性有必定要求的程序則一般使用解釋性語言,如Java、JavaScript、VBScript、Perl、Python等等。 

但既然編譯型與解釋型各有優缺點又相互對立,因此一批新興的語言都有把二者折衷起來的趨勢,例如Java語言雖然比較接近解釋型語言的特徵,但在執行以前已經預先進行一次預編譯,生成的代碼是介於機器碼和Java源代碼之間的中介代碼,運行的時候則由JVM(Java的虛擬機平臺,可視爲解釋器)解釋執行。它既保留了源代碼的高抽象、可移植的特色,又已經完成了對源代碼的大部分預編譯工做,因此執行起來比「純解釋型」程序要快許多。而像VB6(或者之前版本)、C#這樣的語言,雖然表面上看生成的是.exe可執行程序文件,但VB6編譯以後實際生成的也是一種中介碼,只不過編譯器在前面安插了一段自動調用某個外部解釋器的代碼(該解釋程序獨立於用戶編寫的程序,存放於系統的某個DLL文件中,全部以VB6編譯生成的可執行程序都要用到它),以解釋執行實際的程序體。C#(以及其它.net的語言編譯器)則是生成.net目標代碼,實際執行時則由.net解釋系統(就像JVM同樣,也是一個虛擬機平臺)進行執行。固然.net目標代碼已經至關「低級」,比較接近機器語言了,因此仍將其視爲編譯語言,並且其可移植程度也沒有Java號稱的這麼強大,Java號稱是「一次編譯,處處執行」,而.net則是「一次編碼,處處編譯」。呵呵,固然這些都是題外話了。總之,隨着設計技術與硬件的不斷髮展,編譯型與解釋型兩種方式的界限正在不斷變得模糊。

動態語言和靜態語言
一般咱們所說的動態語言、靜態語言是指動態類型語言和靜態類型語言。

(1)動態類型語言:動態類型語言是指在運行期間纔去作數據類型檢查的語言,也就是說,在用動態類型的語言編程時,永遠也不用給任何變量指定數據類型,該語言會在你第一次賦值給變量時,在內部將數據類型記錄下來。Python和Ruby就是一種典型的動態類型語言,其餘的各類腳本語言如VBScript也多少屬於動態類型語言。

(2)靜態類型語言:靜態類型語言與動態類型語言恰好相反,它的數據類型是在編譯其間檢查的,也就是說在寫程序時要聲明全部變量的數據類型,C/C++是靜態類型語言的典型表明,其餘的靜態類型語言還有C#、JAVA等。

 

強類型定義語言和弱類型定義語言

(1)強類型定義語言:強制數據類型定義的語言。也就是說,一旦一個變量被指定了某個數據類型,若是不通過強制轉換,那麼它就永遠是這個數據類型了。舉個例子:若是你定義了一個整型變量a,那麼程序根本不可能將a看成字符串類型處理。強類型定義語言是類型安全的語言。

(2)弱類型定義語言:數據類型能夠被忽略的語言。它與強類型定義語言相反, 一個變量能夠賦不一樣數據類型的值。

強類型定義語言在速度上可能略遜色於弱類型定義語言,可是強類型定義語言帶來的嚴謹性可以有效的避免許多錯誤。另外,「這門語言是否是動態語言」與「這門語言是否類型安全」之間是徹底沒有聯繫的!
例如:Python是動態語言,是強類型定義語言(類型安全的語言); VBScript是動態語言,是弱類型定義語言(類型不安全的語言); JAVA是靜態語言,是強類型定義語言(類型安全的語言)。

 

經過上面這些介紹,咱們能夠得出,python是一門動態解釋性的強類型定義語言。那這些基因使成就了Python的哪些優缺點呢?咱們繼續往下看。

Python的優缺點

先看優勢

  1. Python的定位是「優雅」、「明確」、「簡單」,因此Python程序看上去老是簡單易懂,初學者學Python,不但入門容易,並且未來深刻下去,能夠編寫那些很是很是複雜的程序。
  2. 開發效率很是高,Python有很是強大的第三方庫,基本上你想經過計算機實現任何功能,Python官方庫裏都有相應的模塊進行支持,直接下載調用後,在基礎庫的基礎上再進行開發,大大下降開發週期,避免重複造輪子。
  3. 高級語言————當你用Python語言編寫程序的時候,你無需考慮諸如如何管理你的程序使用的內存一類的底層細節
  4. 可移植性————因爲它的開源本質,Python已經被移植在許多平臺上(通過改動使它可以工 做在不一樣平臺上)。若是你當心地避免使用依賴於系統的特性,那麼你的全部Python程序無需修改就幾乎能夠在市場上全部的系統平臺上運行
  5. 可擴展性————若是你須要你的一段關鍵代碼運行得更快或者但願某些算法不公開,你能夠把你的部分程序用C或C++編寫,而後在你的Python程序中使用它們。
  6. 可嵌入性————你能夠把Python嵌入你的C/C++程序,從而向你的程序用戶提供腳本功能。

再看缺點:

  1. 速度慢,Python 的運行速度相比C語言確實慢不少,跟JAVA相比也要慢一些,所以這也是不少所謂的大牛不屑於使用Python的主要緣由,但其實這裏所指的運行速度慢在大多數狀況下用戶是沒法直接感知到的,必須藉助測試工具才能體現出來,好比你用C運一個程序花了0.1s,用Python是0.01s,這樣C語言直接比Python快了10s,算是很是誇張了,可是你是沒法直接經過肉眼感知的,由於一個正常人所能感知的時間最小單位是0.15-0.4s左右,哈哈。其實在大多數狀況下Python已經徹底能夠知足你對程序速度的要求,除非你要寫對速度要求極高的搜索引擎等,這種狀況下,固然仍是建議你用C去實現的。
  2. 代碼不能加密,由於PYTHON是解釋性語言,它的源碼都是以名文形式存放的,不過我不認爲這算是一個缺點,若是你的項目要求源代碼必須是加密的,那你一開始就不該該用Python來去實現。
  3. 線程不能利用多CPU問題,這是Python被人詬病最多的一個缺點,GIL即全局解釋器鎖(Global Interpreter Lock),是計算機程序設計語言解釋器用於同步線程的工具,使得任什麼時候刻僅有一個線程在執行,Python的線程是操做系統的原生線程。在Linux上爲pthread,在Windows上爲Win thread,徹底由操做系統調度線程的執行。一個python解釋器進程內有一條主線程,以及多條用戶程序的執行線程。即便在多核CPU平臺上,因爲GIL的存在,因此禁止多線程的並行執行。關於這個問題的折衷解決方法,咱們在之後線程和進程章節裏再進行詳細探討。

 

固然,Python還有一些其它的小缺點,在這就不一一列舉了,我想說的是,任何一門語言都不是完美的,都有擅長和不擅長作的事情,建議各位不要拿一個語言的劣勢去跟另外一個語言的優點來去比較,語言只是一個工具,是實現程序設計師思想的工具,就像咱們以前中學學幾什麼時候,有的時候須要要圓規,有的時候須要用三角尺同樣,拿相應的工具去作它最擅長的事纔是正確的選擇。以前不少人問我Shell和Python到底哪一個好?我回答說Shell是個腳本語言,但Python不僅是個腳本語言,能作的事情更多,而後又有鑽牛角尖的人說徹底不必學Python, Python能作的事情Shell均可以作,只要你足夠牛B,而後又舉了用Shell能夠寫俄羅斯方塊這樣的遊戲,對此我能說表達只能是,不要跟SB理論,SB會把你拉到跟他同樣的高度,而後用充分的經驗把你打倒。

 

 

Python解釋器

當咱們編寫Python代碼時,咱們獲得的是一個包含Python代碼的以.py爲擴展名的文本文件。要運行代碼,就須要Python解釋器去執行.py文件。

因爲整個Python語言從規範到解釋器都是開源的,因此理論上,只要水平夠高,任何人均可以編寫Python解釋器來執行Python代碼(固然難度很大)。事實上,確實存在多種Python解釋器。

CPython

當咱們從Python官方網站下載並安裝好Python 2.7後,咱們就直接得到了一個官方版本的解釋器:CPython。這個解釋器是用C語言開發的,因此叫CPython。在命令行下運行python就是啓動CPython解釋器。

CPython是使用最廣的Python解釋器。教程的全部代碼也都在CPython下執行。

IPython

IPython是基於CPython之上的一個交互式解釋器,也就是說,IPython只是在交互方式上有所加強,可是執行Python代碼的功能和CPython是徹底同樣的。比如不少國產瀏覽器雖然外觀不一樣,但內核其實都是調用了IE。

CPython用>>>做爲提示符,而IPython用In [序號]:做爲提示符。

PyPy

PyPy是另外一個Python解釋器,它的目標是執行速度。PyPy採用JIT技術,對Python代碼進行動態編譯(注意不是解釋),因此能夠顯著提升Python代碼的執行速度。

絕大部分Python代碼均可以在PyPy下運行,可是PyPy和CPython有一些是不一樣的,這就致使相同的Python代碼在兩種解釋器下執行可能會有不一樣的結果。若是你的代碼要放到PyPy下執行,就須要瞭解PyPy和CPython的不一樣點

Jython

Jython是運行在Java平臺上的Python解釋器,能夠直接把Python代碼編譯成Java字節碼執行。

IronPython

IronPython和Jython相似,只不過IronPython是運行在微軟.Net平臺上的Python解釋器,能夠直接把Python代碼編譯成.Net的字節碼。

小結

Python的解釋器不少,但使用最普遍的仍是CPython。若是要和Java或.Net平臺交互,最好的辦法不是用Jython或IronPython,而是經過網絡調用來交互,確保各程序之間的獨立性。

 

2、Python發展史 

  • 1989年,爲了打發聖誕節假期,Guido開始寫Python語言的編譯器。Python這個名字,來自Guido所摯愛的電視劇Monty Python’s Flying Circus。他但願這個新的叫作Python的語言,能符合他的理想:創造一種C和shell之間,功能全面,易學易用,可拓展的語言。
  • 1991年,第一個Python編譯器誕生。它是用C語言實現的,並可以調用C語言的庫文件。從一出生,Python已經具備了:類,函數,異常處理,包含表和詞典在內的核心數據類型,以及模塊爲基礎的拓展系統。
  • Granddaddy of Python web frameworks, Zope 1 was released in 1999
  • Python 1.0 - January 1994 增長了 lambdamapfilter and reduce.
  • Python 2.0 - October 16, 2000,加入了內存回收機制,構成了如今Python語言框架的基礎
  • Python 2.4 - November 30, 2004, 同年目前最流行的WEB框架Django 誕生
  • Python 2.5 - September 19, 2006
  • Python 2.6 - October 1, 2008
  • Python 2.7 - July 3, 2010
  • In November 2014, it was announced that Python 2.7 would be supported until 2020, and reaffirmed that there would be no 2.8 release as users were expected to move to Python 3.4+ as soon as possible
  • Python 3.0 - December 3, 2008
  • Python 3.1 - June 27, 2009
  • Python 3.2 - February 20, 2011
  • Python 3.3 - September 29, 2012
  • Python 3.4 - March 16, 2014
  • Python 3.5 - September 13, 2015

3、Python 2 or 3?

In summary : Python 2.x is legacy, Python 3.x is the present and future of the language

Python 3.0 was released in 2008. The final 2.x version 2.7 release came out in mid-2010, with a statement of

extended support for this end-of-life release. The 2.x branch will see no new major releases after that. 3.x is

under active development and has already seen over five years of stable releases, including version 3.3 in 2012,

3.4 in 2014, and 3.5 in 2015. This means that all recent standard library improvements, for example, are only

available by default in Python 3.x.

Guido van Rossum (the original creator of the Python language) decided to clean up Python 2.x properly, with less regard for backwards compatibility than is the case for new releases in the 2.x range. The most drastic improvement is the better Unicode support (with all text strings being Unicode by default) as well as saner bytes/Unicode separation.

Besides, several aspects of the core language (such as print and exec being statements, integers using floor division) have been adjusted to be easier for newcomers to learn and to be more consistent with the rest of the language, and old cruft has been removed (for example, all classes are now new-style, "range()" returns a memory efficient iterable, not a list as in 2.x). 

py2與3的詳細區別

PRINT IS A FUNCTION

The statement has been replaced with a print() function, with keyword arguments to replace most of the special syntax of the old statement (PEP 3105). Examples: 

Old: print "The answer is", 2*2 New: print("The answer is", 2*2)
Old: print x, # Trailing comma suppresses newline New: print(x, end=" ") # Appends a space instead of a newline
Old: print # Prints a newline
New: print() # You must call the function!
Old: print >>sys.stderr, "fatal error" New: print("fatal error", file=sys.stderr)
Old: print (x, y) # prints repr((x, y))
New: print((x, y)) # Not the same as print(x, y)!

You can also customize the separator between items, e.g.: 

print("There are <", 2**32, "> possibilities!", sep="")

ALL IS UNICODE NOW

今後再也不爲討厭的字符編碼而煩惱

 

還能夠這樣玩: (A,*REST,B)=RANGE(5)

>>> a,*rest,b = range(5)
>>> a,rest,b
(0, [1, 2, 3], 4)

  

某些庫更名了

 

Old Name

New Name

_winreg

winreg

ConfigParser

configparser

copy_reg

copyreg

Queue

queue

SocketServer

socketserver

markupbase

_markupbase

repr

reprlib

test.test_support

test.support

  

還有誰不支持PYTHON3?

One popular module that don't yet support Python 3 is Twisted (for networking and other applications). Most

actively maintained libraries have people working on 3.x support. For some libraries, it's more of a priority than

others: Twisted, for example, is mostly focused on production servers, where supporting older versions of

Python is important, let alone supporting a new version that includes major changes to the language. (Twisted is

a prime example of a major package where porting to 3.x is far from trivial 

 

4、Python安裝

windows

一、下載安裝包
    https://www.python.org/downloads/
二、安裝
    默認安裝路徑:C:\python27
三、配置環境變量
    【右鍵計算機】--》【屬性】--》【高級系統設置】--》【高級】--》【環境變量】--》【在第二個內容框中找到 變量名爲Path 的一行,雙擊】 --> 【Python安裝目錄追加到變值值中,用 ; 分割】
    如:原來的值;C:\python27,切記前面有分號

linux、Mac

無需安裝,原裝Python環境
 
ps:若是自帶2.6,請更新至2.7

  

5、Hello World程序

在linux 下建立一個文件叫hello.py,並輸入

print("Hello World!")

而後執行命令:python hello.py ,輸出

localhost:~ jieli$ vim hello.py 
localhost:~ jieli$ python hello.py 
Hello World!

指定解釋器

上一步中執行 python hello.py 時,明確的指出 hello.py 腳本由 python 解釋器來執行。

若是想要相似於執行shell腳本同樣執行python腳本,例: ./hello.py ,那麼就須要在 hello.py 文件的頭部指定解釋器,以下:

#!/usr/bin/env python
 
print "hello,world"

如此一來,執行: ./hello.py 便可。

ps:執行前需給予 hello.py 執行權限,chmod 755 hello.py

在交互器中執行 

除了把程序寫在文件裏,還能夠直接調用python自帶的交互器運行代碼, 

localhost:~ jieli$ python 
Python 2.7.10 (default, Oct 23 2015, 18:05:06) 
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> print("Hello World!")
Hello World!

對比下其它語言的hello world

1 #include <iostream>
2 int main(void)
3 {
4 std::cout<<"Hello world";
5 }
C++
1 #include <stdio.h>
2 int main(void)
3 {
4 printf("\nhello world!");
5 return 0;
6 }
C
1 public class HelloWorld{
2   // 程序的入口
3   public static void main(String args[]){
4     // 向控制檯輸出信息
5     System.out.println("Hello World!");
6   }
7 }
JAVA
1 <?php  
2             echo "hello world!";  
3 ?>  
PHP
1 puts "Hello world."  
RUBY
1 package main
2 
3 import "fmt"
4 
5 func main(){
6 
7     fmt.Printf("Hello World!\n God Bless You!");
8 
9 }
Go

 

6、變量\字符編碼  

Variables are used to store information to be referenced and manipulated in a computer program. They also provide a way of labeling data with a descriptive name, so our programs can be understood more clearly by the reader and ourselves. It is helpful to think of variables as containers that hold information. Their sole purpose is to label and store data in memory. This data can then be used throughout your program.

聲明變量

#_*_coding:utf-8_*_

name = "Alex Li"

上述代碼聲明瞭一個變量,變量名爲: name,變量name的值爲:"Alex Li" 

變量定義的規則:

    • 變量名只能是 字母、數字或下劃線的任意組合
    • 變量名的第一個字符不能是數字
    • 如下關鍵字不能聲明爲變量名
      ['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'exec', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', 'or', 'pass', 'print', 'raise', 'return', 'try', 'while', 'with', 'yield']
變量的賦值
name = "Alex Li"

name2 = name 
print(name,name2)

name = "Jack"

print("What is the value of name2 now?")

 

7、字符編碼

python解釋器在加載 .py 文件中的代碼時,會對內容進行編碼(默認ascill)

ASCII(American Standard Code for Information Interchange,美國標準信息交換代碼)是基於拉丁字母的一套電腦編碼系統,主要用於顯示現代英語和其餘西歐語言,其最多隻能用 8 位來表示(一個字節),即:2**8 = 256-1,因此,ASCII碼最多隻能表示 255 個符號。

 

關於中文

爲了處理漢字,程序員設計了用於簡體中文的GB2312和用於繁體中文的big5。

GB2312(1980年)一共收錄了7445個字符,包括6763個漢字和682個其它符號。漢字區的內碼範圍高字節從B0-F7,低字節從A1-FE,佔用的碼位是72*94=6768。其中有5個空位是D7FA-D7FE。

GB2312 支持的漢字太少。1995年的漢字擴展規範GBK1.0收錄了21886個符號,它分爲漢字區和圖形符號區。漢字區包括21003個字符。2000年的 GB18030是取代GBK1.0的正式國家標準。該標準收錄了27484個漢字,同時還收錄了藏文、蒙文、維吾爾文等主要的少數民族文字。如今的PC平臺必須支持GB18030,對嵌入式產品暫不做要求。因此手機、MP3通常只支持GB2312。

從ASCII、GB23十二、GBK 到GB18030,這些編碼方法是向下兼容的,即同一個字符在這些方案中老是有相同的編碼,後面的標準支持更多的字符。在這些編碼中,英文和中文能夠統一地處理。區分中文編碼的方法是高字節的最高位不爲0。按照程序員的稱呼,GB23十二、GBK到GB18030都屬於雙字節字符集 (DBCS)。

有的中文Windows的缺省內碼仍是GBK,能夠經過GB18030升級包升級到GB18030。不過GB18030相對GBK增長的字符,普通人是很難用到的,一般咱們仍是用GBK指代中文Windows內碼。

 

 

顯然ASCII碼沒法將世界上的各類文字和符號所有表示,因此,就須要新出一種能夠表明全部字符和符號的編碼,即:Unicode

Unicode(統一碼、萬國碼、單一碼)是一種在計算機上使用的字符編碼。Unicode 是爲了解決傳統的字符編碼方案的侷限而產生的,它爲每種語言中的每一個字符設定了統一而且惟一的二進制編碼,規定雖有的字符和符號最少由 16 位來表示(2個字節),即:2 **16 = 65536,
注:此處說的的是最少2個字節,可能更多

UTF-8,是對Unicode編碼的壓縮和優化,他再也不使用最少使用2個字節,而是將全部的字符和符號進行分類:ascii碼中的內容用1個字節保存、歐洲的字符用2個字節保存,東亞的字符用3個字節保存...

因此,python解釋器在加載 .py 文件中的代碼時,會對內容進行編碼(默認ascill),若是是以下代碼的話:

報錯:ascii碼沒法表示中文

#!/usr/bin/env python
 
print "你好,世界" 

改正:應該顯示的告訴python解釋器,用什麼編碼來執行源代碼,即:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
print "你好,世界"

註釋

  當行注視:# 被註釋內容

  多行註釋:""" 被註釋內容 """

  

  

 

8、用戶輸入 

#!/usr/bin/env python 
#_*_coding:utf-8_*_


#name = raw_input("What is your name?") #only on python 2.x
name = input("What is your name?")
print("Hello " + name )

輸入密碼時,若是想要不可見,須要利用getpass 模塊中的 getpass方法,即:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
import getpass
 
# 將用戶輸入的內容賦值給 name 變量
pwd = getpass.getpass("請輸入密碼:")
 
# 打印輸入的內容
print(pwd)

 

9、模塊初識  

Python的強大之處在於他有很是豐富和強大的標準庫和第三方庫,幾乎你想實現的任何功能都有相應的Python庫支持,之後的課程中會深刻講解經常使用到的各類庫,如今,咱們先來象徵性的學2個簡單的。

sys

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys

print(sys.argv)


#輸出
$ python test.py helo world 
['test.py', 'helo', 'world']  #把執行腳本時傳遞的參數獲取到了

  

os

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os

os.system("df -h") #調用系統命令

徹底結合一下  

import os,sys

os.system(''.join(sys.argv[1:])) #把用戶的輸入的參數看成一條命令交給os.system來執行

本身寫個模塊

python tab補全模塊

1 import sys
2 import readline
3 import rlcompleter
4 
5 if sys.platform == 'darwin' and sys.version_info[0] == 2:
6     readline.parse_and_bind("bind ^I rl_complete")
7 else:
8     readline.parse_and_bind("tab: complete")  # linux and python3 on mac
for mac
 1 #!/usr/bin/env python 
 2 # python startup file 
 3 import sys
 4 import readline
 5 import rlcompleter
 6 import atexit
 7 import os
 8 # tab completion 
 9 readline.parse_and_bind('tab: complete')
10 # history file 
11 histfile = os.path.join(os.environ['HOME'], '.pythonhistory')
12 try:
13     readline.read_history_file(histfile)
14 except IOError:
15     pass
16 atexit.register(readline.write_history_file, histfile)
17 del os, histfile, readline, rlcompleter
for Linux

寫完保存後就能夠使用了

localhost:~ jieli$ python 
Python 2.7.10 (default, Oct 23 2015, 18:05:06) 
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import tab

你會發現,上面本身寫的tab.py模塊只能在當前目錄下導入,若是想在系統的何何一個地方都使用怎麼辦呢? 此時你就要把這個tab.py放到python全局環境變量目錄裏啦,基本通常都放在一個叫 Python/2.7/site-packages 目錄下,這個目錄在不一樣的OS裏放的位置不同,用 print(sys.path) 能夠查看python環境變量列表。

  

10、.pyc是個什麼鬼?

1. Python是一門解釋型語言?

我初學Python時,聽到的關於Python的第一句話就是,Python是一門解釋性語言,我就這樣一直相信下去,直到發現了*.pyc文件的存在。若是是解釋型語言,那麼生成的*.pyc文件是什麼呢?c應該是compiled的縮寫纔對啊!

爲了防止其餘學習Python的人也被這句話誤解,那麼咱們就在文中來澄清下這個問題,而且把一些基礎概念給理清。

  

2. 解釋型語言和編譯型語言 

計算機是不可以識別高級語言的,因此當咱們運行一個高級語言程序的時候,就須要一個「翻譯機」來從事把高級語言轉變成計算機能讀懂的機器語言的過程。這個過程分紅兩類,第一種是編譯,第二種是解釋。

編譯型語言在程序執行以前,先會經過編譯器對程序執行一個編譯的過程,把程序轉變成機器語言。運行時就不須要翻譯,而直接執行就能夠了。最典型的例子就是C語言。

解釋型語言就沒有這個編譯的過程,而是在程序運行的時候,經過解釋器對程序逐行做出解釋,而後直接運行,最典型的例子是Ruby。

經過以上的例子,咱們能夠來總結一下解釋型語言和編譯型語言的優缺點,由於編譯型語言在程序運行以前就已經對程序作出了「翻譯」,因此在運行時就少掉了「翻譯」的過程,因此效率比較高。可是咱們也不能一律而論,一些解釋型語言也能夠經過解釋器的優化來在對程序作出翻譯時對整個程序作出優化,從而在效率上超過編譯型語言。

此外,隨着Java等基於虛擬機的語言的興起,咱們又不能把語言純粹地分紅解釋型和編譯型這兩種。

用Java來舉例,Java首先是經過編譯器編譯成字節碼文件,而後在運行時經過解釋器給解釋成機器文件。因此咱們說Java是一種先編譯後解釋的語言。

 

3. Python究竟是什麼 

其實Python和Java/C#同樣,也是一門基於虛擬機的語言,咱們先來從表面上簡單地瞭解一下Python程序的運行過程吧。

當咱們在命令行中輸入python hello.py時,實際上是激活了Python的「解釋器」,告訴「解釋器」:你要開始工做了。但是在「解釋」以前,其實執行的第一項工做和Java同樣,是編譯。

熟悉Java的同窗能夠想一下咱們在命令行中如何執行一個Java的程序:

javac hello.java

java hello

 

只是咱們在用Eclipse之類的IDE時,將這兩部給融合成了一部而已。其實Python也同樣,當咱們執行python hello.py時,他也同樣執行了這麼一個過程,因此咱們應該這樣來描述Python,Python是一門先編譯後解釋的語言。

4. 簡述Python的運行過程

在說這個問題以前,咱們先來講兩個概念,PyCodeObject和pyc文件。

咱們在硬盤上看到的pyc天然沒必要多說,而其實PyCodeObject則是Python編譯器真正編譯成的結果。咱們先簡單知道就能夠了,繼續向下看。

當python程序運行時,編譯的結果則是保存在位於內存中的PyCodeObject中,當Python程序運行結束時,Python解釋器則將PyCodeObject寫回到pyc文件中。

當python程序第二次運行時,首先程序會在硬盤中尋找pyc文件,若是找到,則直接載入,不然就重複上面的過程。

因此咱們應該這樣來定位PyCodeObject和pyc文件,咱們說pyc文件實際上是PyCodeObject的一種持久化保存方式。

 

11、數據類型初識 

一、數字

2 是一個整數的例子。
長整數 不過是大一些的整數。
3.23和52.3E-4是浮點數的例子。E標記表示10的冪。在這裏,52.3E-4表示52.3 * 10-4。
(-5+4j)和(2.3-4.6j)是複數的例子,其中-5,4爲實數,j爲虛數,數學中表示覆數是什麼?。

int(整型)

  在32位機器上,整數的位數爲32位,取值範圍爲-2**31~2**31-1,即-2147483648~2147483647
  在64位系統上,整數的位數爲64位,取值範圍爲-2**63~2**63-1,即-9223372036854775808~9223372036854775807
long(長整型)
  跟C語言不一樣,Python的長整數沒有指定位寬,即:Python沒有限制長整數數值的大小,但實際上因爲機器內存有限,咱們使用的長整數數值不可能無限大。
  注意,自從Python2.2起,若是整數發生溢出,Python會自動將整數數據轉換爲長整數,因此現在在長整數數據後面不加字母L也不會致使嚴重後果了。
float(浮點型)
      先掃盲 http://www.cnblogs.com/alex3714/articles/5895848.html 
  浮點數用來處理實數,即帶有小數的數字。相似於C語言中的double類型,佔8個字節(64位),其中52位表示底,11位表示指數,剩下的一位表示符號。
complex(複數)
  複數由實數部分和虛數部分組成,通常形式爲x+yj,其中的x是複數的實數部分,y是複數的虛數部分,這裏的x和y都是實數。
注:Python中存在小數字池:-5 ~ 257
 
二、布爾值
  真或假
  1 或 0
三、字符串
"hello world"
萬惡的字符串拼接:
  python中的字符串在C語言中體現爲是一個字符數組,每次建立字符串時候須要在內存中開闢一塊連續的空,而且一旦須要修改字符串的話,就須要再次開闢空間,萬惡的+號每出現一次就會在內從中從新開闢一塊空間。
字符串格式化輸出
name = "alex"
print "i am %s " % name
 
#輸出: i am alex

PS: 字符串是 %s;整數 %d;浮點數%f

字符串經常使用功能:
  • 移除空白
  • 分割
  • 長度
  • 索引
  • 切片
四、列表
建立列表:
name_list = ['alex', 'seven', 'eric']
或
name_list = list(['alex', 'seven', 'eric'])

基本操做:

  • 索引
  • 切片
  • 追加
  • 刪除
  • 長度
  • 切片
  • 循環
  • 包含
五、元組(不可變列表)
建立元組:
ages = (11, 22, 33, 44, 55)
或
ages = tuple((11, 22, 33, 44, 55))
 
六、字典(無序)
建立字典:
person = {"name": "mr.wu", 'age': 18}
或
person = dict({"name": "mr.wu", 'age': 18})

經常使用操做:

  • 索引
  • 新增
  • 刪除
  • 鍵、值、鍵值對
  • 循環
  • 長度

12、數據運算  

算數運算:

比較運算:

賦值運算:

邏輯運算:

成員運算:

身份運算:

位運算:

#!/usr/bin/python
 
a = 60            # 60 = 0011 1100
b = 13            # 13 = 0000 1101
c = 0
 
c = a & b;        # 12 = 0000 1100
print "Line 1 - Value of c is ", c
 
c = a | b;        # 61 = 0011 1101
print "Line 2 - Value of c is ", c
 
c = a ^ b;        # 49 = 0011 0001
print "Line 3 - Value of c is ", c
 
c = ~a;           # -61 = 1100 0011
print "Line 4 - Value of c is ", c
 
c = a << 2;       # 240 = 1111 0000
print "Line 5 - Value of c is ", c
 
c = a >> 2;       # 15 = 0000 1111
print "Line 6 - Value of c is ", c

*按位取反運算規則(按位取反再加1)   詳解http://blog.csdn.net/wenxinwukui234/article/details/42119265

 

運算符優先級:

更多內容:猛擊這裏

  

十3、表達式if ... else

場景1、用戶登錄驗證

# 提示輸入用戶名和密碼
 
# 驗證用戶名和密碼
#     若是錯誤,則輸出用戶名或密碼錯誤
#     若是成功,則輸出 歡迎,XXX!


#!/usr/bin/env python
# -*- coding: encoding -*-
 
import getpass
 
 
name = raw_input('請輸入用戶名:')
pwd = getpass.getpass('請輸入密碼:')
 
if name == "alex" and pwd == "cmd":
    print("歡迎,alex!")
else:
    print("用戶名和密碼錯誤")

場景2、猜年齡遊戲

在程序裏設定好你的年齡,而後啓動程序讓用戶猜想,用戶輸入後,根據他的輸入提示用戶輸入的是否正確,若是錯誤,提示是猜大了仍是小了

#!/usr/bin/env python
# -*- coding: utf-8 -*-


my_age = 28

user_input = int(input("input your guess num:"))

if user_input == my_age:
    print("Congratulations, you got it !")
elif user_input < my_age:
    print("Oops,think bigger!")
else:
    print("think smaller!")

  

外層變量,能夠被內層代碼使用
內層變量,不該被外層代碼使用

 

十4、表達式for loop

最簡單的循環10次

#_*_coding:utf-8_*_
__author__ = 'Alex Li'


for i in range(10):
    print("loop:", i )

輸出:

loop: 0
loop: 1
loop: 2
loop: 3
loop: 4
loop: 5
loop: 6
loop: 7
loop: 8
loop: 9

需求一:仍是上面的程序,可是遇到小於5的循環次數就不走了,直接跳入下一次循環

for i in range(10):
    if i<5:
        continue #不往下走了,直接進入下一次loop 
    print("loop:", i )

需求二:仍是上面的程序,可是遇到大於5的循環次數就不走了,直接退出

for i in range(10):
    if i>5:
        break #不往下走了,直接跳出整個loop
    print("loop:", i )

 

十5、while loop   

 有一種循環叫死循環,一經觸發,就運行個天荒地老、海枯石爛。

海枯石爛代碼

count = 0
while True:
    print("你是風兒我是沙,纏纏綿綿到天涯...",count)
    count +=1
    

 

其實除了時間,沒有什麼是永恆的,死loop仍是少寫爲好 

上面的代碼循環100次就退出吧

 

count = 0
while True:
    print("你是風兒我是沙,纏纏綿綿到天涯...",count)
    count +=1
    if count == 100:
        print("去你媽的風和沙,大家這些脫了褲子是人,穿上褲子是鬼的臭男人..")
        break
        

 

 

回到上面for 循環的例子,如何實現讓用戶不斷的猜年齡,但只給最多3次機會,再猜不對就退出程序。

#!/usr/bin/env python
# -*- coding: utf-8 -*-


my_age = 28

count = 0
while count < 3:
    user_input = int(input("input your guess num:"))

    if user_input == my_age:
        print("Congratulations, you got it !")
        break
    elif user_input < my_age:
        print("Oops,think bigger!")
    else:
        print("think smaller!")
    count += 1 #每次loop 計數器+1
else:
    print("猜這麼屢次都不對,你個笨蛋.")

  

  

十6、做業 

做業一:博客

做業二:編寫登錄接口

  • 輸入用戶名密碼
  • 認證成功後顯示歡迎信息
  • 輸錯三次後鎖定

 

做業三:多級菜單
  • 三級菜單
  • 可依次選擇進入各子菜單
  • 所需新知識點:列表、字典

  

  

  

 

 

  

  

 

  

 

入門知識拾遺

1、bytes類型

 

2、三元運算

1
result  =  1  if  條件  else  2

若是條件爲真:result = 值1
若是條件爲假:result = 值2

3、進制

  • 二進制,01
  • 八進制,01234567
  • 十進制,0123456789
  • 十六進制,0123456789ABCDEF  二進制到16進制轉換http://jingyan.baidu.com/album/47a29f24292608c0142399cb.html?picindex=1

4、 一切皆對象

對於Python,一切事物都是對象,對象基於類建立

因此,如下這些值都是對象: "wupeiqi"、3八、['北京', '上海', '深圳'],而且是根據不一樣的類生成的對象。

1. 列表、元組操做

列表是咱們最之後最經常使用的數據類型之一,經過列表能夠對數據實現最方便的存儲、修改等操做

定義列表

names = ['Alex',"Tenglan",'Eric']

經過下標訪問列表中的元素,下標從0開始計數

>>> names[0]
'Alex'
>>> names[2]
'Eric'
>>> names[-1]
'Eric'
>>> names[-2] #還能夠倒着取
'Tenglan'

切片:取多個元素  

>>> names = ["Alex","Tenglan","Eric","Rain","Tom","Amy"]
>>> names[1:4]  #取下標1至下標4之間的數字,包括1,不包括4
['Tenglan', 'Eric', 'Rain']
>>> names[1:-1] #取下標1至-1的值,不包括-1
['Tenglan', 'Eric', 'Rain', 'Tom']
>>> names[0:3] 
['Alex', 'Tenglan', 'Eric']
>>> names[:3] #若是是從頭開始取,0能夠忽略,跟上句效果同樣
['Alex', 'Tenglan', 'Eric']
>>> names[3:] #若是想取最後一個,必須不能寫-1,只能這麼寫
['Rain', 'Tom', 'Amy'] 
>>> names[3:-1] #這樣-1就不會被包含了
['Rain', 'Tom']
>>> names[0::2] #後面的2是表明,每隔一個元素,就取一個
['Alex', 'Eric', 'Tom'] 
>>> names[::2] #和上句效果同樣
['Alex', 'Eric', 'Tom']
View Code

追加

>>> names
['Alex', 'Tenglan', 'Eric', 'Rain', 'Tom', 'Amy']
>>> names.append("我是新來的")
>>> names
['Alex', 'Tenglan', 'Eric', 'Rain', 'Tom', 'Amy', '我是新來的']
View Code

插入

>>> names
['Alex', 'Tenglan', 'Eric', 'Rain', 'Tom', 'Amy', '我是新來的']
>>> names.insert(2,"強行從Eric前面插入")
>>> names
['Alex', 'Tenglan', '強行從Eric前面插入', 'Eric', 'Rain', 'Tom', 'Amy', '我是新來的']

>>> names.insert(5,"從eric後面插入試試新姿式")
>>> names
['Alex', 'Tenglan', '強行從Eric前面插入', 'Eric', 'Rain', '從eric後面插入試試新姿式', 'Tom', 'Amy', '我是新來的']
View Code

修改

>>> names
['Alex', 'Tenglan', '強行從Eric前面插入', 'Eric', 'Rain', '從eric後面插入試試新姿式', 'Tom', 'Amy', '我是新來的']
>>> names[2] = "該換人了"
>>> names
['Alex', 'Tenglan', '該換人了', 'Eric', 'Rain', '從eric後面插入試試新姿式', 'Tom', 'Amy', '我是新來的']
View Code

刪除

>>> del names[2] 
>>> names
['Alex', 'Tenglan', 'Eric', 'Rain', '從eric後面插入試試新姿式', 'Tom', 'Amy', '我是新來的']
>>> del names[4]
>>> names
['Alex', 'Tenglan', 'Eric', 'Rain', 'Tom', 'Amy', '我是新來的']
>>> 
>>> names.remove("Eric") #刪除指定元素
>>> names
['Alex', 'Tenglan', 'Rain', 'Tom', 'Amy', '我是新來的']
>>> names.pop() #刪除列表最後一個值 
'我是新來的'
>>> names
['Alex', 'Tenglan', 'Rain', 'Tom', 'Amy']
View Code

擴展

>>> names
['Alex', 'Tenglan', 'Rain', 'Tom', 'Amy']
>>> b = [1,2,3]
>>> names.extend(b)
>>> names
['Alex', 'Tenglan', 'Rain', 'Tom', 'Amy', 1, 2, 3]
View Code

拷貝

>>> names
['Alex', 'Tenglan', 'Rain', 'Tom', 'Amy', 1, 2, 3]

>>> name_copy = names.copy()
>>> name_copy
['Alex', 'Tenglan', 'Rain', 'Tom', 'Amy', 1, 2, 3]
View Code

copy真的這麼簡單麼?那我還講個屁。。。

統計

>>> names
['Alex', 'Tenglan', 'Amy', 'Tom', 'Amy', 1, 2, 3]
>>> names.count("Amy")
2
View Code

排序&翻轉

>>> names
['Alex', 'Tenglan', 'Amy', 'Tom', 'Amy', 1, 2, 3]
>>> names.sort() #排序
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: int() < str()   #3.0裏不一樣數據類型不能放在一塊兒排序了,擦
>>> names[-3] = '1'
>>> names[-2] = '2'
>>> names[-1] = '3'
>>> names
['Alex', 'Amy', 'Amy', 'Tenglan', 'Tom', '1', '2', '3']
>>> names.sort()
>>> names
['1', '2', '3', 'Alex', 'Amy', 'Amy', 'Tenglan', 'Tom']

>>> names.reverse() #反轉
>>> names
['Tom', 'Tenglan', 'Amy', 'Amy', 'Alex', '3', '2', '1']
View Code

獲取下標

>>> names ['Tom', 'Tenglan', 'Amy', 'Amy', 'Alex', '3', '2', '1'] >>> names.index("Amy") 2 #只返回找到的第一個下標
View Code

元組

元組其實跟列表差很少,也是存一組數,只不是它一旦建立,便不能再修改,因此又叫只讀列表

語法

 names = ("alex","jack","eric")

它只有2個方法,一個是count,一個是index,完畢。  

程序練習 

請閉眼寫出如下程序。

程序:購物車程序

需求:

  1. 啓動程序後,讓用戶輸入工資,而後打印商品列表
  2. 容許用戶根據商品編號購買商品
  3. 用戶選擇商品後,檢測餘額是否夠,夠就直接扣款,不夠就提醒 
  4. 可隨時退出,退出時,打印已購買商品和餘額

 

2. 字符串操做    

>>> n3_arg
{'name': 'alex', 'age': 33}
>>> n3
'my name is {name} and age is {age}'
>>> n3.format_map(n3_arg)
'my name is alex and age is 33'


>>> n4.ljust(40,"-")
'Hello 2orld-----------------------------'
>>> n4.rjust(40,"-")
'-----------------------------Hello 2orld'


>>> s = "Hello World!"
>>> p = str.maketrans("abcdefg","3!@#$%^")
>>> s.translate(p)
'H$llo Worl#!


>>> b="ddefdsdff_哈哈" 
>>> b.isidentifier() #檢測一段字符串能否被看成標誌符,便是否符合變量命名規則
True
一些蛋疼的語法

 

3. 字典操做

字典一種key - value 的數據類型,使用就像咱們上學用的字典,經過筆劃、字母來查對應頁的詳細內容。

語法:

info = {
    'stu1101': "TengLan Wu",
    'stu1102': "LongZe Luola",
    'stu1103': "XiaoZe Maliya",
}

字典的特性:

  • dict是無序的
  • key必須是惟一的,so 天生去重

增長

>>> info["stu1104"] = "蒼井空"
>>> info
{'stu1102': 'LongZe Luola', 'stu1104': '蒼井空', 'stu1103': 'XiaoZe Maliya', 'stu1101': 'TengLan Wu'}
View Code

修改

>>> info['stu1101'] = "武藤蘭"
>>> info
{'stu1102': 'LongZe Luola', 'stu1103': 'XiaoZe Maliya', 'stu1101': '武藤蘭'}
View Code

刪除

>>> info
{'stu1102': 'LongZe Luola', 'stu1103': 'XiaoZe Maliya', 'stu1101': '武藤蘭'}
>>> info.pop("stu1101") #標準刪除姿式
'武藤蘭'
>>> info
{'stu1102': 'LongZe Luola', 'stu1103': 'XiaoZe Maliya'}
>>> del info['stu1103'] #換個姿式刪除
>>> info
{'stu1102': 'LongZe Luola'}
>>> 
>>> 
>>> 
>>> info = {'stu1102': 'LongZe Luola', 'stu1103': 'XiaoZe Maliya'}
>>> info
{'stu1102': 'LongZe Luola', 'stu1103': 'XiaoZe Maliya'} #隨機刪除
>>> info.popitem()
('stu1102', 'LongZe Luola')
>>> info
{'stu1103': 'XiaoZe Maliya'}
View Code

查找

>>> info = {'stu1102': 'LongZe Luola', 'stu1103': 'XiaoZe Maliya'}
>>> 
>>> "stu1102" in info #標準用法
True
>>> info.get("stu1102")  #獲取
'LongZe Luola'
>>> info["stu1102"] #同上,可是看下面
'LongZe Luola'
>>> info["stu1105"]  #若是一個key不存在,就報錯,get不會,不存在只返回None
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'stu1105'
View Code

多級字典嵌套及操做

av_catalog = {
    "歐美":{
        "www.youporn.com": ["不少免費的,世界最大的","質量通常"],
        "www.pornhub.com": ["不少免費的,也很大","質量比yourporn高點"],
        "letmedothistoyou.com": ["可能是自拍,高質量圖片不少","資源很少,更新慢"],
        "x-art.com":["質量很高,真的很高","所有收費,屌比請繞過"]
    },
    "日韓":{
        "tokyo-hot":["質量怎樣不清楚,我的已經不喜歡日韓範了","據說是收費的"]
    },
    "大陸":{
        "1024":["所有免費,真好,好人一輩子平安","服務器在國外,慢"]
    }
}

av_catalog["大陸"]["1024"][1] += ",能夠用爬蟲爬下來"
print(av_catalog["大陸"]["1024"])
#ouput 
['所有免費,真好,好人一輩子平安', '服務器在國外,慢,能夠用爬蟲爬下來']
View Code

 

其它姿式

#values
>>> info.values()
dict_values(['LongZe Luola', 'XiaoZe Maliya'])

#keys
>>> info.keys()
dict_keys(['stu1102', 'stu1103'])


#setdefault
>>> info.setdefault("stu1106","Alex")
'Alex'
>>> info
{'stu1102': 'LongZe Luola', 'stu1103': 'XiaoZe Maliya', 'stu1106': 'Alex'}
>>> info.setdefault("stu1102","龍澤蘿拉")
'LongZe Luola'
>>> info
{'stu1102': 'LongZe Luola', 'stu1103': 'XiaoZe Maliya', 'stu1106': 'Alex'}


#update 
>>> info
{'stu1102': 'LongZe Luola', 'stu1103': 'XiaoZe Maliya', 'stu1106': 'Alex'}
>>> b = {1:2,3:4, "stu1102":"龍澤蘿拉"}
>>> info.update(b)
>>> info
{'stu1102': '龍澤蘿拉', 1: 2, 3: 4, 'stu1103': 'XiaoZe Maliya', 'stu1106': 'Alex'}

#items
info.items()
dict_items([('stu1102', '龍澤蘿拉'), (1, 2), (3, 4), ('stu1103', 'XiaoZe Maliya'), ('stu1106', 'Alex')])


#經過一個列表生成默認dict,有個沒辦法解釋的坑,少用吧這個
>>> dict.fromkeys([1,2,3],'testd')
{1: 'testd', 2: 'testd', 3: 'testd'}
View Code

循環dict 

#方法1
for key in info:
    print(key,info[key])

#方法2
for k,v in info.items(): #會先把dict轉成list,數據裏大時莫用
    print(k,v)

程序練習

程序: 三級菜單

要求: 

  1. 打印省、市、縣三級菜單
  2. 可返回上一級
  3. 可隨時退出程序

 

menu = {
    '北京':{
        '海淀':{
            '五道口':{
                'soho':{},
                '網易':{},
                'google':{}
            },
            '中關村':{
                '愛奇藝':{},
                '汽車之家':{},
                'youku':{},
            },
            '上地':{
                '百度':{},
            },
        },
        '昌平':{
            '沙河':{
                '老男孩':{},
                '北航':{},
            },
            '天通苑':{},
            '回龍觀':{},
        },
        '朝陽':{},
        '東城':{},
    },
    '上海':{
        '閔行':{
            "人民廣場":{
                '炸雞店':{}
            }
        },
        '閘北':{
            '火車戰':{
                '攜程':{}
            }
        },
        '浦東':{},
    },
    '山東':{},
}


exit_flag = False
current_layer = menu

layers = [menu]

while not  exit_flag:
    for k in current_layer:
        print(k)
    choice = input(">>:").strip()
    if choice == "b":
        current_layer = layers[-1]
        #print("change to laster", current_layer)
        layers.pop()
    elif choice not  in current_layer:continue
    else:
        layers.append(current_layer)
        current_layer = current_layer[choice]
三年菜單文藝青年版

 

 

4.集合操做

集合是一個無序的,不重複的數據組合,它的主要做用以下:

  • 去重,把一個列表變成集合,就自動去重了
  • 關係測試,測試兩組數據以前的交集、差集、並集等關係

經常使用操做

s = set([3,5,9,10])      #建立一個數值集合  
  
t = set("Hello")         #建立一個惟一字符的集合  


a = t | s          # t 和 s的並集  
  
b = t & s          # t 和 s的交集  
  
c = t – s          # 求差集(項在t中,但不在s中)  
  
d = t ^ s          # 對稱差集(項在t或s中,但不會同時出如今兩者中)  
  
   
  
基本操做:  
  
t.add('x')            # 添加一項  
  
s.update([10,37,42])  # 在s中添加多項  
  
   
  
使用remove()能夠刪除一項:  
  
t.remove('H')  
  
  
len(s)  
set 的長度  
  
x in s  
測試 x 是不是 s 的成員  
  
x not in s  
測試 x 是否不是 s 的成員  
  
s.issubset(t)  
s <= t  
測試是否 s 中的每個元素都在 t 中  
  
s.issuperset(t)  
s >= t  
測試是否 t 中的每個元素都在 s 中  
  
s.union(t)  
s | t  
返回一個新的 set 包含 s 和 t 中的每個元素  
  
s.intersection(t)  
s & t  
返回一個新的 set 包含 s 和 t 中的公共元素  
  
s.difference(t)  
s - t  
返回一個新的 set 包含 s 中有可是 t 中沒有的元素  
  
s.symmetric_difference(t)  
s ^ t  
返回一個新的 set 包含 s 和 t 中不重複的元素  
  
s.copy()  
返回 set 「s」的一個淺複製  
View Code

 

5. 文件操做

對文件操做流程

  1. 打開文件,獲得文件句柄並賦值給一個變量
  2. 經過句柄對文件進行操做
  3. 關閉文件 

現有文件以下 

Somehow, it seems the love I knew was always the most destructive kind
不知爲什麼,我經歷的愛情老是最具毀滅性的的那種
Yesterday when I was young
昨日當我年少輕狂
The taste of life was sweet
生命的滋味是甜的
As rain upon my tongue
就如舌尖上的雨露
I teased at life as if it were a foolish game
我戲弄生命 視其爲愚蠢的遊戲
The way the evening breeze
就如夜晚的微風
May tease the candle flame
逗弄蠟燭的火苗
The thousand dreams I dreamed
我曾千萬次夢見
The splendid things I planned
那些我計劃的絢麗藍圖
I always built to last on weak and shifting sand
但我老是將之建築在易逝的流沙上
I lived by night and shunned the naked light of day
我夜夜笙歌 逃避白晝赤裸的陽光
And only now I see how the time ran away
事到現在我纔看清歲月是如何匆匆流逝
Yesterday when I was young
昨日當我年少輕狂
So many lovely songs were waiting to be sung
有那麼多甜美的曲兒等我歌唱
So many wild pleasures lay in store for me
有那麼多肆意的快樂等我享受
And so much pain my eyes refused to see
還有那麼多痛苦 個人雙眼卻視而不見
I ran so fast that time and youth at last ran out
我飛快地奔走 最終時光與青春消逝殆盡
I never stopped to think what life was all about
我從未停下腳步去思考生命的意義
And every conversation that I can now recall
現在回想起的全部對話
Concerned itself with me and nothing else at all
除了和我相關的 什麼都記不得了
The game of love I played with arrogance and pride
我用自負和傲慢玩着愛情的遊戲
And every flame I lit too quickly, quickly died
全部我點燃的火焰都熄滅得太快
The friends I made all somehow seemed to slip away
全部我交的朋友彷佛都不知不覺地離開了
And only now I'm left alone to end the play, yeah
只剩我一我的在臺上來結束這場鬧劇
Oh, yesterday when I was young
噢 昨日當我年少輕狂
So many, many songs were waiting to be sung
有那麼那麼多甜美的曲兒等我歌唱
So many wild pleasures lay in store for me
有那麼多肆意的快樂等我享受
And so much pain my eyes refused to see
還有那麼多痛苦 個人雙眼卻視而不見
There are so many songs in me that won't be sung
我有太多歌曲永遠不會被唱起
I feel the bitter taste of tears upon my tongue
我嚐到了舌尖淚水的苦澀滋味
The time has come for me to pay for yesterday
終於到了付出代價的時間 爲了昨日
When I was young
當我年少輕狂

基本操做  

f = open('lyrics') #打開文件
first_line = f.readline()
print('first line:',first_line) #讀一行
print('我是分隔線'.center(50,'-'))
data = f.read()# 讀取剩下的全部內容,文件大時不要用
print(data) #打印文件

f.close() #關閉文件

打開文件的模式有:

  • r,只讀模式(默認)。
  • w,只寫模式。【不可讀;不存在則建立;存在則刪除內容;】
  • a,追加模式。【可讀;   不存在則建立;存在則只追加內容;】

"+" 表示能夠同時讀寫某個文件

  • r+,可讀寫文件。【可讀;可寫;可追加】
  • w+,寫讀
  • a+,同a

"U"表示在讀取時,能夠將 \r \n \r\n自動轉換成 \n (與 r 或 r+ 模式同使用)

  • rU
  • r+U

"b"表示處理二進制文件(如:FTP發送上傳ISO鏡像文件,linux可忽略,windows處理二進制文件時需標註)

  • rb
  • wb
  • ab

其它語法

    def close(self): # real signature unknown; restored from __doc__
        """
        Close the file.
        
        A closed file cannot be used for further I/O operations.  close() may be
        called more than once without error.
        """
        pass

    def fileno(self, *args, **kwargs): # real signature unknown
        """ Return the underlying file descriptor (an integer). """
        pass

    def isatty(self, *args, **kwargs): # real signature unknown
        """ True if the file is connected to a TTY device. """
        pass

    def read(self, size=-1): # known case of _io.FileIO.read
        """
        注意,不必定能全讀回來
        Read at most size bytes, returned as bytes.
        
        Only makes one system call, so less data may be returned than requested.
        In non-blocking mode, returns None if no data is available.
        Return an empty bytes object at EOF.
        """
        return ""

    def readable(self, *args, **kwargs): # real signature unknown
        """ True if file was opened in a read mode. """
        pass

    def readall(self, *args, **kwargs): # real signature unknown
        """
        Read all data from the file, returned as bytes.
        
        In non-blocking mode, returns as much as is immediately available,
        or None if no data is available.  Return an empty bytes object at EOF.
        """
        pass

    def readinto(self): # real signature unknown; restored from __doc__
        """ Same as RawIOBase.readinto(). """
        pass #不要用,沒人知道它是幹嗎用的

    def seek(self, *args, **kwargs): # real signature unknown
        """
        Move to new file position and return the file position.
        
        Argument offset is a byte count.  Optional argument whence defaults to
        SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values
        are SEEK_CUR or 1 (move relative to current position, positive or negative),
        and SEEK_END or 2 (move relative to end of file, usually negative, although
        many platforms allow seeking beyond the end of a file).
        
        Note that not all file objects are seekable.
        """
        pass

    def seekable(self, *args, **kwargs): # real signature unknown
        """ True if file supports random-access. """
        pass

    def tell(self, *args, **kwargs): # real signature unknown
        """
        Current file position.
        
        Can raise OSError for non seekable files.
        """
        pass

    def truncate(self, *args, **kwargs): # real signature unknown
        """
        Truncate the file to at most size bytes and return the truncated size.
        
        Size defaults to the current file position, as returned by tell().
        The current file position is changed to the value of size.
        """
        pass

    def writable(self, *args, **kwargs): # real signature unknown
        """ True if file was opened in a write mode. """
        pass

    def write(self, *args, **kwargs): # real signature unknown
        """
        Write bytes b to file, return number written.
        
        Only makes one system call, so not all of the data may be written.
        The number of bytes actually written is returned.  In non-blocking mode,
        returns None if the write would block.
        """
        pass

with語句

爲了不打開文件後忘記關閉,能夠經過管理上下文,即:

1
2
3
with  open ( 'log' , 'r' ) as f:
     
     ...

如此方式,當with代碼塊執行完畢時,內部會自動關閉並釋放文件資源。

在Python 2.7 後,with又支持同時對多個文件的上下文進行管理,即:

1
2
with  open ( 'log1' ) as obj1,  open ( 'log2' ) as obj2:
     pass

 

 

程序練習  

程序1: 實現簡單的shell sed替換功能

程序2:修改haproxy配置文件 

需求:

1、查
    輸入:www.oldboy.org
    獲取當前backend下的全部記錄

2、新建
    輸入:
        arg = {
            'bakend': 'www.oldboy.org',
            'record':{
                'server': '100.1.7.9',
                'weight': 20,
                'maxconn': 30
            }
        }

3、刪除
    輸入:
        arg = {
            'bakend': 'www.oldboy.org',
            'record':{
                'server': '100.1.7.9',
                'weight': 20,
                'maxconn': 30
            }
        }
需求
global       
        log 127.0.0.1 local2
        daemon
        maxconn 256
        log 127.0.0.1 local2 info
defaults
        log global
        mode http
        timeout connect 5000ms
        timeout client 50000ms
        timeout server 50000ms
        option  dontlognull

listen stats :8888
        stats enable
        stats uri       /admin
        stats auth      admin:1234

frontend oldboy.org
        bind 0.0.0.0:80
        option httplog
        option httpclose
        option  forwardfor
        log global
        acl www hdr_reg(host) -i www.oldboy.org
        use_backend www.oldboy.org if www

backend www.oldboy.org
        server 100.1.7.9 100.1.7.9 weight 20 maxconn 3000
原配置文件

 

6. 字符編碼與轉碼

詳細文章:

http://www.cnblogs.com/yuanchenqi/articles/5956943.html

http://www.diveintopython3.net/strings.html

需知:

1.在python2默認編碼是ASCII, python3裏默認是utf-8

2.unicode 分爲 utf-32(佔4個字節),utf-16(佔兩個字節),utf-8(佔1-4個字節), so utf-8就是unicode

3.在py3中encode,在轉碼的同時還會把string 變成bytes類型,decode在解碼的同時還會把bytes變回string

 

 

 

#-*-coding:utf-8-*-
__author__ = 'Alex Li'

import sys
print(sys.getdefaultencoding())


msg = "我愛北京天安門"
msg_gb2312 = msg.decode("utf-8").encode("gb2312")
gb2312_to_gbk = msg_gb2312.decode("gbk").encode("gbk")

print(msg)
print(msg_gb2312)
print(gb2312_to_gbk)
in python2
#-*-coding:gb2312 -*-   #這個也能夠去掉
__author__ = 'Alex Li'

import sys
print(sys.getdefaultencoding())


msg = "我愛北京天安門"
#msg_gb2312 = msg.decode("utf-8").encode("gb2312")
msg_gb2312 = msg.encode("gb2312") #默認就是unicode,不用再decode,喜大普奔
gb2312_to_unicode = msg_gb2312.decode("gb2312")
gb2312_to_utf8 = msg_gb2312.decode("gb2312").encode("utf-8")

print(msg)
print(msg_gb2312)
print(gb2312_to_unicode)
print(gb2312_to_utf8)
in python3

 

 

7.  內置函數

 

 

溫故知新

1. 集合

主要做用: 

  1. 去重
  2. 關係測試, 交集\差集\並集\反向(對稱)差集
>>> a = {1,2,3,4}
>>> b ={3,4,5,6}
>>> a
{1, 2, 3, 4}
>>> type(a)
<class 'set'>
>>> a.symmetric_difference(b)
{1, 2, 5, 6}
>>> b.symmetric_difference(a)
{1, 2, 5, 6}
>>> 
>>> 
>>> a.difference(b)
{1, 2}
>>> a.union(b)
{1, 2, 3, 4, 5, 6}
>>> a.issu
a.issubset(   a.issuperset(
>>> a.issubset(b)
False

2. 元組  

只讀列表,只有count, index 2 個方法

做用:若是一些數據不想被人修改, 能夠存成元組,好比身份證列表

3. 字典

key-value對

  1. 特性:
  2. 無順序
  3. 去重
  4. 查詢速度快,比列表快多了
  5. 比list佔用內存多

爲何會查詢速度會快呢?由於他是hash類型的,那什麼是hash呢?

哈希算法將任意長度的二進制值映射爲較短的固定長度的二進制值,這個小的二進制值稱爲哈希值。哈希值是一段數據惟一且極其緊湊的數值表示形式。若是散列一段明文並且哪怕只更改該段落的一個字母,隨後的哈希都將產生不一樣的值。要找到散列爲同一個值的兩個不一樣的輸入,在計算上是不可能的,因此數據的哈希值能夠檢驗數據的完整性。通常用於快速查找和加密算法

dict會把全部的key變成hash 表,而後將這個表進行排序,這樣,你經過data[key]去查data字典中一個key的時候,python會先把這個key hash成一個數字,而後拿這個數字到hash表中看沒有這個數字, 若是有,拿到這個key在hash表中的索引,拿到這個索引去與此key對應的value的內存地址那取值就能夠了。

上面依然沒回答這樣作查找一個數據爲何會比列表快,對不對? 呵呵,等我課上揭曉。

4. 字符編碼

 

先說python2

  1. py2裏默認編碼是ascii
  2. 文件開頭那個編碼聲明是告訴解釋這個代碼的程序 以什麼編碼格式 把這段代碼讀入到內存,由於到了內存裏,這段代碼實際上是以bytes二進制格式存的,不過即便是2進制流,也能夠按不一樣的編碼格式轉成2進制流,你懂麼?
  3. 若是在文件頭聲明瞭#_*_coding:utf-8*_,就能夠寫中文了, 不聲明的話,python在處理這段代碼時按ascii,顯然會出錯, 加了這個聲明後,裏面的代碼就全是utf-8格式了
  4. 在有#_*_coding:utf-8*_的狀況下,你在聲明變量若是寫成name=u"大保健",那這個字符就是unicode格式,不加這個u,那你聲明的字符串就是utf-8格式
  5. utf-8 to gbk怎麼轉,utf8先decode成unicode,再encode成gbk

再說python3

  1. py3裏默認文件編碼就是utf-8,因此能夠直接寫中文,也不須要文件頭聲明編碼了,乾的漂亮
  2. 你聲明的變量默認是unicode編碼,不是utf-8, 由於默認便是unicode了(不像在py2裏,你想直接聲明成unicode還得在變量前加個u), 此時你想轉成gbk的話,直接your_str.encode("gbk")便可以
  3. 但py3裏,你在your_str.encode("gbk")時,感受好像還加了一個動做,就是就是encode的數據變成了bytes裏,我操,這是怎麼個狀況,由於在py3裏,str and bytes作了明確的區分,你能夠理解爲bytes就是2進制流,你會說,我看到的不是010101這樣的2進制呀, 那是由於python爲了讓你能對數據進行操做而在內存級別又幫你作了一層封裝,不然讓你直接看到一堆2進制,你能看出哪一個字符對應哪段2進制麼?什麼?本身換算,得了吧,你連超過2位數的數字加減運算都費勁,還仍是省省心吧。  
  4. 那你說,在py2裏好像也有bytes呀,是的,不過py2裏的bytes只是對str作了個別名,沒有像py3同樣給你顯示的多出來一層封裝,但其實其內部仍是封裝了的。 這麼講吧, 不管是2仍是三, 從硬盤到內存,數據格式都是 010101二進制到-->b'\xe4\xbd\xa0\xe5\xa5\xbd' bytes類型-->按照指定編碼轉成你能看懂的文字

編碼應用比較多的場景應該是爬蟲了,互聯網上不少網站用的編碼格式很雜,雖然總體趨向都變成utf-8,但如今仍是很雜,因此爬網頁時就須要你進行各類編碼的轉換,不過生活正在變美好,期待一個不須要轉碼的世界。

最後,編碼is a piece of fucking shit, noboby likes it.

 

 

1.函數基本語法及特性

背景提要

如今老闆讓你寫一個監控程序,監控服務器的系統情況,當cpu\memory\disk等指標的使用量超過閥值時即發郵件報警,你掏空了全部的知識量,寫出瞭如下代碼

while True:
    if cpu利用率 > 90%:
        #發送郵件提醒
        鏈接郵箱服務器
        發送郵件
        關閉鏈接
    
    if 硬盤使用空間 > 90%:
        #發送郵件提醒
        鏈接郵箱服務器
        發送郵件
        關閉鏈接
    
    if 內存佔用 > 80%:
        #發送郵件提醒
        鏈接郵箱服務器
        發送郵件
        關閉鏈接

上面的代碼實現了功能,但即便是鄰居老王也看出了端倪,老王親切的摸了下你家兒子的臉蛋,說,你這個重複代碼太多了,每次報警都要重寫一段發郵件的代碼,太low了,這樣幹存在2個問題:

  1. 代碼重複過多,一個勁的copy and paste不符合高端程序員的氣質
  2. 若是往後須要修改發郵件的這段代碼,好比加入羣發功能,那你就須要在全部用到這段代碼的地方都修改一遍

你以爲老王說的對,你也不想寫重複代碼,但又不知道怎麼搞,老王好像看出了你的心思,此時他抱起你兒子,笑着說,其實很簡單,只須要把重複的代碼提取出來,放在一個公共的地方,起個名字,之後誰想用這段代碼,就經過這個名字調用就好了,以下

def 發送郵件(內容)
    #發送郵件提醒
    鏈接郵箱服務器
    發送郵件
    關閉鏈接
    
while True:
    
    if cpu利用率 > 90%:
        發送郵件('CPU報警')
    
    if 硬盤使用空間 > 90%:
        發送郵件('硬盤報警')
    
    if 內存佔用 > 80%:
        發送郵件('內存報警')

 

你看着老王寫的代碼,氣勢恢宏、磅礴大氣,代碼裏透露着一股內斂的傲氣,心想,老王這我的真是不通常,忽然對他的背景更感興趣了,問老王,這些花式玩法你都是怎麼知道的? 老王親了一口你兒子,捋了捋不存在的鬍子,淡淡的講,「老夫,年少時,師從京西沙河淫魔銀角大王 」, 你一聽「銀角大王」這幾個字,不禁的嬌軀一震,心想,真nb,怪不得代碼寫的這麼6, 這「銀角大王」當年在江湖上但是數得着的響噹噹的名字,只惋惜後期縱慾過分,卒於公元2016年, 真是惋惜了,只留下其哥哥孤守當年兄弟倆一塊兒打下來的江山。 此時你看着的老王離開的身影,感受你兒子跟他愈來愈像了。。。

 

 

 

函數是什麼?

函數一詞來源於數學,但編程中的「函數」概念,與數學中的函數是有很大不一樣的,具體區別,咱們後面會講,編程中的函數在英文中也有不少不一樣的叫法。在BASIC中叫作subroutine(子過程或子程序),在Pascal中叫作procedure(過程)和function,在C中只有function,在Java裏面叫作method。

定義: 函數是指將一組語句的集合經過一個名字(函數名)封裝起來,要想執行這個函數,只需調用其函數名便可

特性:

  1. 減小重複代碼
  2. 使程序變的可擴展
  3. 使程序變得易維護

語法定義

def sayhi():#函數名
    print("Hello, I'm nobody!")

sayhi() #調用函數

能夠帶參數

#下面這段代碼
a,b = 5,8
c = a**b
print(c)


#改爲用函數寫
def calc(x,y):
    res = x**y
    return res #返回函數執行結果

c = calc(a,b) #結果賦值給c變量
print(c)

 

2.函數參數與局部變量  

形參變量只有在被調用時才分配內存單元,在調用結束時,即刻釋放所分配的內存單元。所以,形參只在函數內部有效。函數調用結束返回主調用函數後則不能再使用該形參變量

實參能夠是常量、變量、表達式、函數等,不管實參是何種類型的量,在進行函數調用時,它們都必須有肯定的值,以便把這些值傳送給形參。所以應預先用賦值,輸入等辦法使參數得到肯定值

 

默認參數

看下面代碼

def stu_register(name,age,country,course):
    print("----註冊學生信息------")
    print("姓名:",name)
    print("age:",age)
    print("國籍:",country)
    print("課程:",course)

stu_register("王山炮",22,"CN","python_devops")
stu_register("張叫春",21,"CN","linux")
stu_register("劉老根",25,"CN","linux")

發現 country 這個參數 基本都 是"CN", 就像咱們在網站上註冊用戶,像國籍這種信息,你不填寫,默認就會是 中國, 這就是經過默認參數實現的,把country變成默認參數很是簡單

def stu_register(name,age,course,country="CN"):

這樣,這個參數在調用時不指定,那默認就是CN,指定了的話,就用你指定的值。

另外,你可能注意到了,在把country變成默認參數後,我同時把它的位置移到了最後面,爲何呢?  

關鍵參數

正常狀況下,給函數傳參數要按順序,不想按順序就能夠用關鍵參數,只需指定參數名便可,但記住一個要求就是,關鍵參數必須放在位置參數以後。

stu_register(age=22,name='alex',course="python",)

  

非固定參數

若你的函數在定義時不肯定用戶想傳入多少個參數,就能夠使用非固定參數

def stu_register(name,age,*args): # *args 會把多傳入的參數變成一個元組形式
    print(name,age,args)

stu_register("Alex",22)
#輸出
#Alex 22 () #後面這個()就是args,只是由於沒傳值,因此爲空

stu_register("Jack",32,"CN","Python")
#輸出
# Jack 32 ('CN', 'Python')

還能夠有一個**kwargs

def stu_register(name,age,*args,**kwargs): # *kwargs 會把多傳入的參數變成一個dict形式
    print(name,age,args,kwargs)

stu_register("Alex",22)
#輸出
#Alex 22 () {}#後面這個{}就是kwargs,只是由於沒傳值,因此爲空

stu_register("Jack",32,"CN","Python",sex="Male",province="ShanDong")
#輸出
# Jack 32 ('CN', 'Python') {'province': 'ShanDong', 'sex': 'Male'}

 

局部變量  

name = "Alex Li"

def change_name(name):
    print("before change:",name)
    name = "金角大王,一個有Tesla的男人"
    print("after change", name)


change_name(name)

print("在外面看看name改了麼?",name)

輸出

before change: Alex Li
after change 金角大王,一個有Tesla的男人
在外面看看name改了麼? Alex Li

 

全局與局部變量

在子程序中定義的變量稱爲局部變量,在程序的一開始定義的變量稱爲全局變量。
全局變量做用域是整個程序,局部變量做用域是定義該變量的子程序。
當全局變量與局部變量同名時:
在定義局部變量的子程序內,局部變量起做用;在其它地方全局變量起做用。

 

3.返回值  

要想獲取函數的執行結果,就能夠用return語句把結果返回

注意:

  1. 函數在執行過程當中只要遇到return語句,就會中止執行並返回結果,so 也能夠理解爲 return 語句表明着函數的結束
  2. 若是未在函數中指定return,那這個函數的返回值爲None 

  

強行插入知識點: 嵌套函數  

看上面的標題的意思是,函數還能套函數?of course

name = "Alex"

def change_name():
    name = "Alex2"

    def change_name2():
        name = "Alex3"
        print("第3層打印",name)

    change_name2() #調用內層函數
    print("第2層打印",name)


change_name()
print("最外層打印",name)

此時,在最外層調用change_name2()會出現什麼效果?

沒錯, 出錯了, 爲何呢?

嵌套函數的用法會了,但它有什麼用呢?下節課揭曉。。。

  

 

4. 遞歸

在函數內部,能夠調用其餘函數。若是一個函數在內部調用自身自己,這個函數就是遞歸函數。

def calc(n):
    print(n)
    if int(n/2) ==0:
        return n
    return calc(int(n/2))

calc(10)

輸出:
10
5
2
1

遞歸特性:

1. 必須有一個明確的結束條件

2. 每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減小

3. 遞歸效率不高,遞歸層次過多會致使棧溢出(在計算機中,函數調用是經過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。因爲棧的大小不是無限的,因此,遞歸調用的次數過多,會致使棧溢出)

堆棧掃盲http://www.cnblogs.com/lln7777/archive/2012/03/14/2396164.html 

 

遞歸函數實際應用案例,二分查找

data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]


def binary_search(dataset,find_num):
    print(dataset)

    if len(dataset) >1:
        mid = int(len(dataset)/2)
        if dataset[mid] == find_num:  #find it
            print("找到數字",dataset[mid])
        elif dataset[mid] > find_num :# 找的數在mid左面
            print("\033[31;1m找的數在mid[%s]左面\033[0m" % dataset[mid])
            return binary_search(dataset[0:mid], find_num)
        else:# 找的數在mid右面
            print("\033[32;1m找的數在mid[%s]右面\033[0m" % dataset[mid])
            return binary_search(dataset[mid+1:],find_num)
    else:
        if dataset[0] == find_num:  #find it
            print("找到數字啦",dataset[0])
        else:
            print("沒的分了,要找的數字[%s]不在列表裏" % find_num)


binary_search(data,66)

  

5. 匿名函數 

匿名函數就是不須要顯式的指定函數

#這段代碼
def calc(n):
    return n**n
print(calc(10))

#換成匿名函數
calc = lambda n:n**n
print(calc(10))

你也許會說,用上這個東西沒感受有毛方便呀, 。。。。呵呵,若是是這麼用,確實沒毛線改進,不過匿名函數主要是和其它函數搭配使用的呢,以下

res = map(lambda x:x**2,[1,5,7,4,8])
for i in res:
    print(i)

輸出

1
25
49
16
64

 

 

6.函數式編程介紹  

 

函數是Python內建支持的一種封裝,咱們經過把大段代碼拆成函數,經過一層一層的函數調用,就能夠把複雜任務分解成簡單的任務,這種分解能夠稱之爲面向過程的程序設計。函數就是面向過程的程序設計的基本單元。

函數式編程中的函數這個術語不是指計算機中的函數(其實是Subroutine),而是指數學中的函數,即自變量的映射。也就是說一個函數的值僅決定於函數參數的值,不依賴其餘狀態。好比sqrt(x)函數計算x的平方根,只要x不變,不論何時調用,調用幾回,值都是不變的。

 

Python對函數式編程提供部分支持。因爲Python容許使用變量,所以,Python不是純函數式編程語言。

1、定義

簡單說,"函數式編程"是一種"編程範式"(programming paradigm),也就是如何編寫程序的方法論。

主要思想是把運算過程儘可能寫成一系列嵌套的函數調用。舉例來講,如今有這樣一個數學表達式:

  (1 + 2) * 3 - 4

傳統的過程式編程,可能這樣寫:

  var a = 1 + 2;

  var b = a * 3;

  var c = b - 4;

函數式編程要求使用函數,咱們能夠把運算過程定義爲不一樣的函數,而後寫成下面這樣:

  var result = subtract(multiply(add(1,2), 3), 4);

這段代碼再演進如下,能夠變成這樣

add(1,2).multiply(3).subtract(4)

這基本就是天然語言的表達了。再看下面的代碼,你們應該一眼就能明白它的意思吧:

merge([1,2],[3,4]).sort().search("2")

所以,函數式編程的代碼更容易理解。

要想學好函數式編程,不要玩py,玩Erlang,Haskell, 好了,我只會這麼多了。。。

 

7.高階函數

變量能夠指向函數,函數的參數能接收變量,那麼一個函數就能夠接收另外一個函數做爲參數,這種函數就稱之爲高階函數。

def add(x,y,f):
    return f(x) + f(y)


res = add(3,-6,abs)
print(res)

 

8. 內置參數  

 

內置參數詳解 https://docs.python.org/3/library/functions.html?highlight=built#ascii 

#compile
# f = open("函數遞歸.py")
# data =compile(f.read(),'','exec')
# exec(data)


#print
msg = "又回到最初的起點"
f = open("tofile","w")
print(msg,"記憶中你青澀的臉",sep="|",end="",file=f)


#slice
a = range(20)
pattern = slice(3,8,2)
for i in a[pattern]: #等於a[3:8:2]
    print(i)
幾個內置方法用法提醒

 

 

  

  

本節做業

有如下員工信息表

 

固然此表你在文件存儲時能夠這樣表示

1,Alex Li,22,13651054608,IT,2013-04-01

現須要對這個員工信息文件,實現增刪改查操做

  1. 可進行模糊查詢,語法至少支持下面3種:
    1.   select name,age from staff_table where age > 22
    2.   select  * from staff_table where dept = "IT"
    3.       select  * from staff_table where enroll_date like "2013"
    4. 查到的信息,打印後,最後面還要顯示查到的條數 
  2. 可建立新員工紀錄,以phone作惟一鍵,staff_id需自增
  3. 可刪除指定員工信息紀錄,輸入員工id,便可刪除
  4. 可修改員工信息,語法以下:
    1.   UPDATE staff_table SET dept="Market" WHERE where dept = "IT"

 注意:以上需求,要充分使用函數,請盡你的最大限度來減小重複代碼!

  

 

1.列表生成式,迭代器&生成器

列表生成式

孩子,我如今有個需求,看列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],我要求你把列表裏的每一個值加1,你怎麼實現?你可能會想到2種方式 

>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> b = []
>>> for i in a:b.append(i+1)
... 
>>> b
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a = b
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
普通青年版
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a = map(lambda x:x+1, a)
>>> a
<map object at 0x101d2c630>
>>> for i in a:print(i)
... 
2
3
4
5
6
7
8
9
10
11
文藝青年版

其實還有一種寫法,以下 

>>> a = [i+1 for i in range(10)]
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
裝逼青年版

這就叫作列表生成

 

生成器

經過列表生成式,咱們能夠直接建立一個列表。可是,受到內存限制,列表容量確定是有限的。並且,建立一個包含100萬個元素的列表,不只佔用很大的存儲空間,若是咱們僅僅須要訪問前面幾個元素,那後面絕大多數元素佔用的空間都白白浪費了。

因此,若是列表元素能夠按照某種算法推算出來,那咱們是否能夠在循環的過程當中不斷推算出後續的元素呢?這樣就沒必要建立完整的list,從而節省大量的空間。在Python中,這種一邊循環一邊計算的機制,稱爲生成器:generator。

要建立一個generator,有不少種方法。第一種方法很簡單,只要把一個列表生成式的[]改爲(),就建立了一個generator:

>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>

建立Lg的區別僅在於最外層的[]()L是一個list,而g是一個generator。

咱們能夠直接打印出list的每個元素,但咱們怎麼打印出generator的每個元素呢?

若是要一個一個打印出來,能夠經過next()函數得到generator的下一個返回值:

>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> next(g)
16
>>> next(g)
25
>>> next(g)
36
>>> next(g)
49
>>> next(g)
64
>>> next(g)
81
>>> next(g)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

咱們講過,generator保存的是算法,每次調用next(g),就計算出g的下一個元素的值,直到計算到最後一個元素,沒有更多的元素時,拋出StopIteration的錯誤。

固然,上面這種不斷調用next(g)實在是太變態了,正確的方法是使用for循環,由於generator也是可迭代對象:

>>> g = (x * x for x in range(10))
>>> for n in g:
...     print(n)
... 
0
1
4
9
16
25
36
49
64
81

 

因此,咱們建立了一個generator後,基本上永遠不會調用next(),而是經過for循環來迭代它,而且不須要關心StopIteration的錯誤。

generator很是強大。若是推算的算法比較複雜,用相似列表生成式的for循環沒法實現的時候,還能夠用函數來實現。

好比,著名的斐波拉契數列(Fibonacci),除第一個和第二個數外,任意一個數均可由前兩個數相加獲得:

1, 1, 2, 3, 5, 8, 13, 21, 34, ...

斐波拉契數列用列表生成式寫不出來,可是,用函數把它打印出來卻很容易:

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b
        n = n + 1
    return 'done'

注意,賦值語句:

a, b = b, a + b

至關於:

t = (b, a + b) # t是一個tuple
a = t[0]
b = t[1]

但沒必要顯式寫出臨時變量t就能夠賦值。

上面的函數能夠輸出斐波那契數列的前N個數:

>>> fib(10)
1
1
2
3
5
8
13
21
34
55
done
 
 

仔細觀察,能夠看出,fib函數其實是定義了斐波拉契數列的推算規則,能夠從第一個元素開始,推算出後續任意的元素,這種邏輯其實很是相似generator。

也就是說,上面的函數和generator僅一步之遙。要把fib函數變成generator,只須要把print(b)改成yield b就能夠了:

def fib(max):
    n,a,b = 0,0,1

    while n < max:
        #print(b)
        yield  b
        a,b = b,a+b

        n += 1

    return 'done' 

這就是定義generator的另外一種方法。若是一個函數定義中包含yield關鍵字,那麼這個函數就再也不是一個普通函數,而是一個generator:

>>> f = fib(6)
>>> f
<generator object fib at 0x104feaaa0>

這裏,最難理解的就是generator和函數的執行流程不同。函數是順序執行,遇到return語句或者最後一行函數語句就返回。而變成generator的函數,在每次調用next()的時候執行,遇到yield語句返回,再次執行時從上次返回的yield語句處繼續執行。

data = fib(10)
print(data)

print(data.__next__())
print(data.__next__())
print("乾點別的事")
print(data.__next__())
print(data.__next__())
print(data.__next__())
print(data.__next__())
print(data.__next__())

#輸出
<generator object fib at 0x101be02b0>
1
1
乾點別的事
2
3
5
8
13

在上面fib的例子,咱們在循環過程當中不斷調用yield,就會不斷中斷。固然要給循環設置一個條件來退出循環,否則就會產生一個無限數列出來。

一樣的,把函數改爲generator後,咱們基本上歷來不會用next()來獲取下一個返回值,而是直接使用for循環來迭代:

 

>>> for n in fib(6):
...     print(n)
...
1
1
2
3
5
8

可是用for循環調用generator時,發現拿不到generator的return語句的返回值。若是想要拿到返回值,必須捕獲StopIteration錯誤,返回值包含在StopIterationvalue中:

>>> g = fib(6)
>>> while True:
...     try:
...         x = next(g)
...         print('g:', x)
...     except StopIteration as e:
...         print('Generator return value:', e.value)
...         break
...
g: 1
g: 1
g: 2
g: 3
g: 5
g: 8
Generator return value: done

關於如何捕獲錯誤,後面的錯誤處理還會詳細講解。

還可經過yield實如今單線程的狀況下實現併發運算的效果  

#_*_coding:utf-8_*_
__author__ = 'Alex Li'

import time
def consumer(name):
    print("%s 準備吃包子啦!" %name)
    while True:
       baozi = yield

       print("包子[%s]來了,被[%s]吃了!" %(baozi,name))


def producer(name):
    c = consumer('A')
    c2 = consumer('B')
    c.__next__()
    c2.__next__()
    print("老子開始準備作包子啦!")
    for i in range(10):
        time.sleep(1)
        print("作了2個包子!")
        c.send(i)
        c2.send(i)

producer("alex")
經過生成器實現協程並行運算

 

迭代器

咱們已經知道,能夠直接做用於for循環的數據類型有如下幾種:

一類是集合數據類型,如listtupledictsetstr等;

一類是generator,包括生成器和帶yield的generator function。

這些能夠直接做用於for循環的對象統稱爲可迭代對象:Iterable

能夠使用isinstance()判斷一個對象是不是Iterable對象:

 

>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False

而生成器不但能夠做用於for循環,還能夠被next()函數不斷調用並返回下一個值,直到最後拋出StopIteration錯誤表示沒法繼續返回下一個值了。

*能夠被next()函數調用並不斷返回下一個值的對象稱爲迭代器:Iterator

能夠使用isinstance()判斷一個對象是不是Iterator對象:

>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False

生成器都是Iterator對象,但listdictstr雖然是Iterable,卻不是Iterator

listdictstrIterable變成Iterator能夠使用iter()函數:

>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True

你可能會問,爲何listdictstr等數據類型不是Iterator

這是由於Python的Iterator對象表示的是一個數據流,Iterator對象能夠被next()函數調用並不斷返回下一個數據,直到沒有數據時拋出StopIteration錯誤。能夠把這個數據流看作是一個有序序列,但咱們卻不能提早知道序列的長度,只能不斷經過next()函數實現按需計算下一個數據,因此Iterator的計算是惰性的,只有在須要返回下一個數據時它纔會計算。

Iterator甚至能夠表示一個無限大的數據流,例如全體天然數。而使用list是永遠不可能存儲全體天然數的。

 

小結

凡是可做用於for循環的對象都是Iterable類型;

凡是可做用於next()函數的對象都是Iterator類型,它們表示一個惰性計算的序列;

集合數據類型如listdictstr等是Iterable但不是Iterator,不過能夠經過iter()函數得到一個Iterator對象。

Python的for循環本質上就是經過不斷調用next()函數實現的,例如:

for x in [1, 2, 3, 4, 5]:
    pass

實際上徹底等價於:

# 首先得到Iterator對象:
it = iter([1, 2, 3, 4, 5])
# 循環:
while True:
    try:
        # 得到下一個值:
        x = next(it)
    except StopIteration:
        # 遇到StopIteration就退出循環
        break

 

  

2.裝飾器

你是一家視頻網站的後端開發工程師,大家網站有如下幾個版塊

def home():
    print("---首頁----")

def america():
    print("----歐美專區----")

def japan():
    print("----日韓專區----")

def henan():
    print("----河南專區----")

視頻剛上線初期,爲了吸引用戶,大家採起了免費政策,全部視頻免費觀看,迅速吸引了一大批用戶,免費一段時間後,天天巨大的帶寬費用公司承受不了了,因此準備對比較受歡迎的幾個版塊收費,其中包括「歐美」 和 「河南」專區,你拿到這個需求後,想了想,想收費得先讓其進行用戶認證,認證經過後,再斷定這個用戶是不是VIP付費會員就能夠了,是VIP就讓看,不是VIP就不讓看就好了唄。 你以爲這個需求非常簡單,由於要對多個版塊進行認證,那應該把認證功能提取出來單獨寫個模塊,而後每一個版塊裏調用 就能夠了,與是你輕輕的就實現了下面的功能 。

#_*_coding:utf-8_*_


user_status = False #用戶登陸了就把這個改爲True

def login():
    _username = "alex" #僞裝這是DB裏存的用戶信息
    _password = "abc!23" #僞裝這是DB裏存的用戶信息
    global user_status

    if user_status == False:
        username = input("user:")
        password = input("pasword:")

        if username == _username and password == _password:
            print("welcome login....")
            user_status = True
        else:
            print("wrong username or password!")
    else:
        print("用戶已登陸,驗證經過...")

def home():
    print("---首頁----")

def america():
    login() #執行前加上驗證
    print("----歐美專區----")

def japan():
    print("----日韓專區----")

def henan():
    login() #執行前加上驗證
    print("----河南專區----")



home()
america()
henan()

此時你信心滿滿的把這個代碼提交給你的TEAM LEADER審覈,沒成想,沒過5分鐘,代碼就被打回來了, TEAM LEADER給你反饋是,我如今有不少模塊須要加認證模塊,你的代碼雖然實現了功能,可是須要更改須要加認證的各個模塊的代碼,這直接違反了軟件開發中的一個原則「開放-封閉」原則,簡單來講,它規定已經實現的功能代碼不容許被修改,但能夠被擴展,即:

  • 封閉:已實現的功能代碼塊
  • 開放:對擴展開發

這個原則你仍是第一次據說,我擦,再次感覺了本身這個野生程序員與正規軍的差距,BUT ANYWAY,老大要求的這個怎麼實現呢?如何在不改原有功能代碼的狀況下加上認證功能呢?你一時想不出思路,只好帶着這個問題回家繼續憋,媳婦不在家,去隔壁老王家串門了,你正好落的清靜,一不當心就想到了解決方案,不改源代碼能夠呀,

你師從沙河金角大王時,記得他教過你,高階函數,就是把一個函數當作一個參數傳給另一個函數,當時大王說,有一天,你會用到它的,沒想到這時這個知識點忽然從腦子 裏蹦出來了,我只須要寫個認證方法,每次調用 須要驗證的功能 時,直接 把這個功能 的函數名當作一個參數 傳給 個人驗證模塊不就好了麼,哈哈,機智如我,如是你啪啪啪改寫了以前的代碼

#_*_coding:utf-8_*_


user_status = False #用戶登陸了就把這個改爲True

def login(func): #把要執行的模塊從這裏傳進來
    _username = "alex" #僞裝這是DB裏存的用戶信息
    _password = "abc!23" #僞裝這是DB裏存的用戶信息
    global user_status

    if user_status == False:
        username = input("user:")
        password = input("pasword:")

        if username == _username and password == _password:
            print("welcome login....")
            user_status = True
        else:
            print("wrong username or password!")

    if user_status == True: 
        func() # 看這裏看這裏,只要驗證經過了,就調用相應功能

def home():
    print("---首頁----")

def america():
    #login() #執行前加上驗證
    print("----歐美專區----")

def japan():
    print("----日韓專區----")

def henan():
    #login() #執行前加上驗證
    print("----河南專區----")



home()
login(america) #須要驗證就調用 login,把須要驗證的功能 當作一個參數傳給login
# home()
# america()
login(henan)

你很開心,終於實現了老闆的要求,不改變原功能代碼的前提下,給功能加上了驗證,此時,媳婦回來了,後面還跟着老王,你兩家關係 很是 好,老王常常來串門,老王也是碼農,你跟他分享了你寫的代碼,興奮的等他看完 誇獎你NB,沒成想,老王看後,並無誇你,抱起你的兒子,笑笑說,你這個代碼仍是改改吧, 要否則會被開除的,WHAT? 會開除,明明實現了功能 呀, 老王講,沒錯,你功能 是實現了,可是你又犯了一個大忌,什麼大忌? 

你改變了調用方式呀, 想想,如今沒每一個須要認證的模塊,都必須調用你的login()方法,並把本身的函數名傳給你,人家以前可不是這麼調用 的, 試想,若是 有100個模塊須要認證,那這100個模塊都得更改調用方式,這麼多模塊確定不止是一我的寫的,讓每一個人再去修改調用方式 才能加上認證,你會被罵死的。。。。

你以爲老王說的對,但問題是,如何即不改變原功能代碼,又不改變原有調用方式,還能加上認證呢? 你苦思了一會,仍是想不出,老王在逗你的兒子玩,你說,老王呀,快給我點思路 ,實在想不出來,老王背對着你問,

老王:學過匿名函數沒有?

你:學過學過,就是lambda嘛

老王:那lambda與正常函數的區別是什麼?

你:最直接的區別是,正常函數定義時須要寫名字,但lambda不須要

老王:沒錯,那lambda定好後,爲了屢次調用 ,能否也給它命個名?

你:能夠呀,能夠寫成plus = lambda x:x+1相似這樣,之後再調用plus就能夠了,但這樣不就失去了lambda的意義了,明明人家叫匿名函數呀,你起了名字有什麼用呢?

老王:我不是要跟你討論它的意義 ,我想經過這個讓你明白一個事實

說着,老王拿起你兒子的畫板,在上面寫了如下代碼:

def plus(n):
    return n+1

plus2 = lambda x:x+1

老王: 上面這兩種寫法是否是表明 一樣的意思?

你:是的

老王:我給lambda x:x+1 起了個名字叫plus2,是否是至關於def plus2(x) ?

你:我擦,你別說,還真是,但老王呀,你想說明什麼呢?

老王: 沒啥,只想告訴你,給函數賦值變量名就像def func_name 是同樣的效果,以下面的plus(n)函數,你調用時能夠用plus名,還能夠再起個其它名字,如

calc = plus

calc(n)

你明白我想傳達什麼意思了麼?

你:。。。。。。。。。。。這。。。。。。嗯 。。。。。不太。。。。明白 。。

老王:。。。。這。。。。。呵呵。。。。。。好吧。。。。,那我在給你點一下,你以前寫的下面這段調用 認證的代碼 

home()
login(america) #須要驗證就調用 login,把須要驗證的功能 當作一個參數傳給login
# home()
# america()
login(henan)

你之所改變了調用方式,是由於用戶每次調用時須要執行login(henan),相似的。其實稍一改就能夠了呀

home()
america = login(america) 
henan = login(henan)

這樣你,其它人調用henan時,其實至關於調用了login(henan), 經過login裏的驗證後,就會自動調用henan功能。 

你:我擦,還真是唉。。。,老王,仍是你nb。。。不過,等等, 我這樣寫了好,那用戶調用時,應該是下面這個樣子

home()
america = login(america) #你在這裏至關於把america這個函數替換了
henan = login(henan)

#那用戶調用時依然寫
america()

但問題在於,還不等用戶調用 ,你的america = login(america)就會先本身把america執行了呀。。。。,你應該等我用戶調用 的時候 再執行纔對呀,不信我試給你看。。。

老王:哈哈,你說的沒錯,這樣搞會出現這個問題? 但你想一想有沒有解決辦法 呢?

你:我擦,你指的思路呀,大哥。。。我哪知道 下一步怎麼走。。。

 

老王:算了,估計你也想不出來。。。 學過嵌套函數沒有?

你:yes,而後呢?

老王:想實現一開始你寫的america = login(america)不觸發你函數的執行,只須要在這個login裏面再定義一層函數,第一次調用america = login(america)只調用到外層login,這個login雖然會執行,但不會觸發認證了,由於認證的全部代碼被封裝在login裏層的新定義 的函數裏了,login只返回 裏層函數的函數名,這樣下次再執行america()時, 就會調用裏層函數啦。。。

你:。。。。。。什麼? 什麼個意思,我蒙逼了。。。

老王:仍是給你看代碼吧。。

def login(func): #把要執行的模塊從這裏傳進來

    def inner():#再定義一層函數
        _username = "alex" #僞裝這是DB裏存的用戶信息
        _password = "abc!23" #僞裝這是DB裏存的用戶信息
        global user_status

        if user_status == False:
            username = input("user:")
            password = input("pasword:")

            if username == _username and password == _password:
                print("welcome login....")
                user_status = True
            else:
                print("wrong username or password!")

        if user_status == True:
            func() # 看這裏看這裏,只要驗證經過了,就調用相應功能

    return inner #用戶調用login時,只會返回inner的內存地址,下次再調用時加上()纔會執行inner函數

此時你仔細着了老王寫的代碼 ,感受老王真不是通常人呀,連這種奇淫巧技都能想出來。。。,心中默默感謝上天賜你一個大牛鄰居。

你: 老王呀,你這個姿式很nb呀,你首創的?

此時你媳婦噗嗤的笑出聲來,你也不知道 她笑個球。。。

老王:呵呵, 這不是我首創的呀固然 ,這是開發中一個經常使用的玩法,叫語法糖,官方名稱「裝飾器」,其實上面的寫法,還能夠更簡單

能夠把下面代碼去掉

america = login(america) #你在這裏至關於把america這個函數替換了

只在你要裝飾的函數上面加上下面代碼

@login
def america():
    #login() #執行前加上驗證
    print("----歐美專區----")

def japan():
    print("----日韓專區----")

@login
def henan():
    #login() #執行前加上驗證
    print("----河南專區----")

效果是同樣的。

你開心的玩着老王教你的新姿式 ,玩着玩着就手賤給你的「河南專區」版塊 加了個參數,而後,結果 出錯了。。。

你:老王,老王,怎麼傳個參數就不行了呢?

老王:那必然呀,你調用henan時,實際上是至關於調用的login,你的henan第一次調用時henan = login(henan), login就返回了inner的內存地址,第2次用戶本身調用henan("3p"),實際上至關於調用的時inner,但你的inner定義時並無設置參數,但你給他傳了個參數,因此天然就報錯了呀

你:可是個人 版塊須要傳參數呀,你不讓我傳不行呀。。。

老王:沒說不讓你傳,稍作改動即可。。

老王:你再試試就行了 。 

你: 果真好使,大神就是大神呀。 。。 不過,若是有多個參數呢?

老王:。。。。老弟,你不要什麼都讓我教你吧,非固定參數你沒學過麼? *args,**kwargs...

你:噢 。。。還能這麼搞?,nb,我再試試。

 

你身陷這種新玩法中沒法自拔,竟沒注意到老王已經離開,你媳婦告訴你說爲了避免打擾你加班,今晚帶孩子去跟她姐妹住 ,你以爲媳婦真體貼,最終,你終於搞定了全部需求,徹底遵循開放-封閉原則,最終代碼以下 。

#_*_coding:utf-8_*_


user_status = False #用戶登陸了就把這個改爲True

def login(func): #把要執行的模塊從這裏傳進來

    def inner(*args,**kwargs):#再定義一層函數
        _username = "alex" #僞裝這是DB裏存的用戶信息
        _password = "abc!23" #僞裝這是DB裏存的用戶信息
        global user_status

        if user_status == False:
            username = input("user:")
            password = input("pasword:")

            if username == _username and password == _password:
                print("welcome login....")
                user_status = True
            else:
                print("wrong username or password!")

        if user_status == True:
            func(*args,**kwargs) # 看這裏看這裏,只要驗證經過了,就調用相應功能

    return inner #用戶調用login時,只會返回inner的內存地址,下次再調用時加上()纔會執行inner函數


def home():
    print("---首頁----")

@login
def america():
    #login() #執行前加上驗證
    print("----歐美專區----")

def japan():
    print("----日韓專區----")

# @login
def henan(style):
    '''
    :param style: 喜歡看什麼類型的,就傳進來
    :return:
    '''
    #login() #執行前加上驗證
    print("----河南專區----")

home()
# america = login(america) #你在這裏至關於把america這個函數替換了
henan = login(henan)

# #那用戶調用時依然寫
america()

henan("3p")

此時,你已累的不行了,洗洗就抓緊睡了,半夜,上廁所,隱隱聽到隔壁老王家有微弱的女人的聲音傳來,你會心一笑,老王這傢伙,不聲不響找了女友也不帶給我看看,改天必定要見下真人。。。。

 

 第二2天早上,產品經理又提了新的需求,要容許用戶選擇用qq\weibo\weixin認證,此時的你,已深諳裝飾器各類裝逼技巧,輕鬆的就實現了新的需求。

#_*_coding:utf-8_*_


user_status = False #用戶登陸了就把這個改爲True

def login(auth_type): #把要執行的模塊從這裏傳進來
    def auth(func):
        def inner(*args,**kwargs):#再定義一層函數
            if auth_type == "qq":
                _username = "alex" #僞裝這是DB裏存的用戶信息
                _password = "abc!23" #僞裝這是DB裏存的用戶信息
                global user_status

                if user_status == False:
                    username = input("user:")
                    password = input("pasword:")

                    if username == _username and password == _password:
                        print("welcome login....")
                        user_status = True
                    else:
                        print("wrong username or password!")

                if user_status == True:
                    return func(*args,**kwargs) # 看這裏看這裏,只要驗證經過了,就調用相應功能
            else:
                print("only support qq ")
        return inner #用戶調用login時,只會返回inner的內存地址,下次再調用時加上()纔會執行inner函數

    return auth

def home():
    print("---首頁----")

@login('qq')
def america():
    #login() #執行前加上驗證
    print("----歐美專區----")

def japan():
    print("----日韓專區----")

@login('weibo')
def henan(style):
    '''
    :param style: 喜歡看什麼類型的,就傳進來
    :return:
    '''
    #login() #執行前加上驗證
    print("----河南專區----")

home()
# america = login(america) #你在這裏至關於把america這個函數替換了
#henan = login(henan)

# #那用戶調用時依然寫
america()

# henan("3p")
帶參數的裝飾器

 

 

  

 

 

 

3.Json & pickle 數據序列化

參考 http://www.cnblogs.com/alex3714/articles/5161349.html

 

  

4.軟件目錄結構規範

爲何要設計好目錄結構?

"設計項目目錄結構",就和"代碼編碼風格"同樣,屬於我的風格問題。對於這種風格上的規範,一直都存在兩種態度:

  1. 一類同窗認爲,這種我的風格問題"可有可無"。理由是能讓程序work就好,風格問題根本不是問題。
  2. 另外一類同窗認爲,規範化能更好的控制程序結構,讓程序具備更高的可讀性。

我是比較偏向於後者的,由於我是前一類同窗思想行爲下的直接受害者。我曾經維護過一個很是很差讀的項目,其實現的邏輯並不複雜,可是卻耗費了我很是長的時間去理解它想表達的意思。今後我我的對於提升項目可讀性、可維護性的要求就很高了。"項目目錄結構"其實也是屬於"可讀性和可維護性"的範疇,咱們設計一個層次清晰的目錄結構,就是爲了達到如下兩點:

  1. 可讀性高: 不熟悉這個項目的代碼的人,一眼就能看懂目錄結構,知道程序啓動腳本是哪一個,測試目錄在哪兒,配置文件在哪兒等等。從而很是快速的瞭解這個項目。
  2. 可維護性高: 定義好組織規則後,維護者就能很明確地知道,新增的哪一個文件和代碼應該放在什麼目錄之下。這個好處是,隨着時間的推移,代碼/配置的規模增長,項目結構不會混亂,仍然可以組織良好。

因此,我認爲,保持一個層次清晰的目錄結構是有必要的。更況且組織一個良好的工程目錄,實際上是一件很簡單的事兒。

目錄組織方式

關於如何組織一個較好的Python工程目錄結構,已經有一些獲得了共識的目錄結構。在Stackoverflow的這個問題上,能看到你們對Python目錄結構的討論。

這裏面說的已經很好了,我也不打算從新造輪子列舉各類不一樣的方式,這裏面我說一下個人理解和體會。

假設你的項目名爲foo, 我比較建議的最方便快捷目錄結構這樣就足夠了:

Foo/
|-- bin/
|   |-- foo
|
|-- foo/
|   |-- tests/
|   |   |-- __init__.py
|   |   |-- test_main.py
|   |
|   |-- __init__.py
|   |-- main.py
|
|-- docs/
|   |-- conf.py
|   |-- abc.rst
|
|-- setup.py
|-- requirements.txt
|-- README

簡要解釋一下:

  1. bin/: 存放項目的一些可執行文件,固然你能夠起名script/之類的也行。
  2. foo/: 存放項目的全部源代碼。(1) 源代碼中的全部模塊、包都應該放在此目錄。不要置於頂層目錄。(2) 其子目錄tests/存放單元測試代碼; (3) 程序的入口最好命名爲main.py
  3. docs/: 存放一些文檔。
  4. setup.py: 安裝、部署、打包的腳本。
  5. requirements.txt: 存放軟件依賴的外部Python包列表。
  6. README: 項目說明文件。

除此以外,有一些方案給出了更加多的內容。好比LICENSE.txt,ChangeLog.txt文件等,我沒有列在這裏,由於這些東西主要是項目開源的時候須要用到。若是你想寫一個開源軟件,目錄該如何組織,能夠參考這篇文章

下面,再簡單講一下我對這些目錄的理解和我的要求吧。

關於README的內容

這個我以爲是每一個項目都應該有的一個文件,目的是能簡要描述該項目的信息,讓讀者快速瞭解這個項目。

它須要說明如下幾個事項:

  1. 軟件定位,軟件的基本功能。
  2. 運行代碼的方法: 安裝環境、啓動命令等。
  3. 簡要的使用說明。
  4. 代碼目錄結構說明,更詳細點能夠說明軟件的基本原理。
  5. 常見問題說明。

我以爲有以上幾點是比較好的一個README。在軟件開發初期,因爲開發過程當中以上內容可能不明確或者發生變化,並非必定要在一開始就將全部信息都補全。可是在項目完結的時候,是須要撰寫這樣的一個文檔的。

能夠參考Redis源碼中Readme的寫法,這裏面簡潔可是清晰的描述了Redis功能和源碼結構。

關於requirements.txt和setup.py

setup.py

通常來講,用setup.py來管理代碼的打包、安裝、部署問題。業界標準的寫法是用Python流行的打包工具setuptools來管理這些事情。這種方式廣泛應用於開源項目中。不過這裏的核心思想不是用標準化的工具來解決這些問題,而是說,一個項目必定要有一個安裝部署工具,能快速便捷的在一臺新機器上將環境裝好、代碼部署好和將程序運行起來。

這個我是踩過坑的。

我剛開始接觸Python寫項目的時候,安裝環境、部署代碼、運行程序這個過程全是手動完成,遇到過如下問題:

  1. 安裝環境時常常忘了最近又添加了一個新的Python包,結果一到線上運行,程序就出錯了。
  2. Python包的版本依賴問題,有時候咱們程序中使用的是一個版本的Python包,可是官方的已是最新的包了,經過手動安裝就可能裝錯了。
  3. 若是依賴的包不少的話,一個一個安裝這些依賴是很費時的事情。
  4. 新同窗開始寫項目的時候,將程序跑起來很是麻煩,由於可能常常忘了要怎麼安裝各類依賴。

setup.py能夠將這些事情自動化起來,提升效率、減小出錯的機率。"複雜的東西自動化,能自動化的東西必定要自動化。"是一個很是好的習慣。

setuptools的文檔比較龐大,剛接觸的話,可能不太好找到切入點。學習技術的方式就是看他人是怎麼用的,能夠參考一下Python的一個Web框架,flask是如何寫的: setup.py

固然,簡單點本身寫個安裝腳本(deploy.sh)替代setup.py也何嘗不可。

requirements.txt

這個文件存在的目的是:

  1. 方便開發者維護軟件的包依賴。將開發過程當中新增的包添加進這個列表中,避免在setup.py安裝依賴時漏掉軟件包。
  2. 方便讀者明確項目使用了哪些Python包。

這個文件的格式是每一行包含一個包依賴的說明,一般是flask>=0.10這種格式,要求是這個格式能被pip識別,這樣就能夠簡單的經過 pip install -r requirements.txt來把全部Python包依賴都裝好了。具體格式說明: 點這裏

 

關於配置文件的使用方法

注意,在上面的目錄結構中,沒有將conf.py放在源碼目錄下,而是放在docs/目錄下。

不少項目對配置文件的使用作法是:

  1. 配置文件寫在一個或多個python文件中,好比此處的conf.py。
  2. 項目中哪一個模塊用到這個配置文件就直接經過import conf這種形式來在代碼中使用配置。

這種作法我不太贊同:

  1. 這讓單元測試變得困難(由於模塊內部依賴了外部配置)
  2. 另外一方面配置文件做爲用戶控制程序的接口,應當能夠由用戶自由指定該文件的路徑。
  3. 程序組件可複用性太差,由於這種貫穿全部模塊的代碼硬編碼方式,使得大部分模塊都依賴conf.py這個文件。

因此,我認爲配置的使用,更好的方式是,

  1. 模塊的配置都是能夠靈活配置的,不受外部配置文件的影響。
  2. 程序的配置也是能夠靈活控制的。

可以佐證這個思想的是,用過nginx和mysql的同窗都知道,nginx、mysql這些程序均可以自由的指定用戶配置。

因此,不該當在代碼中直接import conf來使用配置文件。上面目錄結構中的conf.py,是給出的一個配置樣例,不是在寫死在程序中直接引用的配置文件。能夠經過給main.py啓動參數指定配置路徑的方式來讓程序讀取配置內容。固然,這裏的conf.py你能夠換個相似的名字,好比settings.py。或者你也能夠使用其餘格式的內容來編寫配置文件,好比settings.yaml之類的。

 

5.本節做業

做業需求:

模擬實現一個ATM + 購物商城程序

  1. 額度 15000或自定義
  2. 實現購物商城,買東西加入 購物車,調用信用卡接口結帳
  3. 能夠提現,手續費5%
  4. 每個月22號出帳單,每個月10號爲還款日,過時未還,按欠款總額 萬分之5 每日計息
  5. 支持多帳戶登陸
  6. 支持帳戶間轉帳
  7. 記錄每個月平常消費流水
  8. 提供還款接口
  9. ATM記錄操做日誌 
  10. 提供管理接口,包括添加帳戶、用戶額度,凍結帳戶等。。。
  11. 用戶認證用裝飾器

示例代碼 https://github.com/triaquae/py_training/tree/master/sample_code/day5-atm   

 

 

模塊,用一砣代碼實現了某個功能的代碼集合。 

相似於函數式編程和麪向過程編程,函數式編程則完成一個功能,其餘代碼用來調用便可,提供了代碼的重用性和代碼間的耦合。而對於一個複雜的功能來,可能須要多個函數才能完成(函數又能夠在不一樣的.py文件中),n個 .py 文件組成的代碼集合就稱爲模塊。

如:os 是系統相關的模塊;file是文件操做相關的模塊

模塊分爲三種:

  • 自定義模塊
  • 內置標準模塊(又稱標準庫)
  • 開源模塊

自定義模塊 和開源模塊的使用參考 http://www.cnblogs.com/wupeiqi/articles/4963027.html 

 

 

time & datetime模塊

 1 #_*_coding:utf-8_*_
 2 __author__ = 'Alex Li'
 3 
 4 import time
 5 
 6 
 7 # print(time.clock()) #返回處理器時間,3.3開始已廢棄 , 改爲了time.process_time()測量處理器運算時間,不包括sleep時間,不穩定,mac上測不出來
 8 # print(time.altzone)  #返回與utc時間的時間差,以秒計算\
 9 # print(time.asctime()) #返回時間格式"Fri Aug 19 11:14:16 2016",
10 # print(time.localtime()) #返回本地時間 的struct time對象格式
11 # print(time.gmtime(time.time()-800000)) #返回utc時間的struc時間對象格式
12 
13 # print(time.asctime(time.localtime())) #返回時間格式"Fri Aug 19 11:14:16 2016",
14 #print(time.ctime()) #返回Fri Aug 19 12:38:29 2016 格式, 同上
15 
16 
17 
18 # 日期字符串 轉成  時間戳
19 # string_2_struct = time.strptime("2016/05/22","%Y/%m/%d") #將 日期字符串 轉成 struct時間對象格式
20 # print(string_2_struct)
21 # #
22 # struct_2_stamp = time.mktime(string_2_struct) #將struct時間對象轉成時間戳
23 # print(struct_2_stamp)
24 
25 
26 
27 #將時間戳轉爲字符串格式
28 # print(time.gmtime(time.time()-86640)) #將utc時間戳轉換成struct_time格式
29 # print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()) ) #將utc struct_time格式轉成指定的字符串格式
30 
31 
32 
33 
34 
35 #時間加減
36 import datetime
37 
38 # print(datetime.datetime.now()) #返回 2016-08-19 12:47:03.941925
39 #print(datetime.date.fromtimestamp(time.time()) )  # 時間戳直接轉成日期格式 2016-08-19
40 # print(datetime.datetime.now() )
41 # print(datetime.datetime.now() + datetime.timedelta(3)) #當前時間+3天
42 # print(datetime.datetime.now() + datetime.timedelta(-3)) #當前時間-3天
43 # print(datetime.datetime.now() + datetime.timedelta(hours=3)) #當前時間+3小時
44 # print(datetime.datetime.now() + datetime.timedelta(minutes=30)) #當前時間+30分
45 
46 
47 #
48 # c_time  = datetime.datetime.now()
49 # print(c_time.replace(minute=3,hour=2)) #時間替換
View Code

 

 
Directive Meaning Notes
%a Locale’s abbreviated weekday name.  
%A Locale’s full weekday name.  
%b Locale’s abbreviated month name.  
%B Locale’s full month name.  
%c Locale’s appropriate date and time representation.  
%d Day of the month as a decimal number [01,31].  
%H Hour (24-hour clock) as a decimal number [00,23].  
%I Hour (12-hour clock) as a decimal number [01,12].  
%j Day of the year as a decimal number [001,366].  
%m Month as a decimal number [01,12].  
%M Minute as a decimal number [00,59].  
%p Locale’s equivalent of either AM or PM. (1)
%S Second as a decimal number [00,61]. (2)
%U Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Sunday are considered to be in week 0. (3)
%w Weekday as a decimal number [0(Sunday),6].  
%W Week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday are considered to be in week 0. (3)
%x Locale’s appropriate date representation.  
%X Locale’s appropriate time representation.  
%y Year without century as a decimal number [00,99].  
%Y Year with century as a decimal number.  
%z Time zone offset indicating a positive or negative time difference from UTC/GMT of the form +HHMM or -HHMM, where H represents decimal hour digits and M represents decimal minute digits [-23:59, +23:59].  
%Z Time zone name (no characters if no time zone exists).  
%% A literal '%' character.

 

 

 

random模塊

隨機數

mport random
print random.random()
print random.randint(1,2)
print random.randrange(1,10)

生成隨機驗證碼

import random
checkcode = ''
for i in range(4):
    current = random.randrange(0,4)
    if current != i:
        temp = chr(random.randint(65,90))
    else:
        temp = random.randint(0,9)
    checkcode += str(temp)
print checkcode

 

OS模塊  

提供對操做系統進行調用的接口

os.getcwd() 獲取當前工做目錄,即當前python腳本工做的目錄路徑
os.chdir("dirname")  改變當前腳本工做目錄;至關於shell下cd
os.curdir  返回當前目錄: ('.')
os.pardir  獲取當前目錄的父目錄字符串名:('..')
os.makedirs('dirname1/dirname2')    可生成多層遞歸目錄
os.removedirs('dirname1')    若目錄爲空,則刪除,並遞歸到上一級目錄,如若也爲空,則刪除,依此類推
os.mkdir('dirname')    生成單級目錄;至關於shell中mkdir dirname
os.rmdir('dirname')    刪除單級空目錄,若目錄不爲空則沒法刪除,報錯;至關於shell中rmdir dirname
os.listdir('dirname')    列出指定目錄下的全部文件和子目錄,包括隱藏文件,並以列表方式打印
os.remove()  刪除一個文件
os.rename("oldname","newname")  重命名文件/目錄
os.stat('path/filename')  獲取文件/目錄信息
os.sep    輸出操做系統特定的路徑分隔符,win下爲"\\",Linux下爲"/"
os.linesep    輸出當前平臺使用的行終止符,win下爲"\t\n",Linux下爲"\n"
os.pathsep    輸出用於分割文件路徑的字符串
os.name    輸出字符串指示當前使用平臺。win->'nt'; Linux->'posix'
os.system("bash command")  運行shell命令,直接顯示
os.environ  獲取系統環境變量
os.path.abspath(path)  返回path規範化的絕對路徑
os.path.split(path)  將path分割成目錄和文件名二元組返回
os.path.dirname(path)  返回path的目錄。其實就是os.path.split(path)的第一個元素
os.path.basename(path)  返回path最後的文件名。如何path以/或\結尾,那麼就會返回空值。即os.path.split(path)的第二個元素
os.path.exists(path)  若是path存在,返回True;若是path不存在,返回False
os.path.isabs(path)  若是path是絕對路徑,返回True
os.path.isfile(path)  若是path是一個存在的文件,返回True。不然返回False
os.path.isdir(path)  若是path是一個存在的目錄,則返回True。不然返回False
os.path.join(path1[, path2[, ...]])  將多個路徑組合後返回,第一個絕對路徑以前的參數將被忽略
os.path.getatime(path)  返回path所指向的文件或者目錄的最後存取時間
os.path.getmtime(path)  返回path所指向的文件或者目錄的最後修改時間

更多猛擊這裏 

 

sys模塊

sys.argv           命令行參數List,第一個元素是程序自己路徑
sys.exit(n)        退出程序,正常退出時exit(0)
sys.version        獲取Python解釋程序的版本信息
sys.maxint         最大的Int值
sys.path           返回模塊的搜索路徑,初始化時使用PYTHONPATH環境變量的值
sys.platform       返回操做系統平臺名稱
sys.stdout.write('please:')
val = sys.stdin.readline()[:-1]

 

shutil 模塊

直接參考 http://www.cnblogs.com/wupeiqi/articles/4963027.html 

 

json & pickle 模塊

用於序列化的兩個模塊

  • json,用於字符串 和 python數據類型間進行轉換
  • pickle,用於python特有的類型 和 python的數據類型間進行轉換

Json模塊提供了四個功能:dumps、dump、loads、load

pickle模塊提供了四個功能:dumps、dump、loads、load

 

shelve 模塊

shelve模塊是一個簡單的k,v將內存數據經過文件持久化的模塊,能夠持久化任何pickle可支持的python數據格式

import shelve

d = shelve.open('shelve_test') #打開一個文件 

class Test(object):
    def __init__(self,n):
        self.n = n


t = Test(123)  
t2 = Test(123334)

name = ["alex","rain","test"] 
d["test"] = name #持久化列表
d["t1"] = t      #持久化類
d["t2"] = t2

d.close()

  

xml處理模塊

xml是實現不一樣語言或程序之間進行數據交換的協議,跟json差很少,但json使用起來更簡單,不過,古時候,在json還沒誕生的黑暗年代,你們只能選擇用xml呀,至今不少傳統公司如金融行業的不少系統的接口還主要是xml。

xml的格式以下,就是經過<>節點來區別數據結構的:

<?xml version="1.0"?>
<data>
    <country name="Liechtenstein">
        <rank updated="yes">2</rank>
        <year>2008</year>
        <gdppc>141100</gdppc>
        <neighbor name="Austria" direction="E"/>
        <neighbor name="Switzerland" direction="W"/>
    </country>
    <country name="Singapore">
        <rank updated="yes">5</rank>
        <year>2011</year>
        <gdppc>59900</gdppc>
        <neighbor name="Malaysia" direction="N"/>
    </country>
    <country name="Panama">
        <rank updated="yes">69</rank>
        <year>2011</year>
        <gdppc>13600</gdppc>
        <neighbor name="Costa Rica" direction="W"/>
        <neighbor name="Colombia" direction="E"/>
    </country>
</data>

 

xml協議在各個語言裏的都 是支持的,在python中能夠用如下模塊操做xml   

import xml.etree.ElementTree as ET

tree = ET.parse("xmltest.xml")
root = tree.getroot()
print(root.tag)

#遍歷xml文檔
for child in root:
    print(child.tag, child.attrib)
    for i in child:
        print(i.tag,i.text)

#只遍歷year 節點
for node in root.iter('year'):
    print(node.tag,node.text)

修改和刪除xml文檔內容

import xml.etree.ElementTree as ET

tree = ET.parse("xmltest.xml")
root = tree.getroot()

#修改
for node in root.iter('year'):
    new_year = int(node.text) + 1
    node.text = str(new_year)
    node.set("updated","yes")

tree.write("xmltest.xml")


#刪除node
for country in root.findall('country'):
   rank = int(country.find('rank').text)
   if rank > 50:
     root.remove(country)

tree.write('output.xml')

本身建立xml文檔

import xml.etree.ElementTree as ET


new_xml = ET.Element("namelist")
name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"})
age = ET.SubElement(name,"age",attrib={"checked":"no"})
sex = ET.SubElement(name,"sex")
sex.text = '33'
name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"})
age = ET.SubElement(name2,"age")
age.text = '19'

et = ET.ElementTree(new_xml) #生成文檔對象
et.write("test.xml", encoding="utf-8",xml_declaration=True)

ET.dump(new_xml) #打印生成的格式 

 

PyYAML模塊

Python也能夠很容易的處理ymal文檔格式,只不過須要安裝一個模塊,參考文檔:http://pyyaml.org/wiki/PyYAMLDocumentation 

 

ConfigParser模塊

用於生成和修改常見配置文檔,當前模塊的名稱在 python 3.x 版本中變動爲 configparser。

來看一個好多軟件的常見文檔格式以下

[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes

[bitbucket.org]
User = hg

[topsecret.server.com]
Port = 50022
ForwardX11 = no

若是想用python生成一個這樣的文檔怎麼作呢?

import configparser

config = configparser.ConfigParser()
config["DEFAULT"] = {'ServerAliveInterval': '45',
                      'Compression': 'yes',
                     'CompressionLevel': '9'}

config['bitbucket.org'] = {}
config['bitbucket.org']['User'] = 'hg'
config['topsecret.server.com'] = {}
topsecret = config['topsecret.server.com']
topsecret['Host Port'] = '50022'     # mutates the parser
topsecret['ForwardX11'] = 'no'  # same here
config['DEFAULT']['ForwardX11'] = 'yes'
with open('example.ini', 'w') as configfile:
   config.write(configfile)

  

寫完了還能夠再讀出來哈。

>>> import configparser
>>> config = configparser.ConfigParser()
>>> config.sections()
[]
>>> config.read('example.ini')
['example.ini']
>>> config.sections()
['bitbucket.org', 'topsecret.server.com']
>>> 'bitbucket.org' in config
True
>>> 'bytebong.com' in config
False
>>> config['bitbucket.org']['User']
'hg'
>>> config['DEFAULT']['Compression']
'yes'
>>> topsecret = config['topsecret.server.com']
>>> topsecret['ForwardX11']
'no'
>>> topsecret['Port']
'50022'
>>> for key in config['bitbucket.org']: print(key)
...
user
compressionlevel
serveraliveinterval
compression
forwardx11
>>> config['bitbucket.org']['ForwardX11']
'yes'

configparser增刪改查語法

[section1]
k1 = v1
k2:v2
 
[section2]
k1 = v1

import ConfigParser
 
config = ConfigParser.ConfigParser()
config.read('i.cfg')
 
# ########## 讀 ##########
#secs = config.sections()
#print secs
#options = config.options('group2')
#print options
 
#item_list = config.items('group2')
#print item_list
 
#val = config.get('group1','key')
#val = config.getint('group1','key')
 
# ########## 改寫 ##########
#sec = config.remove_section('group1')
#config.write(open('i.cfg', "w"))
 
#sec = config.has_section('wupeiqi')
#sec = config.add_section('wupeiqi')
#config.write(open('i.cfg', "w"))
 
 
#config.set('group2','k1',11111)
#config.write(open('i.cfg', "w"))
 
#config.remove_option('group2','age')
#config.write(open('i.cfg', "w"))

  

hashlib模塊  

用於加密相關的操做,3.x裏代替了md5模塊和sha模塊,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法

import hashlib

m = hashlib.md5()
m.update(b"Hello")
m.update(b"It's me")
print(m.digest())
m.update(b"It's been a long time since last time we ...")

print(m.digest()) #2進制格式hash
print(len(m.hexdigest())) #16進制格式hash
'''
def digest(self, *args, **kwargs): # real signature unknown
    """ Return the digest value as a string of binary data. """
    pass

def hexdigest(self, *args, **kwargs): # real signature unknown
    """ Return the digest value as a string of hexadecimal digits. """
    pass

'''
import hashlib

# ######## md5 ########

hash = hashlib.md5()
hash.update('admin')
print(hash.hexdigest())

# ######## sha1 ########

hash = hashlib.sha1()
hash.update('admin')
print(hash.hexdigest())

# ######## sha256 ########

hash = hashlib.sha256()
hash.update('admin')
print(hash.hexdigest())


# ######## sha384 ########

hash = hashlib.sha384()
hash.update('admin')
print(hash.hexdigest())

# ######## sha512 ########

hash = hashlib.sha512()
hash.update('admin')
print(hash.hexdigest())

還不夠吊?python 還有一個 hmac 模塊,它內部對咱們建立 key 和 內容 再進行處理而後再加密

import hmac
h = hmac.new('wueiqi')
h.update('hellowo') 
print h.hexdigest()

更多關於md5,sha1,sha256等介紹的文章看這裏https://www.tbs-certificates.co.uk/FAQ/en/sha256.html 

  

Subprocess模塊 

The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace several older modules and functions:

os.system os.spawn*

The recommended approach to invoking subprocesses is to use the run() function for all use cases it can handle. For more advanced use cases, the underlying Popen interface can be used directly.

The run() function was added in Python 3.5; if you need to retain compatibility with older versions, see the Older high-level API section.

(args*stdin=Noneinput=Nonestdout=Nonestderr=Noneshell=Falsetimeout=Nonecheck=False)subprocess.run

Run the command described by args. Wait for command to complete, then return a CompletedProcess instance.

The arguments shown above are merely the most common ones, described below in Frequently Used Arguments (hence the use of keyword-only notation in the abbreviated signature). The full function signature is largely the same as that of the Popen constructor - apart from timeoutinput and check, all the arguments to this function are passed through to that interface.

This does not capture stdout or stderr by default. To do so, pass PIPE for the stdout and/or stderr arguments.

The timeout argument is passed to Popen.communicate(). If the timeout expires, the child process will be killed and waited for. The TimeoutExpired exception will be re-raised after the child process has terminated.

The input argument is passed to Popen.communicate() and thus to the subprocess’s stdin. If used it must be a byte sequence, or a string if universal_newlines=True. When used, the internal Popen object is automatically created withstdin=PIPE, and the stdin argument may not be used as well.

If check is True, and the process exits with a non-zero exit code, a CalledProcessError exception will be raised. Attributes of that exception hold the arguments, the exit code, and stdout and stderr if they were captured.

經常使用subprocess方法示例

#執行命令,返回命令執行狀態 , 0 or 非0
>>> retcode = subprocess.call(["ls", "-l"])

#執行命令,若是命令結果爲0,就正常返回,不然拋異常
>>> subprocess.check_call(["ls", "-l"])
0

#接收字符串格式命令,返回元組形式,第1個元素是執行狀態,第2個是命令結果
>>> subprocess.getstatusoutput('ls /bin/ls')
(0, '/bin/ls')

#接收字符串格式命令,並返回結果
>>> subprocess.getoutput('ls /bin/ls')
'/bin/ls'

#執行命令,並返回結果,注意是返回結果,不是打印,下例結果返回給res
>>> res=subprocess.check_output(['ls','-l'])
>>> res
b'total 0\ndrwxr-xr-x 12 alex staff 408 Nov 2 11:05 OldBoyCRM\n'

#上面那些方法,底層都是封裝的subprocess.Popen
poll()
Check if child process has terminated. Returns returncode

wait()
Wait for child process to terminate. Returns returncode attribute.


terminate() 殺掉所啓動進程
communicate() 等待任務結束

stdin 標準輸入

stdout 標準輸出

stderr 標準錯誤

pid
The process ID of the child process.

#例子
>>> p = subprocess.Popen("df -h|grep disk",stdin=subprocess.PIPE,stdout=subprocess.PIPE,shell=True)
>>> p.stdout.read()
b'/dev/disk1 465Gi 64Gi 400Gi 14% 16901472 104938142 14% /\n'

 

 

 

>>> subprocess.run(["ls", "-l"])  # doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')

 

調用subprocess.run(...)是推薦的經常使用方法,在大多數狀況下能知足需求,但若是你可能須要進行一些複雜的與系統的交互的話,你還能夠用subprocess.Popen(),語法以下:

p = subprocess.Popen("find / -size +1000000 -exec ls -shl {} \;",shell=True,stdout=subprocess.PIPE)
print(p.stdout.read())

可用參數:

    • args:shell命令,能夠是字符串或者序列類型(如:list,元組)
    • bufsize:指定緩衝。0 無緩衝,1 行緩衝,其餘 緩衝區大小,負值 系統緩衝
    • stdin, stdout, stderr:分別表示程序的標準輸入、輸出、錯誤句柄
    • preexec_fn:只在Unix平臺下有效,用於指定一個可執行對象(callable object),它將在子進程運行以前被調用
    • close_sfs:在windows平臺下,若是close_fds被設置爲True,則新建立的子進程將不會繼承父進程的輸入、輸出、錯誤管道。
      因此不能將close_fds設置爲True同時重定向子進程的標準輸入、輸出與錯誤(stdin, stdout, stderr)。
    • shell:同上
    • cwd:用於設置子進程的當前目錄
    • env:用於指定子進程的環境變量。若是env = None,子進程的環境變量將從父進程中繼承。
    • universal_newlines:不一樣系統的換行符不一樣,True -> 贊成使用 \n
    • startupinfo與createionflags只在windows下有效
      將被傳遞給底層的CreateProcess()函數,用於設置子進程的一些屬性,如:主窗口的外觀,進程的優先級等等

終端輸入的命令分爲兩種:

  • 輸入便可獲得輸出,如:ifconfig
  • 輸入進行某環境,依賴再輸入,如:python

須要交互的命令示例

import subprocess

obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
obj.stdin.write('print 1 \n ')
obj.stdin.write('print 2 \n ')
obj.stdin.write('print 3 \n ')
obj.stdin.write('print 4 \n ')

out_error_list = obj.communicate(timeout=10)
print out_error_list

subprocess實現sudo 自動輸入密碼

import subprocess

def mypass():
    mypass = '123' #or get the password from anywhere
    return mypass

echo = subprocess.Popen(['echo',mypass()],
                        stdout=subprocess.PIPE,
                        )

sudo = subprocess.Popen(['sudo','-S','iptables','-L'],
                        stdin=echo.stdout,
                        stdout=subprocess.PIPE,
                        )

end_of_pipe = sudo.stdout

print "Password ok \n Iptables Chains %s" % end_of_pipe.read()

  

  

logging模塊  

不少程序都有記錄日誌的需求,而且日誌中包含的信息即有正常的程序訪問日誌,還可能有錯誤、警告等信息輸出,python的logging模塊提供了標準的日誌接口,你能夠經過它存儲各類格式的日誌,logging的日誌能夠分爲 debug()info()warning()error() and critical() 5個級別,下面咱們看一下怎麼用。

最簡單用法

import logging

logging.warning("user [alex] attempted wrong password more than 3 times")
logging.critical("server is down")

#輸出
WARNING:root:user [alex] attempted wrong password more than 3 times
CRITICAL:root:server is down

看一下這幾個日誌級別分別表明什麼意思

Level When it’s used
DEBUG Detailed information, typically of interest only when diagnosing problems.
INFO Confirmation that things are working as expected.
WARNING An indication that something unexpected happened, or indicative of some problem in the near future (e.g. ‘disk space low’). The software is still working as expected.
ERROR Due to a more serious problem, the software has not been able to perform some function.
CRITICAL A serious error, indicating that the program itself may be unable to continue running.

  

若是想把日誌寫到文件裏,也很簡單

import logging

logging.basicConfig(filename='example.log',level=logging.INFO) 
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')

其中下面這句中的level=loggin.INFO意思是,把日誌紀錄級別設置爲INFO,也就是說,只有比日誌是INFO或比INFO級別更高的日誌纔會被紀錄到文件裏,在這個例子, 第一條日誌是不會被紀錄的,若是但願紀錄debug的日誌,那把日誌級別改爲DEBUG就好了。

logging.basicConfig(filename='example.log',level=logging.INFO) 

感受上面的日誌格式忘記加上時間啦,日誌不知道時間怎麼行呢,下面就來加上!

import logging
logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
logging.warning('is when this event was logged.')

#輸出
12/12/2010 11:46:36 AM is when this event was logged.

日誌格式

%(name)s

Logger的名字

%(levelno)s

數字形式的日誌級別

%(levelname)s

文本形式的日誌級別

%(pathname)s

調用日誌輸出函數的模塊的完整路徑名,可能沒有

%(filename)s

調用日誌輸出函數的模塊的文件名

%(module)s

調用日誌輸出函數的模塊名

%(funcName)s

調用日誌輸出函數的函數名

%(lineno)d

調用日誌輸出函數的語句所在的代碼行

%(created)f

當前時間,用UNIX標準的表示時間的浮 點數表示

%(relativeCreated)d

輸出日誌信息時的,自Logger建立以 來的毫秒數

%(asctime)s

字符串形式的當前時間。默認格式是 「2003-07-08 16:49:45,896」。逗號後面的是毫秒

%(thread)d

線程ID。可能沒有

%(threadName)s

線程名。可能沒有

%(process)d

進程ID。可能沒有

%(message)s

用戶輸出的消息

 

 

 

  

若是想同時把log打印在屏幕和文件日誌裏,就須要瞭解一點複雜的知識 了


Python 使用logging模塊記錄日誌涉及四個主要類,使用官方文檔中的歸納最爲合適:

logger提供了應用程序能夠直接使用的接口;

handler將(logger建立的)日誌記錄發送到合適的目的輸出;

filter提供了細度設備來決定輸出哪條日誌記錄;

formatter決定日誌記錄的最終輸出格式。

logger
每一個程序在輸出信息以前都要得到一個Logger。Logger一般對應了程序的模塊名,好比聊天工具的圖形界面模塊能夠這樣得到它的Logger:
LOG=logging.getLogger(」chat.gui」)
而核心模塊能夠這樣:
LOG=logging.getLogger(」chat.kernel」)

Logger.setLevel(lel):指定最低的日誌級別,低於lel的級別將被忽略。debug是最低的內置級別,critical爲最高
Logger.addFilter(filt)、Logger.removeFilter(filt):添加或刪除指定的filter
Logger.addHandler(hdlr)、Logger.removeHandler(hdlr):增長或刪除指定的handler
Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():能夠設置的日誌級別

 

handler

handler對象負責發送相關的信息到指定目的地。Python的日誌系統有多種Handler能夠使用。有些Handler能夠把信息輸出到控制檯,有些Logger能夠把信息輸出到文件,還有些 Handler能夠把信息發送到網絡上。若是以爲不夠用,還能夠編寫本身的Handler。能夠經過addHandler()方法添加多個多handler
Handler.setLevel(lel):指定被處理的信息級別,低於lel級別的信息將被忽略
Handler.setFormatter():給這個handler選擇一個格式
Handler.addFilter(filt)、Handler.removeFilter(filt):新增或刪除一個filter對象


每一個Logger能夠附加多個Handler。接下來咱們就來介紹一些經常使用的Handler:
1) logging.StreamHandler
使用這個Handler能夠向相似與sys.stdout或者sys.stderr的任何文件對象(file object)輸出信息。它的構造函數是:
StreamHandler([strm])
其中strm參數是一個文件對象。默認是sys.stderr


2) logging.FileHandler
和StreamHandler相似,用於向一個文件輸出日誌信息。不過FileHandler會幫你打開這個文件。它的構造函數是:
FileHandler(filename[,mode])
filename是文件名,必須指定一個文件名。
mode是文件的打開方式。參見Python內置函數open()的用法。默認是’a',即添加到文件末尾。

3) logging.handlers.RotatingFileHandler
這個Handler相似於上面的FileHandler,可是它能夠管理文件大小。當文件達到必定大小以後,它會自動將當前日誌文件更名,而後建立 一個新的同名日誌文件繼續輸出。好比日誌文件是chat.log。當chat.log達到指定的大小以後,RotatingFileHandler自動把 文件更名爲chat.log.1。不過,若是chat.log.1已經存在,會先把chat.log.1重命名爲chat.log.2。。。最後從新建立 chat.log,繼續輸出日誌信息。它的構造函數是:
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
其中filename和mode兩個參數和FileHandler同樣。
maxBytes用於指定日誌文件的最大文件大小。若是maxBytes爲0,意味着日誌文件能夠無限大,這時上面描述的重命名過程就不會發生。
backupCount用於指定保留的備份文件的個數。好比,若是指定爲2,當上面描述的重命名過程發生時,原有的chat.log.2並不會被改名,而是被刪除。


4) logging.handlers.TimedRotatingFileHandler
這個Handler和RotatingFileHandler相似,不過,它沒有經過判斷文件大小來決定什麼時候從新建立日誌文件,而是間隔必定時間就 自動建立新的日誌文件。重命名的過程與RotatingFileHandler相似,不過新的文件不是附加數字,而是當前時間。它的構造函數是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename參數和backupCount參數和RotatingFileHandler具備相同的意義。
interval是時間間隔。
when參數是一個字符串。表示時間間隔的單位,不區分大小寫。它有如下取值:
S 秒
M 分
H 小時
D 天
W 每星期(interval==0時表明星期一)
midnight 天天凌晨

 

 

import logging

#create logger
logger = logging.getLogger('TEST-LOG')
logger.setLevel(logging.DEBUG)


# create console handler and set level to debug
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)

# create file handler and set level to warning
fh = logging.FileHandler("access.log")
fh.setLevel(logging.WARNING)
# create formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# add formatter to ch and fh
ch.setFormatter(formatter)
fh.setFormatter(formatter)

# add ch and fh to logger
logger.addHandler(ch)
logger.addHandler(fh)

# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')

  

 

文件自動截斷例子

import logging

from logging import handlers

logger = logging.getLogger(__name__)

log_file = "timelog.log"
#fh = handlers.RotatingFileHandler(filename=log_file,maxBytes=10,backupCount=3)
fh = handlers.TimedRotatingFileHandler(filename=log_file,when="S",interval=5,backupCount=3)


formatter = logging.Formatter('%(asctime)s %(module)s:%(lineno)d %(message)s')

fh.setFormatter(formatter)

logger.addHandler(fh)


logger.warning("test1")
logger.warning("test12")
logger.warning("test13")
logger.warning("test14")
View Code

 

 

 

 

re模塊   

經常使用正則表達式符號

'.'		默認匹配除\n以外的任意一個字符,若指定flag DOTALL,則匹配任意字符,包括換行
'^'		匹配字符開頭,若指定flags MULTILINE,這種也能夠匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)
'$'		匹配字符結尾,或e.search("foo$","bfoo\nsdfsf",flags=re.MULTILINE).group()也能夠
'*'		匹配*號前的字符0次或屢次,re.findall("ab*","cabb3abcbbac")  結果爲['abb', 'ab', 'a']
'+'		匹配前一個字符1次或屢次,re.findall("ab+","ab+cd+abb+bba") 結果['ab', 'abb']
'?'		匹配前一個字符1次或0次
'{m}'	匹配前一個字符m次
'{n,m}'	匹配前一個字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 結果'abb', 'ab', 'abb']
'|'		匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group()	結果'ABC'
'(...)' 分組匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 結果 abcabca456c


'\A'	只從字符開頭匹配,re.search("\Aabc","alexabc") 是匹配不到的
'\Z'	匹配字符結尾,同$
'\d'	匹配數字0-9
'\D'	匹配非數字
'\w'	匹配[A-Za-z0-9]
'\W'	匹配非[A-Za-z0-9]
's'		匹配空白字符、\t、\n、\r , re.search("\s+","ab\tc1\n3").group() 結果 '\t'

'(?P<name>...)' 分組匹配 re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","371481199306143242").groupdict("city") 結果{'province': '3714', 'city': '81', 'birthday': '1993'}

  

最經常使用的匹配語法

re.match 從頭開始匹配
re.search 匹配包含
re.findall 把全部匹配到的字符放到以列表中的元素返回
re.splitall 以匹配到的字符當作列表分隔符
re.sub		匹配字符並替換 

反斜槓的困擾
與大多數編程語言相同,正則表達式裏使用"\"做爲轉義字符,這就可能形成反斜槓困擾。假如你須要匹配文本中的字符"\",那麼使用編程語言表示的正則表達式裏將須要4個反斜槓"\\\\":前兩個和後兩個分別用於在編程語言裏轉義成反斜槓,轉換成兩個反斜槓後再在正則表達式裏轉義成一個反斜槓。Python裏的原生字符串很好地解決了這個問題,這個例子中的正則表達式能夠使用r"\\"表示。一樣,匹配一個數字的"\\d"能夠寫成r"\d"。有了原生字符串,你不再用擔憂是否是漏寫了反斜槓,寫出來的表達式也更直觀。

 

僅需輕輕知道的幾個匹配模式

re.I(re.IGNORECASE): 忽略大小寫(括號內是完整寫法,下同)
M(MULTILINE): 多行模式,改變'^'和'$'的行爲(參見上圖)
S(DOTALL): 點任意匹配模式,改變'.'的行爲

  

  

本節做業

開發一個簡單的python計算器

  1. 實現加減乘除及拓號優先級解析
  2. 用戶輸入 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等相似公式後,必須本身解析裏面的(),+,-,*,/符號和公式(不能調用eval等相似功能偷懶實現),運算後得出結果,結果必須與真實的計算器所得出的結果一致

 

hint:

re.search(r'\([^()]+\)',s).group()

'(-40/5)'

相關文章
相關標籤/搜索