1.set集合
set集合是一個無序、不可重復、可嵌套的序列,基本功能是進行成員關系測試和刪除重復元素,可以使用大括號({})或者 set()函數創建集合,注意:創建一個空集合必須用 set() 而不是 { },因為 { } 是用來創建一個空字典
1.1 常用功能函數
-
增加元素
使用set.add()函數單個添加元素;使用set.update()函數來批量添加元素,參數為可迭代的對象,如列表,元組,字符串
>>> test = {1,2,3,4,} #創建一個集合 >>> test.add("5") #添加集合元素5 >>> test.add("6") >>> test {1, 2, 3, 4, '6', '5'} >>> test.add("5") #重新添加集合元素5.發現,之前已有,印證了不重復性 >>> test {1, 2, 3, 4, '6', '5'} >>> li = [7,8,9,0] >>> test.update(li) #將li列表的元素批量添加到集合中 >>> test {0, 1, 2, 3, 4, 7, 8, 9, '6', '5'} >>> test.update("fuzj") #將fuzj字符串每個字符作為元素添加到集合中 >>> test {0, 1, 2, 3, 4, 7, 8, 9, 'f', 'z', 'j', '6', 'u', '5'}
-
刪除元素
刪除可以使用set.discard() 移除元素,不存在不報錯 set.remove() 移除元素,不存在則報錯 set.pop() 刪除最后的元素,並打印,不能加參數

>>> test {0, 1, 2, 3, 4, 7, 8, 9, 'f', 'z', 'j', '6', 'u', '5'} >>> test.discard(0) #使用dicard刪除0元素 >>> test {1, 2, 3, 4, 7, 8, 9, 'f', 'z', 'j', '6', 'u', '5'} >>> test.discard(100) #使用discard刪除不存在的元素,不報錯 >>> test {1, 2, 3, 4, 7, 8, 9, 'f', 'z', 'j', '6', 'u', '5'} >>> test.remove(1) #使用remove刪除1元素 >>> test {2, 3, 4, 7, 8, 9, 'f', 'z', 'j', '6', 'u', '5'} >>> test.remove(100) #使用remove刪除不存在的元素,報錯 Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 100 >>> test.pop() #使用pop隨機刪除元素 2 >>> test {3, 4, 7, 8, 9, 'f', 'z', 'j', '6', 'u', '5'} >>> test.pop() 3
- 交集
交集為兩個集合相同的元素,使用intersection函數或者&符號,將交集重新組合為一個集合

>>> test = {1,2,3,4,5,} >>> test2 = {2,3,5,6,7,8,} >>> test.intersection(test2) #取test和test2的交集 {2, 3, 5} >>> test3 = test.intersection(test2) >>> test3 {2, 3, 5} >>> test & test2 #使用&符號來取交集 {2, 3, 5} >>> test.intersection_update(test2) #加update將會把test更新,只留下交集部分 >>> test {2, 3, 5}
- 並集
並集為兩個集合合並,去重后的結果,可以用union函數或|符號,將並集重新組合為一個集合

>>> test {1, 2, 3, 4, 5} >>> test2 {2, 3, 5, 6, 7, 8} >>> test.union(test2) {1, 2, 3, 4, 5, 6, 7, 8} >>> test | test2 {1, 2, 3, 4, 5, 6, 7, 8}
- 差集
差集為兩個集合不相同的元素,或者B對於A中不存在的元素,或者A對於B中不存在的元素,取差集要確定好對比的前后順序,使用difference函數和symmetrice_difference函數,也可以使用-和符號

