python 基礎知識點

  • Python介紹及發展史
  • Python 2 or 3 區別
  • 安裝和第一個Hello World程序
  • 變量
  • 用戶交互
  • 模塊初識
  • .pyc文件是什麼?
  • 數據類型初識
  • 數據運算
  • 表達式if......else語句
  • 表達式for循環
  • break and continue區別及用法
  • 表達式while循環
  • 入門知識拾遺
  • 列表、元組操做
  • 字符串操做
  • 字典操做
  • 文件操做
  • 字符編碼與轉碼
  • 函數的基本語法及特性
  • 參數與局部變量
  • 返回值
  • 嵌套函數
  • 遞歸
  • 匿名函數
  • 函數式編程介紹
  • 高階函數
  • 內置函數
  • 迭代器&生成器
  • 裝飾器
  • Json & pickle 數據序列化
  • 軟件目錄結構規範

1、Python介紹php

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

       Python崇尚優美、清晰、簡單,是一個優秀並普遍使用的語言,Python應用愈來愈普遍而且也逐漸獲得行業的承認!!!java

       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

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

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

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

編譯型與解釋型的區別

編譯型

優勢:編譯器通常會有預編譯的過程對代碼進行優化。由於編譯只作一次,運行是不須要編譯,因此編譯型語言的程序執行效率高。能夠脫離語言環境獨立運行。

缺點:編譯以後若是須要修改就須要整個模塊從新編譯。編譯的時候根據對應的運行環境生成機器碼,不一樣的操做系統之間移植就會有問題,須要根據運行的操做系統環境編譯不一樣的可執行文件。

解釋型

有點:有良好的平臺兼容性,在任何環境中均可以運行,前提是安裝瞭解釋器(虛擬機)。靈活,修改代碼的時候直接修改就能夠,能夠快速部署,不用停機維護。

缺點:每次運行的時候都要解釋一遍,性能上不如編譯型語言。

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則是」一次編碼,處處編譯「。總之,隨着設計技術與硬件的不斷髮展,編譯型與解釋型兩種方式的界限正在不斷的變得模糊。

動態語言和靜態語言

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

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

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

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

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

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

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

例如:Python是動態語言,是強類型定義語言(類安全的語言);VBScript是動態語言,是弱類型定義的語言(類型不安全的語言);Java是靜態語言,是強類型定義的語言(類型安全的語言)。

經過上面的介紹,能夠得出,Python是一門動態解釋性的強類型定義語言。

Python的優缺點

優勢

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

缺點

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

固然,Python還有一些其餘的小缺點,就不一一列舉了,我想說的是,任何一門語言都不是完美的,都有擅長和不擅長作的事情,建議各位不要拿一個語言的劣勢去跟另外一個語言的優點去比較,語言只是一個工具,是實現程序設計師思想的工具,就像咱們中學學幾什麼時候,有時要用到圓規,有時又要使用三角尺同樣,拿相應的工具去作它最上傳的事纔是正確的選擇。

Python解釋器

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

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

CPython

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

CPython是使用最廣的Python解釋器。

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 framework,Zope 1 was released in 1999
  • Python 1.0 - January 1994增長了lambda、map、filter and reduce。
  • Python 2.0 - October 16,2000,加入了內存回收機制,構成了如今Python語言框架的基礎。
  • Python 2.4 - Novermber 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 - 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 develoment 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.Tis 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 laguage) 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 (PEP3105).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)!
View Code

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

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

ALL IS UNICODE NOW

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

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

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

某些庫名更名了

 Old Name

New Name
_winreg

winreg

ConfigParser

configparser

 

copy_reg

copyreg

Queue

queue

SocketServer

sockertserver

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 importhant,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

1、下載安裝包
    https://www.python.org/downloads/
2、安裝
    默認安裝路徑:C:\python27
3、配置環境變量
    【右鍵計算機】--》【屬性】--》【高級系統設置】--》【高級】--》【環境變量】--》【在第二個內容框中找到 變量名爲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

#include <iostream>
int main(void)
{
std::cout<<"Hello world";
 }
C++
#include <stdio.h>
int main(void)
{
printf("\nhello world!");
return 0;
}
C
public class HelloWorld{
// 程序的入口
public static void main(String args[]){
// 向控制檯輸出信息
System.out.println("Hello World!");
}
}
Java
<?php  
           echo "hello world!";  
?>  
PHP
puts "Hello world."  
Ruby
package main

import "fmt"

func main(){

    fmt.Printf("Hello World!\n God Bless You!");

}
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 store data in memory.This data can then be used throughout your grogram.

