python 集合、函數和文件操作


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

     

  • 刪除元素

刪除可以使用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
View Code

 

  • 交集

交集為兩個集合相同的元素,使用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}
View Code

 

  • 並集

並集為兩個集合合並,去重后的結果,可以用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}
View Code

 

  • 差集

差集為兩個集合不相同的元素,或者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}
View Code

 

  • 其他函數

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

 

運行結果:

```
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'}

```
View Code

 

2.函數

函數是組織好的,可重復使用的,用來實現單一,或相關聯功能的代碼段。函數能提高應用的模塊性,和代碼的重復利用率,分自定義函數和內置函數

2.1 函數的創建

  • 格式

def 函數名(參數):
代碼塊
return 返回值

  • 要素

    • 函數代碼塊以 def 關鍵詞開頭,后接函數標識符名稱和圓括號 ()。
    • 任何傳入參數和自變量必須放在圓括號中間,圓括號之間可以用於定義參數。
    • 函數的第一行語句可以選擇性地使用文檔字符串—用於存放函數說明。
    • 函數內容以冒號起始,並且縮進。
    • return [表達式] 結束函數,選擇性地返回一個值給調用方。不帶表達式的return相當於返回 None。函數中如果執行了return,此函數將終止執行return后面的語句
  • 示例

    ```
    >>> def hello(arg) :
            print(arg)
    
    >>> hello("Hello World!")
    Hello World!
    >>>
    ```
    View Code

     

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

     

  • 指定參數

關鍵字參數和函數調用關系緊密,函數調用使用關鍵字參數來確定傳入的參數值。使用關鍵字參數允許函數調用時參數的順序與聲明時不一致,因為 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)
    
        ```
    View Code

     

執行結果

```
#函數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'>
```
View Code

 

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

```
View Code

 

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

```
View Code

 

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

     

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

    ```
View Code

 

使用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'))
```
View Code

 


運行結果:
```
文件內容:  fuzengjie付增傑
付增傑abcdefg123l
當前指針位置:  39
改變后的指針位置: 35

test文件
fuzengjie付增傑
付增傑abcdefg123l   #指針移動四位到h字符串,然后使用123開始往后替換,最后l字符串沒得替換,保留了。

```
View Code

 

注意:一個漢字如果使用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
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM