友情提示:本文針對的是非編程零基礎的朋友,能夠幫助咱們快速瞭解Python語法,接着就能夠快樂的投入到實戰環節了。若是是零基礎,仍是老老實實看書最爲穩妥。html
偶然在知乎上看到了一些好玩的Python項目(學 Python 都用來幹嗎的?),讓我對Python產生了些許興趣。距離北漂實習還有兩個月時間,正好能夠在這段空閒時間裏學一學。若是能作出些小工具,說不定對工做還有幫助,何樂而不爲呢?python
關於環境的安裝和IDE就很少說了,網上有不少教程。這裏貼出一篇博客,你們按裏面的步驟安裝就行:VSCode搭建Python開發環境。使用VSCode主要是由於免費,並且有大量插件能夠下載,你們能夠盡情的定製本身的IDE。若是曾經沒有使用過VSCode,最好多瞭解下哪些必須的插件,優化本身的Coding體驗。好比:Python插件推薦。正則表達式
環境搭建好後,就能夠愉快地敲代碼了。VSCode須要本身建立Python文件,以.py爲後綴。Ctrl+F5運行程序,F5調試程序。算法
單行註釋:#編程
多行註釋:''' (三個英文單引號開頭,三個英文單引號結尾)json
# 這是單行註釋 ''' 這是多行註釋 '''
Python的變量定義不須要顯式指明數據類型,直接【變量名=值】便可。注意變量名分大小寫,如Name和name不是同一個變量。緩存
name = "小王" print(name) # 輸出 小王
Python提供6種基礎的數據類型:數字類型(number)、字符串類型(string)、列表(list)、元組(tuple)、字典(dictionary)、集合(set)。其中數字類型還包括三種數值類型:整型(int)、浮點型(float)、複數類型(complex)。安全
列表、元組那些咱們留在容器那一節裏面講,先看看數字類型。數據結構
浮點型表示小數,咱們建立一個浮點型變量,再經過type函數看一看它的類型:閉包
pi = 3.1415926 print(type(pi)) # 輸出<class 'float'>
int整數型就不說了,其爲Integer的縮寫。
複數類型,所謂複數就是咱們中學學的,實數+虛數,好比:
x = 10+1.2j # 虛數以j或J結尾 print(type(x)) # 輸出<class 'complex'>
剛開始接觸複數時,很納悶爲啥會有這種類型,到底有啥實際做用,遂百度了一番:
mzy0324:微電子方面的運算基本所有都是複數運算。
hilevel:至少複數用來計算向量的旋轉要比矩陣方便多了。科學計算和物理應該會用獲得吧。PS:我常常把Python當帶編程功能的計算器用,用來調試純粹的數學算法挺方便的。
morris88:Python 的一大應用領域,主要是科學計算,主要用於太空宇航、銀行等。
聯想到Python平時在算法、科學研究等領域應用頗多,因此也就明白了,只是本身沒使用的需求而已。
字符串類型的變量定義用一對雙引號或者單引號括起來。如:
x = "Hello Python" y = 'Hello Python' print(x,y) # 輸出Hello Python Hello Python
字符串內置函數:
函數 | 做用 |
---|---|
find(str[,start,end]) | 在字符串中查找子串str,可選參數start和end能夠限定範圍 |
count(str[,start,end]) | 在字符串中統計子串str的個數,可選參數start和end能夠限定範圍 |
replace(old,new[,count]) | 在字符串中用new子串替換old子串,可選參數count表明替換個數,默認所有替換 |
split(sep[,maxsplit]) | 用指定分隔符sep分割字符,返回一個列表,可選參數maxsplit表明分割幾回,默認所有 |
upper()、lower() | 轉換大小寫 |
join(序列) | 把序列中的元素用指定字符隔開並生成一個字符串。 |
startwith(prefix[,start,end]) | 判斷字符串中是否以prefix開頭,返回bool類型。還有一個endwith,判斷結尾的。 |
strip([,str]) | 去掉字符串開頭和結尾的空白字符(包括\n、\t這些),可選參數表明能夠去掉指定字符 |
順便再說一下布爾類型,不過與Java不一樣的是,布爾類型的True和False,首字母必須大寫:
x = True print(type(x)) # 輸出<class 'bool'>
說完幾個基本的數據類型,難免要提到類型轉換。Python內置一些類型轉換的函數:
函數名 | 做用 |
---|---|
int(x) | 將x轉換爲整型(小數轉整型會去掉小數部分) |
float(x) | 將x轉換爲浮點型 |
str(x) | 將x轉換爲字符串 |
tuple(x) | 將x轉換爲元組 |
list(x) | 將x轉換爲列表 |
set(x) | 將x轉換爲集合,並去重 |
輸入函數爲input。input函數返回用戶輸入的信息爲字符串類型。因此若是你輸入的是數字類型,記得類型轉換。
x = input("請輸入數字") print(type(x),x) # 輸出<class 'str'> 10
輸出前面已經演示了不少次了,函數爲print,能夠直接輸出變量與值。一次輸出多個變量能夠用逗號隔開,就想上面的演示同樣,既要輸出類型,也要輸出值。不換行輸出,能夠在print函數里加上end=""這個參數,由於print默認end="\n",\n就是換行的意思。若是想輸出特殊字符,可能須要用到轉義字符:\。
x = 10 y = 20 print(x,y,end="") # 輸出10 20 加上end="" 不換行 print("Hello \\n Python") # 輸出 Hello \n Python
在輸出時,還能夠格式化輸出內容:%s表明字符串格式、%d表明整型、%f表明浮點型
z = 1.2 print("%f"%z) # 輸出 1.200000
除了格式化,%d等還能夠看成佔位符:
name = "小明" age = 18 print("姓名:%s,年齡:%d"%(name,age)) # 姓名:小明,年齡:18
若是你閒這個佔位符麻煩,還可使用format函數,佔位符只用寫一對{}:
print("姓名:{},年齡:{}".format(name,age)) # 姓名:小明,年齡:18
除了加減乘除,還有冪(**)、取模(%)、取整(//)
x = 3 ** 2 # x=9 即3的2次方 y = 5 % 3 # y=2 即5除以3餘2 z = 5 // 2 # z=2 即5除以2,整數部分爲2
和其餘經常使用編程語言基本如出一轍,不等於(!=)、大於等於(>=)、等於(==)。
Python也支持+=、*=等形式的賦值運算。除此以外,固然也支持前面說到的冪、取模等算術運算符,如取整並賦值(//=)、取模並賦值(%=)。
x = 10 x %= 3 print(x) # 輸出1 ,x%=3 意爲 x = x%3
非(not)、與(and)、或(or)
x = True print(not x) # 輸出 False
這三個和其餘編程語言基本沒差,就是寫法上有點區別。首先沒了大括號,條件語句後以冒號開頭;代碼快有嚴格的縮進要求,由於沒了大括號,縮進就是條件語句判斷本身代碼快範圍的依據。其餘的基本同樣,好比continue跳過當次循環,break跳出整個循環體。下面看三個簡單的例子就明白了:
a = 10 # if或else後面是冒號,代碼塊還須要縮進 if a >= 10: print("你好啊老大") else: print("滾蛋") # 一樣的while後面也須要冒號,代碼塊必須縮進。(Python沒有num++,得寫成num+=1) # print想不換行打印,最後得加個end="",由於默認有一個end="\n" # " "*(j-i),表明j-i個空格 i = 1 j = 4 while i <= j: print(" "*(j-i), end="") n = 1 while n <= 2*i-1: print("*", end="") n += 1 print("") i += 1 # 語法:for 變量 in 序列 ,還沒講序列,暫時用range表示,表明1-21的序列 # continue略過當次循環,break跳出整個循環 for i in range(1, 21): if i % 2 == 0: if(i % 10 == 0): continue if(i >= 15): break print(i)
列表使用一對[]定義,每一個元素用逗號隔開,元素類型不強求相同,經過索引獲取列表元素。具體的咱們看下面的代碼:
info_list = ["小紅", 18, "男"] #能夠不是同一類型 info_list[2] = "女" # 修改指定索引位置的元素 del info_list[1] # 刪除指定索引位置的元素 info_list.remove("女") # 刪除列表中指定的值 for att in info_list: # 遍歷元素 print(att)
上面的示例代碼演示了部分列表的用法,下面再列出一些其餘的經常使用函數或語法:
函數或語法 | 做用 |
---|---|
list.append(element) | 向列表list結尾添加元素(這個元素也能夠是個列表) |
list.insert(index,element) | 向列表指定位置添加元素 |
list.extend(new_list) | 向列表list添加new_list的全部元素 |
list.pop([,index]) | 彈出最後一個元素,可選參數index,彈出指定位置元素 |
list.sort([,reverse=True]) | 對列表排序,可選參數reverse=True表示降序 |
list[start:end] | 對列表分片,start和end表明起始結束索引 |
list1+list2 | 拼接兩個列表 |
元組用一對()定義。元組也是有序的,它和列表的區別就是,列表能夠修改元素,元組不行。正是由於這個特色,元組佔用的內存也比列表小。
name_list=("小紅","小王")
字典使用一對{}定義,元素是鍵值對。用法示例以下:
user_info_dict = {"name": "小王", "age": "18", "gender": "男"} name = user_info_dict["name"] # 直接用key獲取value age = user_info_dict.get("age") # 也能夠用get(key)獲取value user_info_dict["tel"] = "13866663333" # 當key不存在,就是往字典添加鍵值對,若是存在就是修改value del user_info_dict["tel"] # 刪除指定鍵值對
以上就是經常使用語法和函數。字典也能夠遍歷,只是遍歷時,須要指定遍歷的是key仍是value,好比:
for k in dict.keys(): # 遍歷全部key for v in dict.values(): # 遍歷全部value for item in dict.items(): # 也能夠直接遍歷鍵值對
集合是無序的,也用一對{}定義,但不是鍵值對了,是單獨且不重複的元素。部分用法以下:
user_id_set = {"1111","22222","3333"} # 元素不重複 print(type(user_id_set)) # 輸出<class 'set'> # 除了直接用{}定義,還能夠用set函數傳入一個序列,其會爲list去重,並返回一個集合(若是是字符串,字符串會被拆成字符) new_user_id_set = set(list)
上面演示了部分用法,下面咱們用一個表格展現一些經常使用的函數或語法:
函數或語法 | 做用 |
---|---|
element in set | 判斷元素是否在集合中,返回布爾類型 |
element not in set | 判斷元素是否不在集合中 |
set.add(element) | 向集合添加元素 |
set.update(list,.....) | 將序列中的每一個元素去重並添加到集合中,若是有多個序列,用逗號隔開 |
set.remove(element) | 刪除指定元素,若是元素不存在就會報錯 |
set.discard(element) | 刪除指定元素,若是元素不存在也不會報錯 |
set.pop() | 隨機刪除集合中的元素,並返回被刪除的元素 |
set1 & set2 或set1 intersection set2 | 求兩個集合的交集,兩種用法結果同樣 |
set1 | set2 或set1 union set2 | 求兩個集合的並集 |
set1 - set2 或set1.difference(set2) | 求兩個集合的差集,注意順序。set1-set2表明set1有set2沒有的元素 |
Python中函數用def定義,格式爲:
def function_name(參數列表): # 參數可爲空,多個參數用逗號隔開 函數體 return 返回值 #可選 # 函數的調用 function_name(參數列表)
和循環體同樣的,由於沒有了大括號,因此縮進是嚴格要求的。除了上面那種比較常見的格式,Python函數的參數中,還有一種缺省參數,即帶有默認值的參數。調用帶有缺省參數的函數時,能夠不用傳入缺省參數的值,若是傳入了缺省參數的值,則會使用傳入的值。
def num_add(x,y=10): # y爲缺省函數,若是調用這個函數只傳入了x的值,那麼y默認爲10
通常狀況下,調用函數傳入實參時,都會遵循參數列表的順序。而命名參數的意思就是,調用函數時,經過參數名傳入實參,這樣能夠不用按照參數定義的順序傳入實參。
def num_add(x, y): print("x:{},y:{}".format(x, y)) return x+y # 輸出: # x:10,y:5 # 15 print(num_add(y=5, x=10))
不定長參數能夠接收任意多個參數,Python中有兩種方法接收:1.在參數前加一個*,傳入的參數會放到元組裏;2.在參數前加兩個**,表明接收的是鍵值對形式的參數。
# 一個* def eachNum(*args): print(type(args)) for num in args: print(num) # 輸出: # <class 'tuple'>‘ # (1, 2, 3, 4, 5) eachNum(1,2,3,4,5) ## 兩個**。這個other是想告訴你,在使用不定長參數時,也能夠搭配普通的參數 def user_info(other,**info): print(type(info)) print("其餘信息:{}".format(other)) for key in info.keys(): print("{} : {}".format(key,info[key])) # 傳入參數時,不用像定義字典同樣,加個大括號再添加鍵值對,直接當命名參數傳入便可 # 輸出: # <class 'dict'> # 其餘信息:管理員 # 略... user_info("管理員",name="趙四",age=18,gender="男")
上面示例代碼中的註釋說到了,當使用不定長參數時,不用像字典或者元組的定義那樣,直接傳入參數便可。但有時候,可能會遇到想把字典、元組等容器中的元素傳入到不定長參數的函數中,這個時候就須要用到拆包了。
所謂拆包,其實就是在傳入參數時,在容器前面加上一個或兩個*。仍是以上面的user_info函數爲例:
user_info_dict={"name":"趙四","age":18,"gender":"男"} user_info("管理員",**user_info_dict) # 效果和上面同樣
注意,若是接收方的不定長參數只用了一個 * 定義,那麼傳入實參時,也只能用一個 *。
匿名函數,即沒有名字的函數。在定義匿名函數時,既不須要名稱,也不須要def關鍵字。語法以下:
lambda 參數列表: 表達式
多個參數用逗號隔開,匿名函數會自動把表達式的結果return。在使用時,通常會用一個變量接收匿名函數,或者直接把匿名函數當參數傳入。
sum = lambda x,y : x+y print(sum(1,2)) # 輸出3
在Python中,函數內還能夠定義函數,外面這個函數咱們就稱爲外部函數,裏面的函數咱們就稱爲內部函數。而外部函數的返回值是內部函數的引用,這種表達方式就是閉包。內部函數能夠調用外部函數的變量,咱們看一個示例:
# 外部函數 def sum_closure(x): # 內部函數 def sum_inner(y): return x+y return sum_inner # 返回內部函數 # 獲取了內部函數 var1 = sum_closure(1) print(var1) # 輸出<function sum_closure.<locals>.sum_inner at 0x000001D82900E0D0>,是個函數類型 print(var1(2)) # 輸出3
說完閉包的用法,接着瞭解一下裝飾器。不知道你們瞭解過AOP沒,即面向切面編程。說人話就是在目標函數先後加上一些公共函數,好比記錄日誌、權限判斷等。Python中固然也提供了實現切面編程的方法,那就是裝飾器。裝飾器和閉包一塊兒,能夠很靈活的實現相似功能,下面看示例:
import datetime #若是沒有這個包,在終端裏輸入pip3 install datetime # 外部函數,其參數是目標函數 def log(func): #內部函數,參數得和目標函數一致。也可使用不定長參數,進一步提高程序靈活性 def do(x, y): # 僞裝記錄日誌,執行切面函數。(第一次datetime是模塊、第二個是類、now是方法。在下一節講到模塊) print("時間:{}".format(datetime.datetime.now())) print("記錄日誌") # 執行目標函數 func(x, y) return do # @就是裝飾器的語法糖,log外部函數 @ log def something(x, y): print(x+y) # 調用目標函數 # 輸出: # 時間:2021-01-06 16:17:00.677198 # 記錄日誌 # 30 something(10, 20)
函數相關的就說到這裏了,其實還有一些知識沒說到,好比變量的做用域、返回值等。這部份內容和其餘語言幾乎無異,一點區別無非就是返回值不用在意類型了,畢竟定義函數時也沒指定函數返回值類型,這一點各位老司機應該也會想到。
Python中包與普通文件夾的區別就是,包內要建立一個__init__.py文件,來標識它是一個包。這個文件能夠是空白的,也能夠定義一些初始化操做。當其餘包下的模塊調用本包下的模塊時,會自動的執行__init__.py文件的內容。
一個Python文件就是一個模塊,不一樣包下的模塊能夠重名,在使用的時候以「包名.模塊名」區別。導入其餘模塊用import關鍵字,前面的示例代碼中也演示過一次。導入多個模塊能夠用逗號隔開,也能夠直接分開寫。除了導入整個模塊,還能夠導入模塊中指定的函數或類:
from model_name import func_name(or class_name)
導入函數或類後,就不要使用模塊名了,直接調用導入的類或函數便可。
Python是一種面向對象的解釋型編程語言。面向對象的關鍵就在於類和對象。Python中類的定義用class關鍵字,以下:
class 類名: def 方法名(self[,參數列表]) ...
定義在類裏面的函數叫作方法,只是與類外部的函數作個區分,不用在乎叫法。類裏面的方法,參數列表中會有一個默認的參數,表示當前對象,你能夠看成Java中的this。由於一個類能夠建立多個對象,有了self,Python就知道本身在操做哪一個對象了。咱們在調用這個方法時,不須要手動傳入self。示例代碼:
class Demo: def do(self): print(self) # 建立兩個Demmo類型的對象 demo1=Demo() demo1.do() # 輸出<__main__.Demo object at 0x0000019C78106FA0> demo2=Demo() demo2.do() # 輸出<__main__.Demo object at 0x0000019C77FE8640> print(type(demo1)) # <class '__main__.Demo'>
構造方法的做用是在建立一個類的對象時,對對象進行初始化操做。Python中類的構造方法的名稱是__init__(兩邊分別兩個下劃線)。在建立對象時,__init__方法自動執行。和普通方法同樣的,若是你想自定義構造方法,也要接收self參數。示例代碼:
class Demo: # 構造方法,還能夠傳入其餘參數化 def __init__(self,var1,var2): # 把參數設置到當前對象上,即便類中沒有屬性也能夠設置 self.var1=var1 self.var2=var2 print("初始化完成") def do(self): print("Working...") # 經過構造方法傳入實參 demo1=Demo(66,77) demo1.do() # 經過當前對象,獲取剛剛設置的參數 print(demo1.var1) print(demo1.var2)
Java或C#中有好幾種訪問權限,在Python中,屬性和方法前添加兩個下劃線即爲私有,反之就是共公有。具備私有訪問權限的屬性和方法,只能在類的內部方法,外部沒法訪問。和其餘語言同樣,私有的目的是爲了保證屬性的準確性和安全性,示例代碼以下:
class Demo: # 爲了方便理解,咱們顯示的設置一個私有屬性 __num = 10 # 公有的操做方法,裏面加上判斷,保證數據的準確性 def do(self, temp): if temp > 10: self.__set(temp) # 私有的設置方法,不讓外部直接設置屬性 def __set(self, temp): self.__num = temp # 公有的get方法 def get(self): print(self.__num) demo1 = Demo() demo1.do(11) demo1.get() # 輸出 11
一堆self.剛開始看時還有點暈乎,把它看成this就好。
繼承是面向對象編程裏另外一大利器,好處之一就是代碼重用。子類只能繼承父類的公有屬性和方法,Python的語法以下:
class SonClass(FatherClass):
當咱們建立一個SonClass對象時,直接能夠用該對象調用FatherClass的公有方法。Python還支持多繼承,若是是多繼承就在小括號裏把父類用逗號隔開。
若是想在子類裏面調用父類的方法,通常有兩種方式:1.父類名.方法名(self[,參數列表])。此時的self是子類的self,且須要顯示傳入;2.super().方法名()。第二種方式由於沒有指定父類,因此在多繼承的狀況下,若是調用了這些父類中同名的方法,Python實際會執行小括號裏寫在前面的父類中的方法。
若是子類定義了與父類同名的方法,子類的方法就會覆蓋父類的方法,這就是重寫。
捕獲異常的語法以下:
try: 代碼快 # 可能發生異常的代碼 except (異常類型,...) as err: # 多個異常類型用逗號隔開,若是隻有一個異常類型能夠不要小括號。err是取的別名 異常處理 finally: 代碼快 # 不管如何都會執行
在try代碼塊中,錯誤代碼以後的代碼是不會執行的,但不會影響到try ... except以外的代碼。看個示例代碼:
try: open("123.txt") #打開不存在的文件,發生異常 print("hi") # 這行代碼不會執行 except FileNotFoundError as err: print("發生異常:{}".format(err)) # 異常處理 print("我是try except以外的代碼") #正常執行
雖然上面的內容和其餘語言相差不大,可是剛剛接觸Python鬼知道有哪些異常類型,有沒有相似Java的Exception異常類型呢?確定是有的。Python一樣提供了Exception異常類型來捕獲所有異常。
那若是發生異常的代碼沒有用try except捕獲呢?這種狀況要麼直接報錯,程序中止運行。要麼會被外部的try except捕獲到,也就是說異常是能夠傳遞的。好比func1發生異常沒有捕獲,func2調用了func1並用了try except,那麼func1的異常會被傳遞到func2這裏。是否是和Java的throws差很少?
Python中拋出異常的關鍵字是raise,其做用和Java的throw new差很少。示例代碼以下:
def do(x): if(x>3): # 若是大於3就拋出異常 raise Exception("不能大於3") # 拋出異常,若是你知道具體的異常最好,後面的小括號能夠寫上異常信息 else: print(x) try: do(4) except Exception as err: print("發生異常:{}".format(err)) # 輸出 發生異常:不能大於3
想要操做一個文件,首先得打開它。Python中有個內置的函數:open。使用open打開文件能夠有三種模式,分別爲:只讀(默認的模式,只能讀取文件內容,r表示)、只寫(會覆蓋原文本內容,w表示)、追加(新內容追加到末尾,a表示)。示例以下:
f = open("text.txt","a") # 用追加的方式獲取文件對象
由於text.txt和代碼在同一目錄因此只寫了文件名,若是不在同一目錄須要寫好相對路徑或絕對路徑。
獲取到文件對象後,接下來就能夠操做了,反正就是些API,直接看示例:
f = open("text.txt","a",encoding="utf-8") # 以追加的方式打開文件,並設置編碼方式,由於接下來要寫入中文 f.write("234567\n") # 寫入數據,最後的\n是換行符,實現換行 f.writelines(["張三\n","趙四\n","王五\n"]) # write只能寫一個字符串,writelines能夠寫入一列表的字符串 f.close() # 操做完記得關閉
以上是寫文件的兩個方法。最後記得關閉文件,由於操做系統會把寫入的內容緩存起來,萬一系統崩潰,寫入的數據就會丟失。雖然程序執行完文件會自動關閉,可是實際項目中,確定不止這點代碼。Python也很貼心,防止咱們忘了close,提供了一種安全打開文件的方式,語法是 with open() as 別名:,示例以下
with open("test.txt","w") as f: # 安全打開文件,不須要close。 f.write("123")
寫完了,該讀一讀了。示例以下:
f = open("text.txt","r",encoding="utf-8") data = f.read() # read會一次性讀出全部內容 print(data) f.close()
除了一次性讀取完,還能夠按行的方式返回所有內容,並用一個列表裝起來,這樣咱們就能夠進行遍歷了。方法是readlines,示例以下:
f = open("text.txt","r",encoding="utf-8") lines = f.readlines() # lines是個列表 for line in lines: print(line) f.close()
在操做文件的時候,確定不止讀寫這麼簡單,可能還會涉及文件的刪除、重命名、建立等等。在用Python的函數操做文件以前,須要導入os模式:import os
。下面簡單的演示一下重命名的函數,其餘的函數咱們以表格的形式展示。
import os os.rename("text.txt","123.txt") # 把text.txt更名爲123.txt
函數 | 做用 |
---|---|
os.remove(path) | 刪除指定文件 |
os.mkdir(path) | 在指定路徑下建立新文件 |
os.getcwd() | 獲取程序運行的絕對路徑 |
os.listdir(path) | 獲取指定路徑下的文件列表,包含文件和文件夾 |
os.redir(path) | 刪除指定路徑下的空文件夾(若是不是空文件夾就會報錯) |
學了前面的容器,會發現JSON的格式和Python的字典有點像,都是鍵值對形式的。雖然格式很像,但仍是有點小區別,好比:Python的元組和列表在JSON中都是列表、Python的True和Flase會被轉換成小寫、空類型None會被轉換成null。下面咱們來看一些具體的函數把。
在Python中操做JSON格式的數據須要導入json模塊。一樣的,我這裏只演示一個函數,其餘經常使用的用表格列出來。
import json user_info={"name":"張三","age":18,"gender":"男","hobby":("唱歌","跳舞","打籃球"),"other":None} # 建立一個字典 json_str=json.dumps(user_info,ensure_ascii=False) # dumps函數會把字典轉換爲json字符串 # 輸出 {"name": "張三", "age": 18, "gender": "男", "hobby": ["唱歌", "跳舞", "打籃球"], "other": null} print(json_str)
須要注意若是數據存在中文,須要在dumps函數加上ensure_ascii=False
。
函數 | 做用 |
---|---|
json.loads(json_str) | 把json字符串轉換爲Python數據結構 |
json.dump(user_info,file) | 把Python數據寫入到json文件,要先獲取文件,那個file就是文件對象 |
json.load(file) | 把json文件中的數據轉爲成Python數據結構,一樣須要獲取文件 |
關於JSON的操做就說這些。通用的數據格式不止JSON一種,好比還有xml、csv等。爲了節約篇幅,就再也不贅述了,你們能夠根據本身的需求查對應的API便可。
最後一節講正則表達式,一是由於這也算個基礎知識,在不少地方都有可能用到。二是由於後面的爬蟲實戰,確定會用到正則表達式來解析各類數據。
Python中內置了re模塊來處理正常表達式,有了這個模塊咱們就能夠很方便的對字符串進行各類規則匹配檢查。不過正則表達式真正難的是表達式的書寫,函數主要就一個:re.match(pattern,string)
,其中pattren就是正則表達式,stirng就是待匹配字符串。若是匹配成功就會返回一個Match對象,不然就返回None。匹配是從左往右,若是不匹配就直接返回None,不會接着匹配下去。示例以下:
import re res=re.match("asd","asdabcqwe") # 匹配字符串中是否有asd(若是asd不在開頭就會返回None) print(res) # 輸出 <re.Match object; span=(0, 3), match='asd'> print(res.group()) # 輸出 asd 若是想獲取匹配的子字符就用這個函數
秉着幫人幫到底的精神,下面就簡單的介紹下正則表達式的一些規則。
單字符匹配,顧名思義就是匹配一個字符。除了直接使用某個具體的字符,還可使用如下符號來進行匹配:
符號 | 做用 |
---|---|
. | 匹配除」\n「之外的任意單個字符 |
\d | 匹配0-9之間的一個數字,等價於[0-9] |
\D | 匹配一個非數字字符,等價於[^0-9] |
\s | 匹配任意空白字符,如空格、\t、\n等 |
\S | 匹配任意非空白字符 |
\w | 匹配單詞字符,包括字母、數字、下劃線 |
\W | 匹配非單詞字符 |
[] | 匹配[]中列舉的字符,好比[abc],只要出現這三個字母中的一個便可匹配 |
以防有的朋友從未接觸過正則表達式,不知道怎麼用,下面我來作個簡答的演示。假如我想匹配三個字符:第一個是數字、第二個是空格、第三個是字母,一塊兒來看看怎麼寫這個正則表達式吧:
import re pattern = "\d\s\w" # \d匹配數字、\s匹配空格、\w匹配字母(切記是從左往右依次匹配的,只要有一個字符匹配不上就直接返回None) string = "2 z你好" res=re.match(pattern,string) print(res.group()) # 輸出:2 z
看到這你可能會想,非得一個個字符匹配,那多麻煩啊,有沒有更靈活的規則?固然有了,接着看。
若是咱們只想匹配字母,但不限制有多少個,該怎麼寫呢?看下面的表格就知道了:
符號 | 做用 |
---|---|
* | 匹配一個字符出現0次或屢次 |
+ | 匹配一個字符至少出現一次,等價於{,1} |
? | 匹配一個字符出現0次或1次,等價於{1,2} |
{m} | 匹配一個字符出現m次 |
{m,} | 匹配一個字符至少出現m次 |
{m,n} | 匹配一個字符出現m到n次 |
數量匹配的符號後面若是加上?
,就會盡量少的去匹配字符,在Python裏面叫非貪婪模式,反之默認的就是貪婪模式。好比{m,}
會盡量多的去匹配字符,而{m,}?
在知足至少有m個的狀況下儘量少的去匹配字符。其餘的同理。
來看一個例子,我想匹配開頭是任意個小寫字母,接着是1到5個2-6的數字,最後是至少一個空格:
import re pat = r"[a-z]*[2-6]{1,5}\s+" str = "abc423 你好" res=re.match(pat,str) print(res) #輸出 abc423
咱們來解析下這個正則表達式,pat字符串開頭的r是告訴Python這是個正則表達式,不要轉義裏面的\,建議寫表達式時都加上。[a-z]
表明任意小寫字母,不用\w的緣由是,\w還包括數字、下劃線,沒有嚴格符合咱們的要求。加上個*就表明任意數量。這裏強調一下單字符匹配和數量表示之間的邏輯關係,以[a-z]*
爲例,其表達的是任意個[a-z]
,而不是某個字母有任意個。明白了這個邏輯後,其餘的也好理解了。
前面的例子都是我隨意編的,其實學了這些,已經能夠寫出一個有實際做用的表達式了,好比咱們來匹配一個手機號。首先手機號只有11位,第一個數字必須是1,第二個是三、五、七、8中的一個。知道了這三個個規律,咱們來寫一下表達式:1[3578]\d{9}
。看上去好像能夠,可是仔細一想,前面不是說了正則表達式是從左往右匹配,只要符合了就會返回結果,也不會管字符串匹配徹底沒有。若是最後有10個數字,這個表達式也會匹配成功。關於這個問題咱們接着看。
邊界表示符有兩個:開頭^
和結尾$
。使用起來也很簡單,仍是以上面的手機號爲例,咱們再來完善一下:^1[3578]\d{9}$
。其中^1
表示以1開頭,\d{9}$
表示以9個數字結尾。其實這個^1
無關緊要,畢竟是從左往右的,字符串不是1開頭的話直接就會返回None,可是這個結尾符是必須的。
假如咱們想匹配的字符與正則表達式規定的這些字符同樣該怎麼辦?好比咱們想單純的匹配.
這個字符,可是這個字符在正則表達式中表示的是任意字符。這時候就要用到轉義字符\
了。其實這個轉義字符在不少語言裏都是同樣的。那麼前面的例子就能夠寫出\.
。咱們再演示個匹配郵箱的例子:
import re pat = r"^\w{4,10}@qq\.com" # 若是.前面不加\,就表明任意字符了 str = "1234@qq.com" res=re.match(pat,str) print(res)
看到上面的匹配郵箱例子,是否是有個疑問,若是我想不止匹配QQ郵箱該怎麼辦呢。那就要用到分組了,其能夠實現匹配多種狀況。分組符號以下:
符號 | 做用 |
---|---|
() | 將括號裏的內容看成一個分組,每一個分組會有一個編號,從1開始 |
| | 鏈接多個表達式,表達式之間是「或」的關係,可與()一塊兒使用 |
\num | 引用分組,num表明分組編號 |
(?P
|
給分組取別名,別名寫在表達式前面,name不用打引號 |
(?P=name) | 根據別名使用分組中的正則表達式 |
那麼咱們把上面的例子稍微修改下:^\w{4,10}@(qq|163|outlook|gmail)\.com
。這樣就能夠匹配多種郵箱了。
簡單的演示了下|
的用法,你們可能對其餘的分組符號還有點疑惑,下面咱們再來演示一下這些符號:
import re pat = r"<(.+)><(.+)>.*<(/\2)><(/\1)>" str = "<body><div></div></body>" res=re.match(pat,str) print(res)
這個表達式匹配的是由兩個標籤組成的html字符串。第一眼看上去有點麻煩,實際很簡單。再次強調一下,普通字符也能夠當表達式來匹配的,好比上面的< >
就是普通字符而已。
咱們來分析一下這個表達式,首先一對小括號表示一個分組,裏面的.+
表示只有一個非\n字符。中間的.*
用來匹配標籤內的內容。/\2
中,第一個斜槓與前面的html標籤組成一對,/2表示引用第二個分組的內容。這裏爲何要使用分組呢?由於咱們還要保證html標籤正確匹配。若是後面也使用.+
,你們能夠試着把/div
和/body
交換位置,表達式依舊匹配成功,但這顯然不符合html的語法。
正則表達式的一些規則符號終於講完了,最後再列舉幾個Python中操做正則表達式的函數:(re爲導入的模塊)
函數 | 做用 |
---|---|
re.compile(patt) | 封裝正則表達式,並返回一個表達式對象 |
re.search(patt,str) | 從左往右搜索第一個配正則表達式匹配的子字符串 |
re.findall(patt,str) | 在字符串中查找正則表達式匹配到的全部子字符串,並返回一個列表 |
re.finditer(patt,str) | 在字符串中查找正則表達式匹配到的全部子字符串,並返回一個Iterator對象 |
re.sub(patt,newstr,str) | 將字符串中被正則表達式匹配到的子字符串替換成newstr,並返回新的字符串,原字符串不變 |
Python的第一篇文章就到這裏了。接下來會邊學邊寫,作一些好玩的Python項目,再一塊兒分享出來。若有錯誤,感謝指出!
參考資料:《Python 3快速入門與實戰》