1. 程式人生 > >python自動化學習筆記3-集合、函數、模塊

python自動化學習筆記3-集合、函數、模塊

內容 rem alt 進程 操作 字典類 修改 指定 img

文件操作

上次學習到文件的讀寫,為了高效的讀寫文件,我們可以用循環的方式,一行一行的進行讀寫操作,打開文件的方法是open的方法,打開文件執行完後還要進行關閉操作。

一般的文件流操作都包含緩沖機制,write方法並不直接將數據寫入文件,而是先寫入內存中特定的緩沖區。

正常情況下緩沖區滿時,操作系統會自動將緩沖數據寫入到文件中。

至於close方法,原理是內部先調用flush方法來刷新緩沖區,再執行關閉操作,這樣即使緩沖區數據未滿也能保證數據的完整性。

如果進程意外退出或正常退出時而未執行文件的close方法,緩沖區中的內容將會丟失。

所以我們通常用flush方法刷新緩沖區的,即將緩沖區中的數據立刻寫入文件,同時清空緩沖區。如下:

f=open(‘www‘,‘a+‘,encoding=‘utf-8‘)
f.
f.write(‘hahah\n‘)
f.flush()
f.close()

還有一種打開文件的方式,可以自動關閉文件,防止open方式忘記手動關閉文件。

with open(‘aaa‘,‘a+‘,encoding=‘utf-8‘) as f:
f.seek(0)
f.write(‘haha\n‘)
f.flush()

在 “with” 打開的代碼塊內,文件是打開的,而且可以自由讀取。 然而,一旦Python代碼從 “with” 負責的代碼段退出,文件會自動關閉。

用with打開文件的時候可以打開多個,用逗號分開就好:


with open(‘aaa‘,‘a+‘,encoding=‘utf-8‘) as f,open(‘www‘,‘w‘,encoding=‘utf-8‘)as w:
f.seek(0)
f.write(‘haha\n‘)
f.flush()
w.write(再見你好!‘)

打開多個文件時,我們就可以對多個文件同時進行操作了。

在文件操作時可能會遇到需要下載圖片或視頻的內容,如果我們要下載一個網站的圖片,進行保存,由於圖片地址時http協議的,所以我們需要用到request處理HTTP的功能。

import requests
url=‘https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1515432257731&di=feaf94121db96dc3e315f6c170e0d5a0&imgtype=0&src=http%3A%2F%2Fh.hiphotos.baidu.com%2Fzhidao%2Fpic%2Fitem%2F1e30e924b899a901934d50551d950a7b0208f55d.jpg‘
img=requests.get(url).content
f=open(‘ooo.jpg‘,‘wb‘)
f.write(img)

wb模式時文件的一種操作模式,wb代表以二進制的格式寫文件,還有以下幾種方式:

"rb" 以二進制讀方式打開,只能讀文件 , 如果文件不存在,會發生異常

"wb" 以二進制寫方式打開,只能寫文件, 如果文件不存在,創建該文件

如果文件已存在,先清空,再打開文件

"rt" 以文本讀方式打開,只能讀文件 , 如果文件不存在,會發生異常

"wt" 以文本寫方式打開,只能寫文件, 如果文件不存在,創建該文件

如果文件已存在,先清空,再打開文件

"rb+" 以二進制讀方式打開,可以讀、寫文件 , 如果文件不存在,會發生異常

"wb+" 以二進制寫方式打開,可以讀、寫文件, 如果文件不存在,創建該文件

如果文件已存在,先清空,再打開文件

實戰練習:

用學過的知識完成下面的小程序:

將文件中的內容個別文字進行批量替換。

with open(‘ttt‘,‘a+‘,encoding=‘utf-8‘)as f:
f.seek(0)
content=f.read()
new_content=content.replace(終於‘,還好‘)
f.seek(0)
f.truncate()
f.write(new_content)
f.flush()

上述方法我們直接取出所有內容,然後進行替換,清空源文件後再寫入所有內容,這樣的效率時不高的,文件小的時候還好,當文件有大量數據的時候,這種方法的效率就太低了。

我還可以用for循環的方式,進行逐行讀取,逐行修改的方式,但在文件中我們沒辦法在原文件中取讀完每一行就立馬進行修改

所以可以分為以下幾個步驟進行:

1、逐行高效讀取文件,進行修改

2、將修改後的內容寫入一個新的文件中

3、修改完成後刪除原有文件

4、將新文件的名稱修改為目標文件的名稱

import os#導入文件操作模塊
with open(‘ttt‘,‘r‘,encoding=‘utf-8‘)as f,open(‘new‘,‘a+‘,encoding=‘utf-8‘)as newf:#打開要修改的文件和一個新文件
for content in f:#遍歷文件內容
new_content=content.replace(還好‘,終於‘)#替換文字
newf.write(new_content)#寫入新文件
newf.flush()#立即刷新
os.remove(‘ttt‘)#刪除原有文件
os.rename(‘new‘,‘ttt‘)#重命名文件