聲明變量

#_*_coding:utf-8_*_
 
name = "Zero"

上述代碼聲明瞭一個變量,變量名爲:name,變量name的值爲:」Zero「

變量定義的規則:

  • 變量名只能是字母、數字或下劃線的任意組合
  • 變了名的第一個字符不能是數字
  • 如下關鍵字不能聲明爲變量名
['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 = "Zero"
 
name2 = name
print(name,name2)
 
name = "Jack"
 
print("What is the value of name2 now?")

7、字符編碼

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

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碼中的內容用一個字節保存、歐洲的字符用2個字節保存,東亞的字符用3個字節保存....

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

報錯: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庫支持,後面會說到各類庫,如今咱們先來看兩個簡單的。

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補全模塊

import sys
import readline
import rlcompleter

if sys.platform == 'darwin' and sys.version_info[0] == 2:
    readline.parse_and_bind("bind ^I rl_complete")
else:
    readline.parse_and_bind("tab: complete")  # linux and python3 on mac
from mac
#!/usr/bin/env python 
# python startup file 
import sys
import readline
import rlcompleter
import atexit
import os
# tab completion 
 readline.parse_and_bind('tab: complete')
# history file 
histfile = os.path.join(os.environ['HOME'], '.pythonhistory')
try:
    readline.read_history_file(histfile)
except IOError:
    pass
atexit.register(readline.write_history_file, histfile)
del os, histfile, readline, rlcompleter
from 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/3.x/site-packages目錄下,這個目錄在不一樣的OS裏放的位置不同,用print(sys.path)能夠查看Python的環境變量列表。

10、.pyc文件是什麼?

一、Python是一門解釋型語言?

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

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

二、解釋型語言和編譯型語言

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

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

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

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

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

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

三、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是一門先編譯後解釋的語言。

四、簡述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爲虛數,數學中表示覆數是什麼?用i表示虛數。

int(整型)

     在32位系統上,整數的位數爲32位,取值範圍爲-2**31~2**31-1,即-2147483648~2147483647

     在64位系統上,整數的位數爲64位,取值範圍爲-2**63~2**63-1,即-9223372036854775808~922337203685477807

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 = "Zero"
print "i am %s " % name
  
#輸出: i am Zero

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

三種格式化輸出

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


name = input("name:")
#raw_input 2.x == input 3.x
#iput 2.0 不建議使用
age = int (input("age(請輸入整數):")) #變量類型轉換
print(type(age) , type ( str(age)) ) #變量類型輸出
job = input ("job:")
salary = input ("salary:")

#格式化輸出1,注意輸出格式如:%s,%d,%f的區別
info = '''
-----------info of %s ------------
Name:%s
Age:%d
Job:%s
Salary:%s
'''%(name,name,age,job,salary)

print(info)

#格式化輸出2,官方建議使用這種輸出格式

info2 = '''
-----------info of {_name}----------
Name:{_name}
Age:{_age}
Job:{_job}
Salary:{_salary}
'''.format(
    _name=name,
    _age=age,
    _job=job,
    _salary=salary
)

print(info2)

#格式化輸出3

info3 = '''
-----------info of {0}------------
Name:{0}
Age:{1}
Job:{2}
Salary:{3}
'''.format(
    name,age,job,salary
)

print(info3)
View Code

字符串經常使用功能:

  • 移除空白
  • 分割
  • 長度
  • 索引
  • 切片

四、列表

建立列表:

name_list = ['Zero', 'one', 'two']
或
name_list = list(['Zero', 'one', 'two'])

基本操做:

  • 索引
  • 切片
  • 追加
  • 刪除
  • 長度
  • 循環
  • 包含

五、元組(不可變列表)

建立元組:

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 #相同爲0,不一樣爲1
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
View Code
*按位取反運算規則(按位取反再加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 == "Zero" and pwd == "cmd":
    print("歡迎,Zero!")
else:
    print("用戶名和密碼錯誤")
View Code

場景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!")
View Code

小結:

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

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

十4、表達式for loop

最簡單的循環10次

#_*_coding:utf-8_*_
__author__ = 'Zero'
 
 
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
View Code

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

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

需求2、仍是上面的程序,當時遇到大於5的循環次數就不走了,直接退出

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

十5、while loop

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

海枯石爛代碼

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

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

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

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

回到上面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("猜這麼屢次都不對,你個笨蛋.")
View Code

 十6、入門知識拾遺

一、bytes類型

二、三元運算

result = 值1 if 條件 else 值2

若是條件爲真:result = 值1

若是條件爲假:result = 值2

三、進制

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

計算機內存地址和爲何用十六進制?

爲何用十六進制

一、計算機硬件是0101二進制的,十六進制搞好是2的倍數,更容易表達一個命令或者數據。十六進制更簡短,由於換算的時候一位十六進制數能夠頂4位二進制數,也就是一個字節(八進制能夠用兩個十六進制表示)

二、最先規定ASCII字符集採用的就是8bit(後期擴展了,可是基礎單位仍是8bit),8bit用2個十六進制直接就能表達出來,無論越多仍是存儲都比其餘進制要方便。

三、計算機中CPU運算也是遵守ASCII字符集,以1六、3二、64這樣的方式在發展,所以數據交換的時候十六進制也顯得更好。

四、爲了統一規範,CPU、內存、硬盤咱們看到的都是採用十六進制計算。

十六進制用在哪裏?

一、網絡編程,數據交換的時候需對字節進行解析都是一個byte一個byte的處理,1個byte能夠用0XFF兩個十六進制表達。經過網絡抓包,能夠看到數據是經過十六進制傳輸的。

二、數據存儲,存儲到硬件中是0101的方式,存儲到系統中的表達方式都是byte方式。

三、一些經常使用值的定義,好比:咱們常常用到的html中color表達,就是用的十六進制方式,4個十六進制位能夠表達好幾百萬的顏色信息。

一切皆對象

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

因此,如下這些值都是對象:「Zero」、3八、[‘北京’,‘上海’。‘廣州’],而且是根據不一樣的類生成的對象。

十7、列表、元組操做

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

定義列表(中括號定義列表)

names = ['Zero',"one",'two']

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

>>> names[0]
'Zero'
>>> names[2]
'two'
>>> names[-1]
'two'
>>> names[-2] #還能夠倒着取
'one'

切片:(取多個元素)

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

追加

>>> names
['Zero', 'one', 'two', 'three', 'four', 'five']
>>> names.append("我是新來的")
>>> names
['Zero', 'one', 'two', 'three', 'four', 'fave', '我是新來的']

插入

>>> names
['Zero', 'one', 'two', 'three', 'four', 'five', '我是新來的']
>>> names.insert(2,"強行從two前面插入")
>>> names
['Zero', 'one', '強行從two前面插入', 'two', 'three', 'four', 'five', '我是新來的']
View Code

修改

>>> names
['Zero', 'one', '強行從two前面插入', 'two', 'three', '從two後面插入', 'four', 'five', '我是新來的']
>>> names[2] = "該換人了"
>>> names
['Zero', 'one', '該換人了', 'two', 'three', '從two後面插入', 'four', 'five', '我是新來的']
View Code

刪除

>>> del names[2] 
>>> names
['Zero', 'one', 'two', 'three', '從two後面插入', 'four', 'five', '我是新來的']
>>> del names[4]
>>> names
['Zero', 'one', 'two', 'three', 'four', 'five', '我是新來的']
>>> 
>>> names.remove("two") #刪除指定元素
>>> names
['Zero', 'one', 'three', 'four', 'five', '我是新來的']
>>> names.pop() #刪除列表最後一個值 
'我是新來的'
>>> names
['Zero', 'one', 'three', 'four', 'five']
View Code

擴展

>>> names
['Zero', 'one', 'two', 'three', 'four']
>>> b = [1,2,3]
>>> names.extend(b)
>>> names
['Zero', 'one', 'two', 'three', 'four', 1, 2, 3]
View Code

拷貝

>>> names
['Zero', 'one', 'two', 'three', 'four', 1, 2, 3]

>>> name_copy = names.copy()
>>> name_copy
['Zero', 'one', 'two', 'three', 'four', 1, 2, 3]
View Code

copy真的這麼簡單麼?

統計

>>> names
['Zero', 'one', 'two', 'three', 'four', 1, 2, 3]
>>> names.count("two")
2
View Code

排序&翻轉

>>> names
['Zero', 'one', 'two', 'three', 'two', 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
['Zero', 'one', 'two', 'three', 'two', '1', '2', '3']
>>> names.sort()
>>> names
['1', '2', '3', 'Zero', 'one', 'three', 'two', 'two']
>>> names.reverse() #反轉
>>> names
['two', 'two', 'three', 'one', 'Zero', '3', '2', '1']
View Code

獲取下標

>>> names
['two', 'two', 'three', 'one', 'Zero', '3', '2', '1']
>>> names.index("three")
2 #只返回找到的第一個下標
View Code

元組

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

語法:(採用小括號表示)

names = ("Zero","one","two")
View Code

程序練習

程序:購物車程序

需求:

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

十8、字符串操做

 特性:不可修改

name.capitalize()  首字母大寫
name.casefold()   大寫所有變小寫
name.center(50,"-")  輸出 '---------------------Alex Li----------------------'
name.count('lex') 統計 lex出現次數
name.encode()  將字符串編碼成bytes格式
name.endswith("Li")  判斷字符串是否以 Li結尾
 "Alex\tLi".expandtabs(10) 輸出'Alex      Li', 將\t轉換成多長的空格 
 name.find('A')  查找A,找到返回其索引, 找不到返回-1 

format :
    >>> msg = "my name is {}, and age is {}"
    >>> msg.format("alex",22)
    'my name is alex, and age is 22'
    >>> msg = "my name is {1}, and age is {0}"
    >>> msg.format("alex",22)
    'my name is 22, and age is alex'
    >>> msg = "my name is {name}, and age is {age}"
    >>> msg.format(age=22,name="ale")
    'my name is ale, and age is 22'
format_map
    >>> msg.format_map({'name':'alex','age':22})
    'my name is alex, and age is 22'


msg.index('a')  返回a所在字符串的索引
'9aA'.isalnum()   True

'9'.isdigit() 是否整數
name.isnumeric  
name.isprintable
name.isspace
name.istitle
name.isupper
 "|".join(['alex','jack','rain'])
'alex|jack|rain'


maketrans
    >>> intab = "aeiou"  #This is the string having actual characters. 
    >>> outtab = "12345" #This is the string having corresponding mapping character
    >>> trantab = str.maketrans(intab, outtab)
    >>> 
    >>> str = "this is string example....wow!!!"
    >>> str.translate(trantab)
    'th3s 3s str3ng 2x1mpl2....w4w!!!'

 msg.partition('is')   輸出 ('my name ', 'is', ' {name}, and age is {age}') 

 >>> "alex li, chinese name is lijie".replace("li","LI",1)
     'alex LI, chinese name is lijie'

 msg.swapcase 大小寫互換


 >>> msg.zfill(40)
'00000my name is {name}, and age is {age}'



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


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

十9、字典的操做

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

語法:

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

字典的特性:

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

增長

>>> 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)
View Code

程序練習

程序:三級菜單

要求:

  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]
View Code

二10、集合操做

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

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

經常使用操做

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

二11、文件操做

對文件操做流程

  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
當我年少輕狂
View Code

基本操做

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

打開文件的模式有:

  • 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
View Code

with語句

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

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

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

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

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
原配置文件

二12、字符編碼與轉碼

詳細文章:

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

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

需知:

一、在Python 2.x 默認編碼是ASCII,Python 3.x 裏默認是Unicode

二、Unicode分爲utf-32(佔4個字節),utf-16(佔2個字節),utf-8(佔1-4個字節),因此utf-16就是如今最經常使用的Unicode版本,不過在文件裏存的仍是utf-8,由於utf-8省空間。

三、在Python 3.x 中encode,在轉碼的同時還會把string 變成bytes類型,decode在解碼的同時還會把bytes變回string。

上圖僅適用於Python 2.x

in Python 2.x
#-*-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 Python 3.x

二十3、函數的基本語法及特性

溫故知新

一、集合:

主要做用:

  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

二、元組

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

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

三、字典

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的內存地址那取值就能夠了。

四、字符編碼

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

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

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

背景提要

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

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

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

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

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

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

函數是什麼?

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

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

特性:

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

語法定義

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

能夠帶參數

#下面這段代碼
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)
View Code