>>> test {1, 2, 3, 4, 5} >>> test2 {2, 3, 5, 6, 7, 8} >>> test.difference(test2) #取A集合中,B集合不存在的元素 {1, 4} >>> test - test2 #使用-號 取A集合中,B集合不存在的元素 {1, 4} >>> test2.difference(test) #取B集合中,A集合不存在的元素 {8, 6, 7} >>> test2 - test #使用-號 取B集合中,A集合不存在的元素 {8, 6, 7} >>> test.symmetric_difference(test2) #取A、B集合中互相不存在元素 {1, 4, 6, 7, 8} >>> test ^ test2 #使用^號 取A、B集合中互相不存在元素 {1, 4, 6, 7, 8} 同樣支持update將結果更新至原集合中, test.symmetric_difference_update(test2) >>> test {1, 4, 6, 7, 8}
-
其他函數
- set.copy() 拷貝個集合,為淺copy
- set.clear() 清空集合
1.2 練習示例
取old_cmdb和new_cmdb的差集,交集等,常用在cmdb更新中

``` #!/usr/bin/env python # -*- coding: UTF-8 -*- #pyversion:python3.5 #owner:fuzj old_cmdb = { "#1":8, "#2":4, "#4":2, } new_cmdb = { "#1": 4, "#2": 4, "#3": 2, } print("old_cmdb:" , old_cmdb) print("new_cmdb:" , new_cmdb) s1 = set(old_cmdb.keys()) s2 = set(new_cmdb.keys()) #old_cmdb 要刪除的 s_del = s1.difference(s2) print("old_cmdb 要刪除的: ",s_del) #old_cmdb 要更新的 s_upd1 = s1.intersection(s2) s_upd2 = set() for i in s_upd1: if old_cmdb[i] != new_cmdb[i]: s_upd2.add(i) print("old_cmdb 要更新的:",s_upd2) #old_cmdb 要添加的 s_add = s2.difference(s1) print("old_cmdb 要添加的",s_add) ```
運行結果:

``` old_cmdb: {'#4': 2, '#2': 4, '#1': 8} new_cmdb: {'#3': 2, '#2': 4, '#1': 4} old_cmdb 要刪除的: {'#4'} old_cmdb 要更新的: {'#1'} old_cmdb 要添加的 {'#3'} ```
2.函數
函數是組織好的,可重復使用的,用來實現單一,或相關聯功能的代碼段。函數能提高應用的模塊性,和代碼的重復利用率,分自定義函數和內置函數
2.1 函數的創建
- 格式
def 函數名(參數):
代碼塊
return 返回值
-
要素
- 函數代碼塊以 def 關鍵詞開頭,后接函數標識符名稱和圓括號 ()。
- 任何傳入參數和自變量必須放在圓括號中間,圓括號之間可以用於定義參數。
- 函數的第一行語句可以選擇性地使用文檔字符串—用於存放函數說明。
- 函數內容以冒號起始,並且縮進。
- return [表達式] 結束函數,選擇性地返回一個值給調用方。不帶表達式的return相當於返回 None。函數中如果執行了return,此函數將終止執行return后面的語句
-
示例
``` >>> def hello(arg) : print(arg) >>> hello("Hello World!") Hello World! >>> ```
2.2 函數的參數
-
形式參數,實際參數
形式參數為函數名后邊括號里定義的內容,實際參數是函數被調用時傳入的參數
如上面例子,arg 為hello函數的形式參數,而下面hellow()被調用時Hello World!
為實際參數 -
默認參數
調用函數時,如果沒有傳遞參數,則會使用默認參數。以下實例中如果沒有傳入 age 參數,則使用默認值:
``` #!/usr/bin/python3 #printinfo函數說明 def printinfo( name, age = 35 ): "打印任何傳入的字符串" print ("名字: ", name); print ("年齡: ", age); return; #調用printinfo函數 printinfo( age=50, name="runoob" ); print ("------------------------") printinfo( name="runoob" ); 以上實例輸出結果: 名字: runoob 年齡: 50 ------------------------ 名字: runoob 年齡: 35 ```
-
指定參數
關鍵字參數和函數調用關系緊密,函數調用使用關鍵字參數來確定傳入的參數值。使用關鍵字參數允許函數調用時參數的順序與聲明時不一致,因為 Python 解釋器能夠用參數名匹配參數值,如上默認參數中,name參數和age參數即為指定參數
-
動態參數
*arg 默認傳入的參數放到元組中, 動態參數使用中,如果實際參數前加*號,會將參數的元素傳入到參數中
**kwargs默認傳入的參數放入到字典中.如果實際參數前加*號,會將字典的k/v 傳入到參數中
萬能參數: 即 *args,**kwargs``` #!/usr/bin/env python # -*- coding: UTF-8 -*- #pyversion:python3.5 #owner:fuzj def send1(*args): print(args,type(args)) def send2(**args): print(args,type(args)) def send3(*args,**kwargs): print(args,type(args)) print(kwargs,type(kwargs)) li = [1,2,3,4,] send1(1,2,3,4) send1(li) send1(*li) #參數前加*號會把該參數進行for循環里面的值,然后傳入函數 di = {"a":1,"b":2} send2(k=di) send2(**di) send3(1,2,3,4,"a"=1,"b"=2) ```
執行結果