集合

在Python中集合set是基本數據類型的一種,它有可變集合(set)和不可變集合(frozenset)兩種。創建集合set、集合set添加、集合刪除、交集、並集、差集的操作都是非常實用的方法。

集合的一個特點是天生去重

創建集合:


s=set()#空集合
s2={‘1‘,‘2‘,‘3‘,‘3‘,‘3‘}
list=[1,2,3,4,5,5,5,5,5,5]
s3=set(list)
#list 去重的話,需要循環取出比較
print(list)
print(s2)
print(s3)

查看執行結果:

[1, 2, 3, 4, 5, 5, 5, 5, 5, 5]
{‘2‘, ‘3‘, ‘1‘}
{1, 2, 3, 4, 5}

取集合的數據

s2={‘1‘,‘2‘,‘3‘,‘3‘,‘3‘}
#集合是無序的,沒有辦法通過下標來取數據
print(s2[2])

查看執行結果:

技術分享圖片

添加元素

s2={‘1‘,‘2‘,‘3‘,‘3‘,‘3‘}
s2.add(‘5‘)#add方法可以添加一個元素
print(s2)

查看執行結果:

{‘5‘, ‘2‘, ‘1‘, ‘3‘}

如果想添加多個元素的話,可以用update

s2={‘1‘,‘2‘,‘3‘,‘3‘,‘3‘}
s2.update([7,8,9]) # 添加多個元素
print(s2)

執行查看結果:

{7, ‘2‘, 8, 9, ‘1‘, ‘3‘}

刪除元素

刪除元素可以用pop()隨機刪除一個元素:

s2={‘1‘,‘2‘,‘3‘,‘4‘,‘8‘,‘9‘}
print(s2.pop())
print(s2)

查看執行結果:

2
{‘9‘, ‘1‘, ‘8‘, ‘4‘, ‘3‘}

集合的運算操作:

交集、並集、差集、子集、包含

s2={‘1‘,‘2‘,‘3‘,‘5‘}
s3={‘1‘,‘2‘,‘3‘,‘4‘,‘8‘,‘9‘}


#交集
print(s2.intersection(s3))#intersection
print(s2&s3)#&f符號是取交集

查看執行結果:

{‘1‘, ‘3‘, ‘2‘}
{‘1‘, ‘3‘, ‘2‘}

#並集
print(s2.union(s3))#union取並集
print(s2|s3)#|取並集

查看執行結果:

{‘8‘, ‘3‘, ‘5‘, ‘2‘, ‘1‘, ‘4‘, ‘9‘}
{‘8‘, ‘3‘, ‘5‘, ‘2‘, ‘1‘, ‘4‘, ‘9‘}

# #差集
print(s2.difference(s3))#S2中有,但是S3中沒有的
print(s3.difference(s2))#s3中有,但是s2中沒有的
print(s2-s3)#-代表差集,S2中有,但是S3中沒有的

查看執行結果:

{‘5‘}
{‘4‘, ‘8‘, ‘9‘}
{‘5‘}

子集、包含關系:

s2={‘1‘,‘2‘,‘3‘}
s3={‘1‘,‘2‘,‘3‘,‘4‘,‘8‘,‘9‘}
print(s2.issubset(s3)) #S2是S3的子集
print(s3.issuperset(s2))#S3包含S2

查看執行結果

True
True

函數

函數是把一堆代碼合到一起,變成一個整體,是一個方法或者功能的代碼段,可以重復使用。

定義一個函數的規則:

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

定義一個函數,並調用:hello world!

def hello():
print(‘hello world!‘)
hello() #函數的調用

查看執行結果:

hello world!

再來看一個實例:


def hello():
f=open(‘sss‘,‘a+‘)
f.seek(0)
f.write(‘www‘)
f.close()
hello()

查看執行結果:SSS文件中寫入了www

參數傳遞

在 python 中,類型屬於對象,變量是沒有類型的

a=[1,2,3]

a="Runoob"

以上代碼中,[1,2,3] 是 List 類型,"Runoob" 是 String 類型,而變量 a 是沒有類型,她僅僅是一個對象的引用(一個指針),可以是 List 類型對象,也可以指向 String 類型對象。

實例:def hello(filename,content=‘‘):#形參,形式參數
f = open(filename, ‘a+‘,encoding=‘utf-8‘)
#return #函數中添加return時,結束後邊的代碼
if content:
f.seek(0)
f.write(content)
res=‘‘
else:
f.seek(0)
res=f.read()
#return res return以後文件就不會被關閉了,所以要把return寫到後邊
f.close()
return res
print(hello(‘www‘,‘乒乒乓乓乒乒乓乓乒乒乓乓‘))#實參,實際的參數
users=hello(‘aaa‘)
print(users)