二十4、函數參數與局部變量

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

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

默認參數

看下面代碼

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")
View Code

發現county這個參數基本都是「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

全局與局部變量

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

在定義局部變量的子程序內,局部變量起做用;在其餘地方全局變量起做用。

二十5、返回值

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

注意:

  1. 函數在執行過程當中只要遇到return語句,就會中止執行並返回結果,因此也能夠理解爲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)
View Code

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

沒錯,出錯了,爲何呢?

嵌套函數有什麼用呢?思考.....

二十6、遞歸

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

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

遞歸特性:

  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)
View Code

二十6、匿名函數

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

#這段代碼
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

二十7、函數式編程介紹

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

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

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

1、定義

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

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

         (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)

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

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

二十8、高階函數

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

def add(x,y,f):
    return f(x) + f(y)
 
 
res = add(3,-6,abs)
print(res)

二十9、內置參數

內置參數詳解 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)
#
#


#memoryview
#usage:
#>>> memoryview(b'abcd')
#<memory at 0x104069648>
#在進行切片並賦值數據時,不須要從新copy原列表數據,能夠直接映射原數據內存,
import time
for n in (100000, 200000, 300000, 400000):
    data = b'x'*n
    start = time.time()
    b = data
    while b:
        b = b[1:]
    print('bytes', n, time.time()-start)