``` #函數send1 (1, 2, 3, 4) <class 'tuple'> #傳遞不定長參數的結果 ([1, 2, 3, 4],) <class 'tuple'> #傳入一個列表參數的結果 (1, 2, 3, 4) <class 'tuple'> #傳入一個帶*的列表參數結果 #函數send2 {'k': {'b': 2, 'a': 1}} <class 'dict'> #傳入一個字典結果 {'b': 2, 'a': 1} <class 'dict'> #傳入一個帶**的字典結果 # 函數send3 (1, 2, 3, 4) <class 'tuple'> {'b': 2, 'a': 1} <class 'dict'> ```
2.3 變量作用域
Pyhton 中,程序的變量並不是在哪個位置都可以訪問的,訪問權限決定於這個變量是在哪里賦值的。
變量的作用域決定了在哪一部分程序可以訪問哪個特定的變量名稱,根據作用域的不同,可分為:
-
全局變量: 所有的作用域都可讀,但是作用域內不能重新賦值全局變量,但是可以使用global來重新定義全局變量.如果變量的值是列表\元組\字典 在作用域內可以進行修改,不可重新賦值
-
局部變量: 局部變量只能在其被聲明的函數內部訪問,而全局變量可以在整個程序范圍內訪問
定義在函數內部的變量擁有一個局部作用域,定義在函數外的擁有全局作用域。
局部變量只能在其被聲明的函數內部訪問,而全局變量可以在整個程序范圍內訪問。調用函數時,所有在函數內聲明的變量名稱都將被加入到作用域中。如下實例:

``` #!/usr/bin/env python total = 0; # 這是一個全局變量 # 可寫函數說明 def sum( arg1, arg2 ): #返回2個參數的和." total = arg1 + arg2; # total在這里是局部變量. print ("函數內是局部變量 : ", total) return total; #調用sum函數 sum( 10, 20 ); print ("函數外是全局變量 : ", total) 以上實例輸出結果: 函數內是局部變量 : 30 函數外是全局變量 : 0 ```
2.4 匿名函數
python 使用 lambda 來創建匿名函數。
所謂匿名,意即不再使用 def 語句這樣標准的形式定義一個函數。
lambda 只是一個表達式,函數體比 def 簡單很多。
lambda的主體是一個表達式,而不是一個代碼塊。僅僅能在lambda表達式中封裝有限的邏輯進去。
lambda 函數擁有自己的命名空間,且不能訪問自有參數列表之外或全局命名空間里的參數。
雖然lambda函數看起來只能寫一行,卻不等同於C或C++的內聯函數,后者的目的是調用小函數時不占用棧內存從而增加運行效率。
語法
lambda 函數的語法只包含一個語句,如下:
lambda [arg1 [,arg2,.....argn]]:expression
如下實例:

``` #!/usr/bin/python3 # 可寫函數說明 sum = lambda arg1, arg2: arg1 + arg2; # 調用sum函數 print ("相加后的值為 : ", sum( 10, 20 )) print ("相加后的值為 : ", sum( 20, 20 )) 以上實例輸出結果: 相加后的值為 : 30 相加后的值為 : 40 ```
3.文件操作
3.1 open函數
python的內置函數open()可以打開文件,創建一個file對象,格式如下:
file object = open(file_name [, access_mode][, buffering][,encoding=utf-8])
各個參數的細節如下:
- file_name:file_name變量是一個包含了你要訪問的文件名稱的字符串值。
- access_mode:access_mode決定了打開文件的模式:只讀,寫入,追加等。所有可取值見如下的完全列表。這個參數是非強制的,默認文件訪問模式為只讀(r)。
- buffering:如果buffering的值被設為0,就不會有寄存。如果buffering的值取1,訪問文件時會寄存行。如果將buffering的值設為大於1的整數,表明了這就是的寄存區的緩沖大小。如果取負值,寄存區的緩沖大小則為系統默認
- encoding = utf-8 表示使用utf-8字符集打開
3.2 文件打開模式
模式 | 描述 |
---|---|
r | 以只讀方式打開文件。文件的指針將會放在文件的開頭。這是默認模式。 |
rb | 以二進制格式打開一個文件用於只讀。文件指針將會放在文件的開頭。這是默認模式。 |
r+ | 打開一個文件用於讀寫。文件指針將會放在文件的開頭 |
rb+ | 以二進制格式打開一個文件用於讀寫。文件指針將會放在文件的開頭。 |
w | 打開一個文件只用於寫入。如果該文件已存在則將其覆蓋。如果該文件不存在,創建新文件。 |
wb | 以二進制格式打開一個文件只用於寫入。如果該文件已存在則將其覆蓋。如果該文件不存在,創建新文件。 |
w+ | 打開一個文件用於讀寫。如果該文件已存在則將其覆蓋。如果該文件不存在,創建新文件。 |
wb+ | 以二進制格式打開一個文件用於讀寫。如果該文件已存在則將其覆蓋。如果該文件不存在,創建新文件。 |
a | 打開一個文件用於追加。如果該文件已存在,文件指針將會放在文件的結尾。也就是說,新的內容將會被寫入到已有內容之后。如果該文件不存在,創建新文件進行寫入。 |
ab | 以二進制格式打開一個文件用於追加。如果該文件已存在,文件指針將會放在文件的結尾。也就是說,新的內容將會被寫入到已有內容之后。如果該文件不存在,創建新文件進行寫入。 |
a+ | 打開一個文件用於讀寫。如果該文件已存在,文件指針將會放在文件的結尾。文件打開時會是追加模式。如果該文件不存在,創建新文件用於讀寫。 |
ab+ | 以二進制格式打開一個文件用於追加。如果該文件已存在,文件指針將會放在文件的結尾。如果該文件不存在,創建新文件用於讀寫。 |
PS:以b方式打開時,讀取到的內容是字節類型,寫入時也需要提供字節類型,否則使用讀到的是字符串,寫入時也按字符串
3.3 file對象的屬性
- 文件被打開之后,此文件對象的屬性有如下幾個:
屬性 | 描述 |
---|---|
file.closed | 返回true如果文件已被關閉,否則返回false。 |
file.mode | 返回被打開文件的訪問模式。 |
file.name | 返回文件的名稱。 |
file.softspace | 如果用print輸出后,必須跟一個空格符,則返回false。否則返回true |
file.encoding | 返回打開文件時使用的字符集 |
-
示例
``` >>> fp = open("test",'r') >>> fp.name #顯示打開的文件名 'test' >>> fp.closed #判斷文件是否被關閉 False >>> fp.mode #輸出文件打開的模式 'r' >>> fp.softspace #python3不支持此屬性 Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: '_io.TextIOWrapper' object has no attribute 'softspace' ```
3.4 file對象的常用操作函數
- seek() 調整當前的指針位置,以字節為單位進行調整.從指針位置開始后面會依次覆蓋
- tell() 獲取當前指針位置
- read() 默認讀取一個打開的文件中所有字符串。需要重點注意的是,Python字符串可以是二進制數據,而不是僅僅是文字
- write() 寫數據
- close() 關閉打開的文件
- fileno 獲取文件描述符
- flush() 強制將緩沖區內容寫到硬盤
- readable() 是否可讀
- writeable() 是否可寫
- readline() 僅讀取一行
- truncate() 截斷指針位置.后面內容清空
- readlines() 讀取文件內容,將每行作為列表的元素,最終組合成一個列表
PS:使用輸入方法read() 或者 readlines() 從文件中讀取行時,python並不會刪除行結尾符
tell()方法告訴你文件內的當前位置;換句話說,下一次的讀寫會發生在文件開頭這么多字節之后。
seek(offset [,whence])方法改變當前文件的位置。Offset變量表示要移動的字節數。whence變量指定開始移動字節的參考位置。
如果whence被設為0,這意味着將文件的開頭作為移動字節的參考位置。如果設為1,則使用當前的位置作為參考位置。如果它被設為2,那么該文件的末尾將作為參考位置。注意:python3中已經不允許非二進制打開的文件,相對於文件末尾和當前位置的定位,指針只能從文件開頭開始。python2沒有限制
示例:
test 文件內容:
fuzengjie付增傑
付增傑abcdefghjkl
腳本:初衷是在test文件的第21個字符后面,指針偏移4位,插入123