上述代碼我們可以看到,當content為空或不為空的時候會有一個判斷,一個用來讀文件,一個用來寫文件
形參,實參
#形參,位置參數也叫必填參數
#默認參數,定義是有一個默認值
#默認值參數是不必填的
#函數裏邊的變量只能在函數裏邊用,出了函數裏邊就不能用了,如果想獲取到函數的處理結果,必須return
#沒有return的話,返回的是none,return是非必填的,需要返回值的時候再寫
#函數中遇到return,函數運行結束
#所以return的兩個作用:1、返回函數值,2、結束運行

可變參數,默認參數,擴展參數(不定長參數)
def test(a,b=1,*args):#b=1為默認參數,默認參數為非必填
print(‘a‘,a)
print(‘b‘,b)
print(‘args‘,args)
test(‘hhh‘)
test(‘aaa‘,‘222‘,‘22233‘,‘44444‘,‘5555‘)#位置調用,根據參數的位置指定
test(b=5,a=10)#關鍵字參數,關鍵字調用,與位置調用不能混用
查看執行結果:
a hhh
b 1
args ()
a aaa
b 222
args (‘22233‘, ‘44444‘, ‘5555‘)
a 10
b 5
args ()
*args是可擴展參數,
可擴展參數為非必填參數,會把多傳的參數放到一個元祖中,可以自己定義名字。

參數為字典表的時候:
def test2(**kwargs):#keargs 字典
print(kwargs)
test2(name=‘222‘,sex=‘eee‘)#kwargs方式必須用關鍵字調用的方法

def test3(a,**kwargs):
print(a)
print(kwargs)
test3(a=10000,s=‘sss‘,d=‘ssss3‘)
查看執行結果:
{‘sex‘: ‘eee‘, ‘name‘: ‘222‘}
10000
{‘d‘: ‘ssss3‘, ‘s‘: ‘sss‘}

全局變量和局部變量

定義在函數內部的變量擁有一個局部作用域,定義在函數外的擁有全局作用域。

局部變量只能在其被聲明的函數內部訪問,而全局變量可以在整個程序範圍內訪問。調用函數時,所有在函數內聲明的變量名稱都將被加入到作用域中。

如下實例:


a=100      #全局變量
def test():
a=5 #局部變量
print(‘函數內部:‘,a)
def test2():
b=1
print(a)#獲取的全局變量100
test()
test2()
print(‘函數外部‘,a)#直接打印的外部的全局變量
查看執行結果:
函數內部: 5
100
函數外部 100

如果函數內部要使用全局變量的話,可以單獨進行聲明:例如:
#
d=100
def test():
global d#聲明一下這是全局變量
print(‘libian‘,d)
d=6
test()
print(‘waibian‘,d)

查看執行結果:
libian 100
waibian 6
我們看到函數內部因為生命了d為全局變量,所以執行的時候首先取全局變量d=100,然後對d進行了修改為d=6,所以全局變量變為6,再次打印的時候顯示為6.
我們看一下下邊這個例子:
money = 899
def test(consume):
return money-consume
def test1(money):
return test(money)+test(money)
money=test1(money)
print(money)
可以先預計一下執行結果,money=test1(money),先調用test1,money=899,執行test1又會調用test,傳參都是money,所以test執行後是0,test1執行是0+0=0;
我們執行一下看預期結果:0 #執行結果是0,預期正確
再看一下下邊的例子:
def test():
global f
f=5
print(f)
def test1():
c=f+5
return c
res=test1()
print(res)
看上邊的例子,有的朋友會預期,調用test1,c=f+5,f=5,所以結果應該是10,我們執行看一下結果:
技術分享圖片
從執行結果看到報錯了,因為沒有f沒有定義,那是因為我們調用的時候只調用了test1,沒有調用test,所以系統是不知道f的值的,只有調用的時候才會進行運算。
正確的是:
def test():
global f
f=5
print(f)
def test1():
c=f+5
return c
test()#需要調用才會執行test,不調用不執行
res=test1()
print(res)
查看執行結果:10
實例演練:
寫一個小程序,校驗輸入的字符串是否是一個合法的小數。
分析:1、小數分為正小數和負小數:例3.3,-2.33
2、小數有且只有一個小數點
3、校驗字符串就要先把輸入的內容強制類型轉換成字符串類型