for n in (100000, 200000, 300000, 400000):
    data = b'x'*n
    start = time.time()
    b = memoryview(data)
    while b:
        b = b[1:]
    print('memoryview', n, time.time()-start)
內置參數的幾個用法

三10、迭代器&生成器

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

列表表達式:

我如今有個需求,看列表[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,3,4,6,7,7,8,9,11]

for index,i in enumerate(a):
    a[index] +=1
print(a)

原值修改
>>> 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>

建立L和g的區別僅在於最外層[] 和 () ,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
View Code

咱們講過,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
View Code

因此,咱們建立了一個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'
View Code

注意,賦值語句:

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
View Code

仔細觀察,能夠看出,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' 
View Code

這就會死定義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
View Code

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

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

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

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

>>> 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
View Code

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

還可經過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循環的數據類型用如下幾種:

一類是集合數據類型,如list、tuple、dict、set、str等;

一類是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
View Code

生成器都是Iterator對象,但list、dict、str雖然是Iterable,卻不是Iterator。

把list、dict、str等Iterable變成Iterator能夠使用iter()函數:

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

你可能會問,爲何list、dict、str等數據類型不是Iterator?

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

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

小結

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

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

集合數據類型如list、dict、str等時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
View Code

三11、裝飾器

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

def home():
    print("---首頁----")
 