``` #!/usr/bin/env python # -*- coding: UTF-8 -*- #pyversion:python3.5 #owner:fuzj fp = open("test","r+") #使用r+方式打開test rs = fp.read(21) #讀test第21個字符以內的所有字符,包括第21個以及中間換行。如果是字符 print("文件內容: ",rs) #打印讀取的內容 ad = fp.tell() #打印當前的指針位置 print("當前指針位置: ",ad) se = fp.seek(4,1) fp.write("123") #寫入123 fp.close() ```
使用py3運行后會報錯
io.UnsupportedOperation: can't do nonzero cur-relative seeks。
如果將fp.seek(4,1)改為fp.seek(4,0)從文件開頭插入,則沒問題。
如果使用py2執行,則不會出現上述問題。
可以先獲取當前文件末尾的指針位置,然后再進行移動,
fp.seek(fp.tell(),0),這樣就可以將指針定位到末尾
現在換一種方法,使用二進制打開文件,然后進行插入
代碼:

``` #!/usr/bin/env python # -*- coding: UTF-8 -*- #pyversion:python3.5 #owner:fuzj fp = open("test","rb+") #使用二進制方式打開 rs = fp.read() print("文件內容: ",str(rs,encoding='utf-8')) #由於對象是二進制,所以需要使用str()來轉換成字符串 ad = fp.tell() print("當前指針位置: ",ad) se = fp.seek(-4,1) #在當前位置向左移動四個指針 print("改變后的指針位置:", fp.tell()) fp.write(bytes("123",encoding='utf-8')) ```
運行結果:

``` 文件內容: fuzengjie付增傑 付增傑abcdefg123l 當前指針位置: 39 改變后的指針位置: 35 test文件 fuzengjie付增傑 付增傑abcdefg123l #指針移動四位到h字符串,然后使用123開始往后替換,最后l字符串沒得替換,保留了。 ```
注意:一個漢字如果使用utf-8編碼集的話,會占3個字節,如果使用gbk編碼集的話,會占用2個字節。
- 文件打開的另一種方法:
使用with 打開文件,操作完之后,自動關閉

with open("test",'r') as f: #打開一個文件 pass #同時打開兩個文件 with open("test1",'r') as f1, open("test2",'r') as f2: pass