Python入門 - 2(真0基礎)
一 前言
上一章說了那麽多,不知道大家是否有躍躍欲試的沖動。說實話,編程就像英語一樣,只是一門語言,如果不用出來,能力會衰退。就像荒島沒人對話,時間長了很可能就不會說話了。如果不能自己寫出來,永遠就是別人的東西。這就是為什麽很多人看了網絡上那麽多視頻都學不會的原因。是的,可能你也正在看,甚至跟著視頻將代碼敲了下來,但是這些都是別人的。試著問自己一下,關了視頻再寫一遍,能做到嗎?大概率是做不到的。。。怎麽辦?多寫?寫到吐?NO!!! base on project的學習計劃才是有意義的。盲目多寫,或者盲目寫重復的內容只能讓你記住了一部分的寫法,思路不是你的。找一個目標,你喜歡的方向,往那個方向去研究,找那個方向的project去做。舉個例子,我喜歡炒股炒外匯,那就去看一些關於量化交易系統的書或者文章,試著寫一個自動買賣的小系統。為什麽要這樣做?因為持久的學習需要滿足感,需要自信心。當自己寫的程序能跑起來時,那種快感是難以言喻的。當然,無論選擇哪個方向,基礎還是必須打好的,沒有這些基礎,根本無法支撐你走得更遠,更無法達到你的目標,所以,加油!堅持!
二 三元運算(裝13用!!!~~~)
上一章的流程控制,是不是一個if...else...就得分好幾行來寫,難道就不能有一行寫完的表達方式?必須有啊,寫出來還特別有逼格。別人幾百行實現的功能,幾十行就實現了,是不是短小精悍?
# 正常寫法 if 1 < 2: val = 1 else: val = 2 # 三元運算 val = 1 if 1 < 2 else 2
三 字符編碼
大家在使用電腦的過程肯定都見過一個現象,就是“亂碼”。好好地解壓一個文件,名字變成了亂碼。或者打開一個word文檔,裏面是各種不知名的字符。這些問題大概率都是和字符編碼相關的。最形象的說法就是,你有一把鎖配套一把鑰匙,鎖只能用你的鑰匙來開。要是別人用其他鑰匙硬塞進去,只會弄壞鎖本身。所以,什麽鎖配什麽鑰匙,“上鎖”“解鎖”都用同一把鑰匙就不會出問題了。
1、為什麽需要有字符編碼?
無論你是否科班出身,是否有過編程的經驗,只要你懂點電腦的基本常識,你大概率都會知道計算機只認識二進制,也就是一堆“010101010101”。那西方的英語、西班牙語,東方的國語、韓語、日語等語言,計算機又是怎麽明白的呢?就拿Python作為例子,為什麽我們寫英語,電腦能夠執行?如果說計算機只懂得0和1,是不是會像摩斯密碼一樣,存在一個對照表將我們輸入的內容轉換成0和1?從而破譯出答案來?是的,這就是字符編碼存在的價值。下面是各種字符編碼的簡介,是按照【時間順序】逐一介紹。
2、ASCII碼(American Standard Code for Information Interchange)
最初的版本大概長這個樣子↓↓↓
ASCII碼最早在美國被提出,當時發明者根本就沒想過以後中國人也能用上電腦,所以除了英文字母和一些特殊字符能夠對應上,中文和其他語言均沒有對應。後來又拓展了一些,但依然沒有支持其他語言的對應↓↓↓
3、GBK(Guo Biao Kuozhan國標擴展的首字母,不要Z可能是因為不好讀吧~~~>.<)
從0開始到255,一共256位就是ASCII碼的極限了,但就連一個邊旁部首都沒有,中國人不樂意啊,中國人也會強大啊,憑什麽我們不能有自己的一席之地?一怒之下,自己搞了個GBK,把中文收編進去,而且不能和ASCII碼有沖突。緊接著其他國家的各種碼也出來了。韓國的EUC-KR,日本的Shift_JIS等等。
4、Unicode
碼是越來越多了,難道以後每個電腦都要預裝這麽多不同的碼麽?更重要的是,預裝一個別的國家的東西,那種不安全感,就像要強迫出廠的蘋果手機預裝小米軟件一樣。所以,針對這種需求,萬國碼出現了。終於有一個看上去啥都有的百科全書了。但是有一部分人開始不高興了。你可能不知道,ASCII碼對於英語字符是非常節省的,一個字符只需要1個Bytes,也就是1個B。而在Unicode裏,為了配合其他語言,一個英語字符變成了2個B。無端端多了一倍。。。一兩個字符不是問題,但問題是,多起來怎麽辦?!在那個年代,內存是極其珍貴的,網絡是很慢的,內容多了,肯定慢。我本來可以存的內容,因為Unicode這麽一搞,能存的東西就減半了。有解決方案嗎?繼續看下去。。。
Bit,計算機中最小的表示單位 8Bit = 1Bytes 字節,最小的存儲單位,1Bytes縮寫為1B 1KB = 1024B 1MB = 1024KB 1GB = 1024MB 1TB = 1024GB 1PB = 1024TB 1EB = 1024PB 1ZB = 1024EB 1YB = 1024ZB 1BB = 1024YB
5、UTF-8(Unicode Transformation Format)
為了節約內存,UTF-8誕生了,對Unicode進行了一些加工,將英文字母編寫成1個字節,將漢字編寫成3個字節,對非常生僻的字符才用4-6個字節。這樣解決了英文字母占用內存倍增的問題,也讓各國的編碼整合了。算是現時最完善的編碼了。但是這一切都是按時間順序發生進而完善的,那原本那些已經用GBK、ASCII編碼存好的程序怎麽辦?如果硬生生換編碼,從硬盤讀取到內存時程序肯定會出現各種異常,可能冒這個險嗎?根本不可能!!!幾百萬行代碼重新寫嗎?想太多!!!那怎麽辦?(咋問題這麽多(-_ -!!!))其實上面的內容已經有答案了。Unicode就是答案。反正Unicode整合了這麽多個國家的編碼,只要用Unicode這把萬能鑰匙去解鎖,就一定能不損壞鎖又能開鎖。現在的計算機基本上是這麽幹的,在內存中用的是Unicode,在硬盤中和傳輸中用的是UTF-8。舉個例子,我們打開一個文件,文件會進入內存,這個時候會轉換為Unicode。然後在保存時,文件會進入硬盤,這個時候就會轉換成UTF-8。
6、字符編碼的轉換
總結:什麽鑰匙開什麽鎖。用什麽編碼存到硬盤的,就得用什麽編碼取出來。
最後拋出一個問題。假設現在有兩臺電腦,一臺是日本產的,預裝有Unicode和Shift-JIS日本編碼,一臺是中國產的,預裝有Unicode和GBK中文編碼。如果在中國產的電腦上編寫好文件,在日本產的電腦上打開,能顯示中文嗎?
答案是可以的。文件會先從GBK轉換成Unicode存到內存裏,可以讀取到中文,自然可以顯示中文。
四 文件處理
讀寫文件在Python中是常見的事情。因為暫時不知道數據庫如何使用,所以很多臨時的數據只能夠格式化存到文檔中(也就是存到硬盤裏,不用怕存到內存一斷電就沒了)。以下是一般的文件操作思路:
#1 打開文件,得到文件內容並賦值給一個變量 #2 修改文件內容,增刪改查等方式 #3 將修改的文件內容存回文件 #4 關閉文件
1、讀文件,“r”模式
#1 打開文件nick.txt,並賦值給變量f,方便後續操作用 f = open(‘nick.txt‘, ‘r‘, encoding=‘utf-8‘) # 默認打開模式就為r #2 通過read命令獲得變量f的內容,並賦值給變量data,方便對內容進行增刪改查 data = f.read() # 讀取所有內容 data = f.readline() # 讀取一行內容 data = f.readlines() # 讀取每一行內容,並存放在列表 #3 關閉文件 f.close()
2、寫文件,“w”模式
#1 以“w”模式打開文件nick.txt,並賦值給變量f,方便後續操作用 f = open(‘nick.txt‘, ‘w‘, encoding=‘utf-8‘) #2 通過write命令覆蓋變量f的內容 f.write("01010101") # 註意!原內容會被覆蓋! f.writelines("0101010101") # 當需要將多行內容寫入txt文件時用這個 #3 關閉文件 f.close()
3、加內容,“a”模式
#1 以“a”模式打開文件nick.txt,並賦值給變量f,方便後續操作用 f = open(‘nick.txt‘, ‘a‘, encoding=‘utf-8‘) #2 通過write命令覆蓋變量f的內容 f.write("\n01010101") # 註意!新內容會追加在原內容的後面! #3 關閉文件 f.close()
五 函數(終於要邁入一個稍微有點難度的部分喇~~~散花~~~)
能學到這裏,證明你對最最最基礎的語法已經有了一定的了解。現在寫幾十行甚至上百行代碼實現一些基本功能已經不是問題了。或許你已經感受到,寫代碼時經常會重復用到一些語句,而且頻次還較高,這樣看起來很low,如果能有辦法將這些常用的語句整合到一個地方,然後每次調用這個地方的內容,就不用重復寫同一些代碼了,對不?所以函數就出現了!!!這裏的函數不是數學中常說的函數,而是這類重復功能歸集到一起的統稱。
這部分之所以說是上升了一個難度,並不是說內容難,而是因為你如果不用函數,依然可以實現功能。而用函數能讓代碼優雅,更容易被維護。這是一種思維層次的改變,並不是你學懂了就能用出來的。換句話說,如果你沒有編程經驗,你怎麽知道某些方法會重復?你怎麽知道某些代碼會被經常使用?所以沒有經驗的時候,是無法順利用出函數的。對於入門者,這是一道坎!只有告訴自己,即使代碼low,先寫,重復就重復,通過第二版去將重復的內容寫成函數,不斷修改和優化代碼。切忌一步登天。也不要因為寫不出函數而氣餒。說到底,就是積累得還不夠而已。解釋完函數存在意義,我們一起來看看函數的分類。
1、函數分類
# 使用函數前必須要先定義函數,再使用。就像先有了一只籃球,才能開始一場籃球比賽一樣。定義函數,可以是內置的,也可以是自定義的: #1 內置函數 還記得之前我們在人與機器交互那小節中提及的input功能嗎?其實這裏的input就是一種函數,而且是被內置好的,也就是啟動Python時就會附帶定義好的。這是為了方便開發時,不用再針對一些簡單的功能重復定義。對於內置函數,我們可以拿來就用而無需事先定義,見下表。 #2 自定義函數 由於內置函數的功能都相對簡單,並無法應對復雜的需求。這就需要我們自己根據需求,事先定制好我們自己的函數來實現某種功能,在遇到應用場景時,調用自定義的函數即可。例如在一次計算中,我們可以定義一個函數來處理加法,只需要將內容傳進去,就會返回加法的結果。
以下是常用的內置函數↓↓↓
2、如何自定義函數
# 邏輯大概是這樣的: def 函數名(參數1,參數2,參數3,...): # 定義了函數,函數名最好能夠精煉概括要做的事情 ‘‘‘註釋‘‘‘ 函數體 # 具體函數要做的事情,函數的主體內容 return 返回的值 # 讓函數結束時返回一個東西,可以返回值,甚至函數,遇到return語句,函數就會停止執行並返回結果
# 舉個栗子 def id_verification(account, password): ””” 定義了一個id驗證函數用於驗證輸入賬號是否正確。 :param account: 賬號 :param password: 密碼 :return: 認證結果 ””” if account == ‘nick‘ and password == ‘1234‘: return ‘Welcome back!‘ else: return ‘invalid account or password‘
3、調用函數
# 定義了函數就是為了用,不然定義來幹嘛對不對?那如何調用呢?就像上面的栗子,如果要調用id_verification函數,可以這樣寫 account = input(‘account:‘).strip() password = input(‘password:‘).strip() id_verification(account, password) # 調用函數,並傳入account和password兩個參數,如果僅僅只有id_verification,沒有括號,函數是不會被調用的 # 調用函數後,參數會被送進函數進行運算。最終得出結果取決於自定義函數的返回值。有時候定義函數不一定要傳入參數。像下面的例子,括號裏是空的。
4、函數參數
# 談到函數的參數,就要知道什麽叫實參和形參,簡單理解即可 def calc(x, y): # 這裏的x和y就是形參,等著別人賦值給自己 res = x ** y return res c = calc(1, 2) # 這裏的1和2就是實參,等著傳值給別人 print(c)
# 了解完什麽是形參和實參後,我們來看看一些更實用的例子。 def register(name, age, country): # 定義一個函數,讓用戶傳入基礎資料並打印 print("name:", name) print("age:", age) print("country:", country) register("nick", 18, "China") ... # 關鍵參數 # 如果100個用戶都是來自於中國,那其實可以設置一個默認值,這個時候就出現了關鍵參數 def register(name, age, country="China"): print("name:", name) print("age:", age) print("country:", country) register("nick", 18) # 這樣就不用輸入了~100個用戶都省了事 register("alex", 18, country="USA") # 當出現一個特殊的,這樣寫就好了 ... # 非固定參數 # 對於在定義函數時不知道將來會傳什麽進來的,可以這樣寫 def register(name, age, *args, **kwargs): print(name, age, args, kwargs) # 調用函數 register("nick", 18, "China", "Guangdong", course="Python", gender="male") # 輸出 # nick 18 (China, Guangdong) {‘course‘= ‘Python‘, ‘gender‘= ‘male‘} ... # *args會生成一個元組 # **kwargs會生成一個字典
5、嵌套函數
# 其實在函數裏面,也是可以調用已定義好的函數,也可以定義函數。 def f1(): # 定義函數f1 print(‘f1‘) def f2(): # 定義函數f2 def f3(): # 在函數f2內定義函數f3 print(‘f3‘) f3() # 執行函數f3,如果沒有這一行,則不會執行函數f3 print(‘f2‘) def f4(): f1() f2() # 調用已定義好的函數f2 # 這種函數套函數,就是嵌套函數,在以後的編程會較為常用,很鍛煉邏輯的哦~
6、高階函數
# 函數裏面的參數不僅可以接收變量,也可以接收其他函數,一起看這個高階函數例子 def add(x, y, func): print(func(x) + func(y)) # 兩數絕對值相加 add(1, 2, abs) # abs是內置函數,代表絕對值
7、遞歸
# 如果一個函數在內部調取自己,就叫遞歸 def calc(n) print(n) if int(n / 2) == 0: return n return calc(int(n / 2)) calc(10) #輸出 10 5 2 1
8、名稱空間
# 上面的例子裏存在一個問題,我們可以直接輸入f1(), f2()或f4()來調用函數,但我們無法直接輸入f3()調用函數f3,這樣會報錯,那是為什麽呢? # 簡單來說,就是因為函數f3在函數f2內,函數f3在局部,並不是全局。在全局的位置查看不了局部,但是在局部可以查看全局。就像上面的函數f4裏,可以在局部調用全局的函數f1和f2。 # 復雜來說,就需要引入名稱空間這個新名詞。名稱空間儲存的是變量名和變量值的關系。例如n = 1,名稱空間就儲存著n和1的關系。 # 計算機在查找名稱空間的過程是有順序的,先查看局部的名稱空間,然後才是全局的名稱空間,這就是為什麽當計算機在找到局部名稱空間時,可以找到全局名稱空間。反之則不可以。屬於先後順序問題! # 完整來說,整個名稱空間查找順序可以簡寫為4個字母:LEGB 也稱為作用域。 Locals 是函數內的名稱空間 Enclosing 上一級嵌套函數的名稱空間(閉包中常見,後面會講閉包) Globals 全局變量,函數定義所在模塊的名稱空間 Builtins 內置模塊的名稱空間
9、匿名函數
# 記住一個詞,叫lambda;lambda函數常與其他函數搭配使用,從而節省代碼量,看一下下面的例子。 # 一般來說,如果要計算一堆數各自的平方,我們需要先定義一個計算平方的函數,然後再通過map內置函數,將數導進去進行平方,看代碼↓↓↓ def square(x): return x ** 2 list(map(square, [1, 2, 3, 4, 5])) # 由於是內置函數,不用定義直接使用,得到一個列表 # 如果用lambda,就可以節省一些代碼,不用定義square函數,直接套進map函數使用 list(map(lambda x: x ** 2, [1, 2, 3, 4, 5])) # 對於那種不常用的功能,可以通過lambda來節省代碼,用完即棄。
10、閉包(開始有點深度了哦~)
# 函數裏套了函數,外層函數被調用時,返回了內層函數的內存地址,執行內層函數時,內層函數調用外層函數局部變量的值,這種關系就是閉包。一起看下面這個例子 def outer(x): def inner(y): return x + y return inner # 只返回了inner的內存地址,沒有括號,沒有執行inner函數 a = outer(2) # 執行了外層outer函數 print(a) 返回了inner的內存地址 print(a(3)) # 執行inner函數,inner函數調用了外層函數的局部變量x = 2 返回了5
11、裝飾器(又叫做語法糖,是函數章節較難的部分,很難啃~~做好心理準備,啃下去你就贏了~~>3<)
很多程序已經寫完,且經過大量用戶使用後,已無其他bug反饋,就可以認為該程序已經能穩定運行了。如果要增加新功能,有一個約定俗成的原則就是不能修改已經穩定運行的程序,只能加,不能改,畢竟誰都不是神,誰都無法保證改了之後是否會產生新的bug,特別是上百萬行代碼的程序,一旦發現新的bug,debug起來不是開玩笑的。因此,必須要用特定的方法去加入新功能,這個時候就有了裝飾器存在的價值。一起看下面這個例子。
# 假設我一開始寫了這些代碼(假設有幾十萬行),並且經過了長久驗證,已穩定運行。 def bar(): # 定義了函數bar,用來打印某段話。 print("I am bar") # 假設這裏是幾十萬行代碼,有各種復雜的邏輯 ...
bar() # 執行該函數
# 如果我突然想加一個功能,希望用戶輸入自己的名字後,才執行這幾十萬行代碼,我不能動這些穩定運行的代碼。所以我只能用裝飾器,加功能。我們先感性認識一下裝飾器長什麽樣子。接下去會一步一步解釋。 def login(func): # 在原本的幾十萬行代碼上,加入了這麽一個【裝飾器】(函數) def collect_name(*args, **kwargs): # 函數裏套了函數 input("name:") # 讓用戶輸入名字 return func(*args, **kwargs) # 返回了外層函數參數名的函數(與閉包概念類似) return collect_name # 返回內層函數的內存地址,註意這裏沒有括號,所以是返回內存地址,而不是執行函數 @login # 語法糖,讓下面的函數不止運行自己,還運行與語法糖同名的函數 def bar(): # 定義了函數bar,用來打印某段話。 print("I am bar") # 假設這裏是幾十萬行代碼,有各種復雜的邏輯 ... bar() # 執行該函數,調用bar函數的同時,調用login函數,這樣就做到了沒有動原本的代碼,又增加了新功能的目的
# 下面我們來一步一步分析這個運行過程,請按照【數字順序】閱讀,建議多看幾遍,一遍是看不懂的 def login(func): # 2、因為語法糖的原因,這裏的函數綁定成login(bar) def collect_name(*args, **kwargs): # 5、執行了login函數內部的collect_name函數 input("name:") # 6、讓用戶輸入名字 return func(*args, **kwargs) # 7、執行bar函數 return collect_name # 3、不執行內部函數,直接將collect_name內存地址(不帶括號時)返回 @login # 1、程序經過了上面的函數login,再來到這個語法糖。這個語法糖的目的是綁定下面這個函數bar,當執行下面這個函數bar時,也同時調用與語法糖同名的函數login。 def bar(): print("I am bar") # 8、執行並打印 ... bar() # 4、執行該函數,實際上會執行了函數bar本身,也執行了函數login(bar)(),也就是collect_name函數
四 生成器和叠代器
# 生成器 g = (x * x for x in range(10)) >>>next(g) 1 >>>next(g) 4 >>>next(g) 9 >>>next(g) 16 >>>next(g) 25 # 如果所有值都需要next去調出,會瘋掉的吧。不如用for,值用完了還不會報錯 g = (x * x for x in range(10)) for n in g: print(n)
# 叠代器 # 判斷一個對象是否為可叠代對象 from collections import Iterable a = isinstance([], Iterable) print(a) # 返回True # 判斷一個對象是否為叠代器 from collections import Iterable b = isinstance([], Iterator) print(b) # 返回False # 將其轉成叠代器,用itor函數 from collections import Iterable b = isinstance(iter([]), Iterator) print(b) # 返回True
五 模塊
終於送走了函數,說明在中級的路上已越走越穩了。別忘記多做project,將上面的內容用在實戰中。有一件事是可以肯定的,如果你曾經用過某個知識點,並且解決了問題,這個知識點會記得比其他都要牢固。不斷用,不斷試錯。加油!!!
模塊這一部分,簡直就是Python的精華所在。為什麽近年來Python越來越多人用?那是因為不同的功能模塊越來越完善。(不禁感嘆這個世界牛人真多啊~~~)大神們通過自己的努力,將寫好的Python文件打包,放到網上,讓大家隨意下載使用。這些模塊覆蓋的細分領域越來越廣,從金融、醫療、數學到高新科技,幾乎一切你能想象的領域都有現成的模塊可以下載。大家如果想多了解更多模塊可以到這個網址https://pypi.python.org/pypi,根據自己喜歡的方向去尋找吧~~或許在不久的將來,你也能上傳你的作品。
模塊的存在大大節省了我們的開發時間,畢竟大神已經為我們準備好的工具,不用白不用,對吧?那我們先來看看模塊分了幾種:
1、模塊分類
# 內置標準模塊。有一些模塊在安裝Python時就會一並裝入。可以理解為官方版本的模塊。 # 第三方開源模塊。由世界各地的大神撰寫並上傳,我們可以通過Pycharm等下載安裝使用。 # 自定義模塊。就是自己寫出來的程序,自己打包,自己用。
2、模塊調用
# 有不少表達式可以用來導入模塊,根據不同情況而定,常用的有以下幾種: import module from module import settings from . import module
# 是時候動起來了。快!動手打開Pycharm,建個文件夾printer,文件夾裏新建兩個py文件,分別寫入以下內容。如下 # printer文件夾 # test.py文件 from hello import say_hi say_hi() # hello.py文件 def say_hi(): print("hello world") # 概括點來說,這兩個文件其實可以看作是一個程序,目的是打印某句話。test文件作為程序入口,調用其他模塊來輔助實現這個功能。
# 包(Package) # 上面的例子,我們用了一個文件夾,兩個py文件,實現了打印某句話的功能程序。這類打印功能我們就統一放在printer這個文件夾裏。像這樣一個文件夾裏存放多個模塊文件,就稱這個文件夾為【包】 # 上面的printer文件夾,為了能成為包,還需要在文件夾中加入__init__.py文件,從而告訴程序這是個包 # 像一些比較大型的項目,如微信等,也是將不同功能用不同包分開,例如朋友圈功能和聊天功能分開等。。然後包和包之間互相調用來實現功能。這是為了更加方便運維團隊維護代碼
# 為了調取不同包裏的模塊,有時候需要鋪設好一條路。就像鐵路一樣,通了才有火車的身影 # 下面的例子,為了能夠讀取到另外一個文件夾account下的json文件,我們需要鋪出一條路給程序,為此需要用到兩個內置模塊,os和sys,下面就導入一下 import sys import os # 當前文件路徑向上返回兩級,將路徑賦值於DIR(大寫表示常量,代表不變) DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 將這條路加入到環境變量裏面,這樣Python才會去找這條路找文件 sys.path.append(DIR) # 往DIR路徑後加入account和json.json,拼接出json文件的完整路徑,可以直接用於open os.path.join(DIR, ‘account‘, ‘json.json‘)
3、time模塊
# time模塊是常常用來顯示、計算各種格式的時間,下面是幾個常用的,我們暫時不求多,只求用得著 time.time() # 返回當前時間的時間戳(就是一串數字) time.sleep() # 延遲執行,括號裏寫上時間即可,單位為秒。 time.strftime() # 舉例:time.strftime("%Y-%m-%d %X", time.localtime()) # 輸出‘2018-07-06 00:00:00‘
4、random模塊
# 直接來看兩個例子 # 生成隨機6位數密碼,是不是和一些網站登錄時要你輸入的驗證碼很像 import random import string numbers = " ".join(random.sample(string.ascii_lowercase + string.digits, 6)) print(numbers) # 這樣每次打印都會是不同的6位數字或字母,而且沒有空格 # 洗牌功能 import random a = [0, 1, 2, 3, 4, 5] random.shuffle(a) print(a) # 列表a的順序會被打亂
5、json模塊
# json模塊可以存儲字典,而之前我們常用的txt文件存不了字典 import json data = {"name": "nick", "age": 18} # 將data寫入json文件 with open("nick.json", "w", encoding="utf-8") as db: json.dump(data, db) db.close() # 讀取nick.json文件中的字典,並賦值給nick_data with open("nick.json", "r", encoding="utf-8") as db: nick_data = json.load() db.close()
6、logging模塊
# logging模塊是非常常用的生成日誌的模塊。程序執行時,如果沒有日誌記錄,有很多信息會有缺失,甚至不清楚誰登陸過,誰做過什麽,這樣是非常不安全的。因此,這個模塊十分十分重要。看下面的步驟,可以配置好不同的日誌內容 # 下面這個例子,是配置日誌內容的過程,目的是在文件和Pycharm消息框中同時輸出內容,不妨復制到Pycharm試一試 import logging # 1. 生成logger對象 logger = logging.getLogger("web") # 相當於給日誌起了個名字web logger.setLevel(logging.DEBUG) # 如果不設置默認級別是WARNING,此為全局 # 2. 生成handler對象 ch = logging.StreamHandler() # 輸出到屏幕 ch.setLevel(logging.INFO) # 給不同輸出途徑設置不同的輸出日誌級別,設置級別不能比全局的低 fh = logging.FileHandler("web.log") # 輸出到文件 fh.setLevel(logging.WARNING) # 給不同輸出途徑設置不同的輸出日誌級別,設置級別不能比全局的低 # 2.1 把handler對象綁定到logger logger.addHandler(ch) logger.addHandler(fh) # 3. 生成formatter對象,用於自定義格式化輸出內容 # 3.1 把formatter對象綁定handler對象 file_formatter = logging.Formatter(‘%(asctime)s - %(name)s - %(levelname)s - %(message)s‘) console_formatter = logging.Formatter(‘%(asctime)s - %(name)s - %(levelname)s - %(lineno)d - %(message)s‘) ch.setFormatter(console_formatter) fh.setFormatter(file_formatter) logger.error(‘test log‘) logger.error(‘test log 2‘)
7、re模塊
# 正則表達式也是一個常用的模塊,甚至有的Python開發書一上來第一章第一節就講正則表達式。爬蟲等工序到最後需要用正則表達式格式化輸出內容。不妨通過下面的例子看看,復制到Pycharm上玩一玩吧。不過,看完後盡量自己寫一遍哦! import re # re.match 從頭開始匹配 s = ‘abc1d3e‘ b = re.match(‘[0-9]‘, s) # 要求第一個值必須是數字,否則返回None print(‘b:‘, b) f = ‘12bdfd‘ c = re.match(‘[0-9]‘, f) # 默認只能匹配到一個值 print(‘c:‘, c) # re.search 匹配包含,全局匹配 e = re.search(‘[0-9]‘, s) print(‘e:‘, e) # re.findall 匹配上值,然後以列表形式保存 g = re.findall(‘[0-9]‘, s) print(‘g:‘, g) # re.split 以匹配到的字符當做列表分隔符 s = ‘alex22jack23rain31jinxin50|mack-Oldboy‘ print(re.split(‘\d+|\||\W| ‘, s)) # ‘|‘本身作為或標識符,需要前面加‘\‘才能用於分隔 s = ‘alex22jack23rain\jinxin50|mack-Oldboy‘ print(re.split(‘\d+|\\\\|\||\W| ‘, s)) # ‘\‘本身作為標識符需要用4個才能表示一個 # re.sub 匹配字符並替換 s = ‘alex22jack23rain31jinxin50|mack-Oldboy‘ print(re.sub(‘\d+|\||\W‘, ‘_‘, s)) # 替換掉數字 h = ‘9-2*5/3+7/3*99/4*2998+10*568/14‘ print(re.split(‘[-\*/+]‘, h)) print(re.split(‘\W‘, h)) i = "[email protected]" j = re.fullmatch("\w+@\w+\.(com|cn|edu|org)", i) print(j)
Python入門 - 2(真0基礎)