def america():
    print("----歐美專區----")
 
def japan():
    print("----日韓專區----")
 
def henan():
    print("----河南專區----")
View Code

視頻剛上線初期,爲了吸引用戶,大家採起了免費政策,全部視頻免費觀看,迅速吸引了一大批用戶,免費一段時間後,天天巨大的寬帶費用公司承受不了了,因此準備對比較受歡迎的幾個板塊收費,其中包括」歐美「和」河南「專區,你拿到這個需求後,想了想,想收費得先讓其進行用戶認證,認證經過後,在斷定這個用戶是不是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()
View Code

此時你信心滿滿的把這個代碼提交給你的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)
View Code

你很開心,終於實現了老闆的要求,不改變原功能代碼的前提下,給功能加上了驗證,此時,媳婦回來了,後面還跟着老王,你兩家關係很是好,老王常常來串門,老王也是碼農,你跟他分享了你寫的代碼,興奮的等他看完誇獎你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時,其實至關於調用了longin(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函數
View Code

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

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

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

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

能夠把下面代碼去掉

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

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

@login
def america():
    #login() #執行前加上驗證
    print("----歐美專區----")
 
def japan():
    print("----日韓專區----")
 
@login
def henan():
    #login() #執行前加上驗證
    print("----河南專區----")
View Code

效果是同樣的。

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

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

老王:那必然呀,你調用henan時,實際上是至關於調用login,你的henan第一次調用時henan = login(henan),login 就返回了inner的內存地址,第二次用戶本身調用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")
View Code

次日早上,產品經理又提了新的需求,要容許用戶選擇用qq、weibo、wexin認證,此時的你,已深諳裝飾器各類裝備技巧,輕鬆實現了新的需求。

#_*_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")
帶參數的裝飾器

三12、Json & pickle 數據序列化

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

三十3、軟件目錄結構規範

爲何要設計好目錄結構?

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

  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)其次目錄testes/存放單元測試代碼;(3)程序的入口最好命名爲main.py。
  3. docs/:存放一些文檔。
  4. setup.py:安裝、部署、打包的腳本。
  5. requirements.txt:存放軟件依賴的外部Python包列表。
  6. README:項目說明文件。
  7. 除此以外,有一些方案給出了更加多的內容。好比LICENSE.txt,ChangeLog.txt文件等,我沒有列在這裏,由於這些東西主要是項目開源的時候須要用到。若是你想寫一個開源軟件,目錄該如何組織,能夠參考這篇文章。
https://jeffknupp.com/blog/2013/08/16/open-sourcing-a-python-project-the-right-way/

關於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包依賴都裝好了。具體格式說明:點這裏。

https://pip.readthedocs.io/en/1.1/requirements.html

關於配置文件的使用方法

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

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

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

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

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

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

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

程序練習:

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

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

示例代碼:

 https://github.com/triaquae/py3_training/tree/master/atm

簡易流程圖:

https://www.processon.com/view/link/589eb841e4b0999184934329
相關文章
相關標籤/搜索