def check_float(number):
if number.count(‘.‘) == 1:#判斷小數點的個數
num_left=number.split(‘.‘)[0]#以小數點為分割點
num_rigth=number.split(‘.‘)[1]
if num_left.isdigit() and num_rigth.isdigit():#小數點左邊和右邊都是數字,則為正小數
print(您輸入的是正小數‘)
elif number.count(‘-‘)==1 and number.startswith(‘-‘):#判斷符號的個數,且以負號開頭
if num_left.split(‘-‘)[1].isdigit() and num_rigth.isdigit():#小數點左邊,負號右邊都是數字,小數點右邊都是數字
print(您輸入的是負小數‘)
else:
print(您輸入的不是小數‘)
else:
print(您輸入的不是小數‘)
else:
print(您輸入的不是小數!‘)

str=input(請輸入要校驗的字符串:‘)#input輸入的就是字符串類型
check_float(str)#調用函數
大家可以自己試一下執行一下結果。

遞歸
在函數內部,可以調用其他函數。如果一個函數在內部調用自身本身,這個函數就是遞歸函數。
下面看一個例子:
def test1():
num =int(input(請輸入數字:‘))
if num%2==0:
return True
else:
print(不是偶數請重新輸入:‘)
return test1()
test1()
上述代碼,表達了輸入一個數字,如果是偶數,返回True ,如果是計數再次調用test1,知道輸入的是偶數返回True為止。這種我們就叫它遞歸函數。
遞歸函數的優點是定義簡單,邏輯清晰。
但是使用遞歸函數需要註意防止棧溢出。在計算機中,函數調用是通過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,
每當函數返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞歸調用的次數過多,會導致棧溢出。遞歸最多調用999次;

比較兩個字典的key和value:
########################################
#對比兩個報文中不一樣值
#1、循環第一個字典,取出key
#2、拿第一個的key去第二個的字典中去取值

d1={‘a‘:‘1‘,‘b‘:‘2‘}
d2={‘a‘:‘1‘,‘b‘:‘3‘}
def compare(d1,d2):
for key in d1:
v1=d1.get(key)
v2=d2.get(key)
if v2:
if v1==v2:
pass
else:
print(兩個值不一樣,不一樣的key:%s,v1的值:%s,v2的值:%s‘%(key,v1,v2))
compare(d1,d2)
查看執行結果:
兩個值不一樣,不一樣的key:b,v1的值:2,v2的值:3

判斷對象的數據類型方法,可以用type()方法,如:


def print_var_type(var):
if type(var)==str:#字符串類型
print(‘string‘)
elif type(var)==dict:#字典類型
print(‘dict‘)
elif type(var)==list:#列表類型
print(‘list‘)


s={‘name‘:‘pei‘}
print_var_type(s)

執行查看結果:

dict

模塊

在Python中用關鍵字import來引入某個模塊,比如要引用模塊math,就可以在文件最開始的地方用import math來引入。

如果需要調用模塊中的函數的話,需要用 模塊名.函數名 進行調用。

#一個python文件就是一個模塊
#1、標準模塊
# python自帶的,不需要安裝的
#2、第三方模塊
# 別人寫的,只要安裝就能使用
#3、自己寫的模塊
# pip install radis #直接pip install 就可以 在 python安裝目錄下的scripts,加到環境變量中
#下載好安裝包手動安裝,解壓,在命令行裏邊進入到解壓後的目錄,在執行python setup.py install
#或者進入到目錄中,shift+右鍵,在當前窗口打開命令,輸入python setup.py install

例如上面的校驗是否是小數的函數,存放在check.py文件中,如果需要直接調用函數,則需要導入這個模塊,如下:


import cheak
print(cheak.check_float(‘1.6‘))

執行的話就會直接調用check中的check_float 函數。

#導入python文件的實質是從頭到尾運行一次
#
#import play
#import 導入文件的時候是在當前目錄下找文件,
#當前目錄找不到的話,從環境變量裏面找
#環境變量就是讓一個命令在任何目錄下都能執行
#查看當前系統的環境變量目錄
import sys
print(sys.path)

實戰演練:

需求:access.log日誌

60S內同一個IP地址訪問超過200次,IP加入黑名單
#60s讀一次文件
#以空格切割,取第一個元素,獲取到IP
#把IP地址存入list,如果大於200次,則加入黑名單


import time
point = 0#文件指針

while True:
ips=[]#空列表,用於存放所有IP
bip = set()#定義一個空集合,用於存放需要加入黑名單的
with open(‘access.log‘) as f:
f.seek(point)
for line in f:
ip=line.split()[0]#分割每一行,默認split是以空格分隔
ips.append(ip)#添加到list
if ips.count(ip)>199:#判斷
bip.add(ip)
for i in bip:#bip為集合,存入的去重的ip
print(已經把%s加入黑名單‘%i)
point=f.tell()
time.sleep(60)
else:
print(沒有被攻擊‘)







python自動化學習筆記3-集合、函數、模塊