1. 程式人生 > >python修煉第三天

python修煉第三天

只讀 imp inter urlopen user 信息 創建文件 爬蟲 orm

今天主要講了文件操作,函數與裝飾器,裝飾器比較燒腦,需要多做練習,逐步分解來進行理解! 加油!

一 文件操作

操作系統 提供文件的概念
可以操作磁盤。

文件的只讀模式: 註意如果是windows 前面要加個r:open(r"C:\a.txt") . 或者分隔符是 /
f = open("D:/python21期/L002-老男孩教育-Python20期VIP視頻-mp4/b.txt","r",encoding="utf-8")
data = f.read()
print(data)
f.close() # 文件關閉,回收操作系統的資源
print(f) 這個f變量還是存在的因為是python的變量。 python變量是在程序結束後自動釋放
f.read() 這個文件已經被操作系統關閉了,所以就無法read讀取了。

另一種方法: with open
with open("a.txt","r",encoding="utf-8")
pass
這個是可以幫你自動關閉文件

其他讀方法
1 f.readline() 只讀取一行
print(f.readline(),end="")
print(f.readline(),end="")
print(f.readline(),end="")

2 readlines() 吧文件都讀出來,並全部放在一個列表list裏面。
註意:如果文件過大,比如1T文件 就無法進行操作,這個只適用於小文件


文件的只寫模式: 默認是wt文本寫,如果文件不存在就創建文件,如果存在文件就清空原來的文件!!
f = open("b.txt","w",encoding="utf-8")
f.write(1111\n)
f.write(222222\n)
f.close()

其他寫方法:
1 f.write("11111\n")

2 f.writelines 可以通過列表的形式 或元祖的形式 吧多行內容寫到文件。
f.writelines(["name\n","age\n","hobbie"])
結果是
name
age
hobbie
########## 註意 如果是wt文本格式打開的那麽就只能寫字符串格式


1 文件處理
補充
print(f.writable()) 看一下是否是可寫的 可寫返回True 不可寫False
新的寫模式:
a 追加模式, 整個文件末尾追加寫
f = open("b.txt","a",encoding="utf-8") 文件不存在就新建一個,如果存在就打開文件吧光標移動到文件末尾追加寫,原文件內容不影響

讀取多行的話 可以使用for
whit open("a.txt","r",encoding="utf-8") as f:
for line in f:
print(line)

b 模式 可以理解為而二進制
rb 二進制讀
with open("a.txt","rb‘) as f:
print(f.read().decode("utf-8")) ## 如果是文本內容也存為b二進制模式,可以使用decode解碼查看文本

wb 二進制寫
with open("a.txt","wb") as f:
res = "添加".encode("utf-8") 二進制寫需要進行一下編碼編碼為二進制寫
f.write(res)

ab 追加寫
跟上面一樣 就是需要encode("utf-8")

練習 ; 實現cp命令 可以拷貝任何類型的文件
import sys
_,src_file,dst_file = sys.argv # sys.argv是獲取運行的參數,第一個是cp.py程序文件 第二個是源文件,第三個是目標文件,
# 所以第一個不用獲取,_,就可以空出第一個參數,src_file是第二個參數源文件
# dst_file 是第三個參數目標文件。
with open("src_file","rb") as read_f, open("dst_file","wb") as write_f:
for line in read_f:
write_f.write(line)
# 註意內存的數據往硬盤中存建議設置個緩存區,積攢一定的大小猴在往磁盤中寫入,減少IO壓力
# wirte_f.flush() 這個是告訴操作系統趕快寫到磁盤中

文件的修改:
import os
with open("1.txt","r",encoding="utf-8") as read_f,open(".1.txt.swap","w",encoding="utf-8") as write_f:
data = read_f.read()
write_f.write(read_f.replace("alex","SB"))
os.remove("1.txt")
os.rename(".1,txt.swap","1.txt")
這樣是吧整個文件都寫入到內存中修改,如果文件過大,會導致卡頓,所以可以一行一行的改:
for i in read_f:
if "alex" in i:
i = i.replace("alex","SB")
write_f.write(i)

文件內光標移動
只有一種情況光標指的是以字符為單位移動
with open("c.txt","rt","")as f:
f.read(3)
只有read方式才能以字符方式移動
print(f.tell) 告訴光標在第幾個字節。 註意 如果有中文的話 一個中文是3個字節。比如
hello你好
f.read(6)
print(f.tell())
這個結果就是8 因為一個英文是一個字節,中文是三個字節 所以讀到第六個字符後,這個光標就在5+3=8的字節上

光標的移動
f.seek
with open("a.txt","rt",encoding="utf-8") as f:
f.read(6)
print(f.tell())
這個時候是光標已經移動到了第6個字符(第8個字節)
f.seek(8,0) # 第一個參數是移動幾個字節, 第二個參數有三個模式:0,1,2. 0代表相對的位置參照物,參照文件的最開頭開始移動
# seek(8,0) 就是從開頭0開始移動 往後移動8個字節。
# 0模式在字符t模式與二進制b模式下都可以使用。另外的 1 2 模式需要在bytes模式才能使用。他們的移動單位都是字節
print(f.read())
結果是打印第8個字節後面的內容。

1模式:
從當前光標開始往後移動。
f.read(6) # 已經移動了6個
f.seek(2,1) # 從當前第6個光標繼續往後移動2個
print(f.read())
結果是6+2個字節,也是打印第8個字節後面的內容。

2模式:
從文件最末尾為參考開始移動。倒著移動
f.seek(-3,2)
print(f.read())
從文件最後往前移動3個字節,如果文件最後是一個中文,那就只打印這個中文

實現 tail -f access.log
with open("access.log","rb") as f:
f.seek()
while True:
line = f.readline()
if line:
print(line)
else:
time.sleep(0.5)
註意 二進制b模式不翻譯\n換行符。 字符t模式翻譯\n 如果文本內容有\n換行符,二進制b模式print(line.decode(),end="")
end="" 就是把print自帶的空格取消。 如果文本內容中沒有\n換行符,哪就直接使用print(line) 就可以了


截斷文件
截斷模式只能是 a 模式下使用:
with open("a.txt","a",encoding="utf-8") as f:
f.truncate(3) # 只有從文件開頭為參照物。3代表截取3個字節
#就是只截斷前三個字符



2 函數

  1函數基礎
為何要用函數?沒有函數帶來的困擾
1 組織結構不清晰,可讀性差
2 代碼冗余
3 可擴展性差

什麽是函數?
具備某一個功能的工具-->函數
函數就是事先準備的工具
工具準備好了 ,拿來就可以用。重復使用
先定義,後調用。

函數的分類?
內置函數:
help(函數名) 這個就是查看函數下面的註釋信息 參考語法1
len
max
mix
count
自定義函數:def 自定義函數
定義函數
語法:
def 函數名(參數1,參數2):
""" 註釋信息""" # 可選
函數體,功能體
return 返回值
(其實函數就是一個變量,只不過可以調用)
所以執行函數分為兩步,第一步是通過函數名找到這個函數變量,找到函數就可以用()來調用。
定義階段:
定義函數只檢測語法是否問題,不定義代碼。

調用函數:
先定義後調用。
調用函數,如果函數中定義的變量等功能沒有或其他問題就會報錯。
列子:

def foo():
print(‘from foo")
bar()
foo()
第一次調用會出現問題,因為bar函數沒有定義,所以需要再定義一個bar函數
def bar():
print("from bar")
foo()
這次就可以了。 註意先定義後調用原則。

定義函數的三種形式:
1:無參函數
def foo()
print("我是無參數函數")
2:有參函數
def auth(u,p):
if u =="root" and p == "123":
print("login successfull")
else:
print("user or password err")
def interactive()
name = input("請輸入賬號:").strip()
password = input("請輸入密碼:").strip()
auth(name,password)
3:空函數
def auth():
pass
在寫應用的時候,針對每個功能定義一個函數。空函數就是先一個框架。站個位置。

函數的返回值:
# 函數內可以有多個return 但是只能執行一個return。
def foo(x,y)
print("first")
return 1
print("second")
return 2
print("third")
return 3
res=foo()
print(res) 結果是first 1 因為執行遇到return後就退出了。先運行程序,然後在輸出返回值

# 執行return函數就立刻結束,並且return後的值當做本次調用的結果返回。
def foo(x,y):
retrue x+y
res = foo(1,2)

可以返回函數:
def bar();
print("from bar")
def foo():
return bar()
print(foo())

沒有return 沒有return 返回的是 None print(foo)是打印函數內存地址, print(foo())是返回執行結果
返回一個值return 就返回值本身。
return多個值 返回的是一個元祖格式。

函數調用的三種形式:
def my_mix(x,y):
if x >=y:
return x
else:
reture y
第一種: 單獨使用
res1 = my_max
第二種: 把函數返回值的結果進行運算
res2 = my_max(1,2)*10
第三種: 函數調用可以當作另外一個函數的參數
res3 = foo(my_max(1,2),aa)

函數參數的使用
1.參數種類:兩種
1 形參 def foo(x,y) 在定義階段在括號內是形參, 形參在定義階段是不占內存空間的
2 實參 foo(1,2) 在調用階段括號內傳入的值叫實參, 相當於值
在調用階段,實參的值會綁定給形參,在調用結束後解除綁定 。
2.位置參數
按照從左到右的順序依次定義的參數。
1 位置形參:必須被傳值,多一個少一個都不行。
2 位置實參:與形參一一對應傳值。
def foo(x,y)
print(x,y)
foo(y=1,x=1)
3.關鍵字參數
在函數調用時,按照key=value的形式定義的實參
特點:指名道姓地給形參傳值,不再依賴於位置
註意:
def foo(name,age,sex):
print(name,age,sex)
註意: 1關鍵字實參必須在位置實參的後面。
2不能為同一個參數賦多次值。

4.默認參數
1 指的是在函數定義階段,就已經為形參復制。
def foo(x,y=1):
print(x,y)
默認參數的好處就是可以不用傳值,當然也可以傳值來修改默認參數的值
2 默認參數的值只在定義時被復制一次
res = 1
def foo(x,y=res):
print(x,y)
res = 10
foo("aaaa")
結果是 "aaaa" 1
3 默認參數的值通常應該是不可變類型。 要麽是數字,要嗎是元祖

5.可變長參數*args, **kwargs
在調用函數時,實參值得個數不固定
實參的形式有:位置實參和關鍵字實參。
就是實參兩個形式的長度個數是不固定。
形參的解決方案: * 和 **
* 是位置實參解決方案
** 是關鍵字key value解決方案
1 *args
位置的實參會保存為元祖的形式保存
def foo(x,y,*z):
print(x,y)
print(z)
foo(1,2,3,4,5,6)
結果是吧1給x 2給y *接收後面的然後以元祖形式賦值給z3,4,5,6給z
1,2
( 3,4,5,6 )
另一種
def foo(x,y):
print(x,y)
foo(*(1,2))
結果是1,2
2 **kwargs
def foo(x,y,**kwargs):
print(x,y)
foo(x=1,y=2,i=3,l=4)
這種情況*會接收i=3,l=4 並賦值給kwargs 保存為字典 格式。
另一種
def foo(x,y,**kwargs)
foo(y=2,**{"c":5,"b":6,"x":2})
3 應用場景
def bar(x,y,z):
print(x,y,z)
def wrapper(*args.**kwargs):
bar(*args,**kwargs)
wrapper(1,2,3,a=1,b=2,c=2)
這樣就會報錯,因為wrapper接收參數後,傳給bar,然後bar 通過* 與**原封不動的解析回
一開始傳給wrapper的參數,所以bar就會報錯。無法賦值。

6.命名關鍵字參數
指的是定義在*後的參數,該參數必須被傳值(除非他有默認值),而且必須按照key=value的形式傳值。

三 函數進階

(1)名稱空間:
1 名稱空間
2 局部名稱空間
3 內置名稱空間

1 名稱空間,或命名空間
運行時開辟出來,裏面存的是變量與值內存地址的關系

2 臨時名稱空間
比如定義了一個函數
def func():
name = "wustr"
age = 23
函數名存放到內存空間中
但是函數體中的變量沒有管。
當遇到函數執行的時候,他會通過函數名找到函數體裏面的變量然後
臨時開辟出一個內存空間,就是臨時命名空間,也叫局部名稱空間,然後
吧函數裏面的變量與值得關系存入到臨時命名空間裏面
然後隨著函數的執行結束,臨時名稱空間的內存就消失。釋放。

3 內置名稱空間
只要創建了py文件 解釋器就會吧內置名稱空間加載到內存中了。內置函數就可以使用了
比如:len()

(2)作用域:
1 全局作用域:全局名稱空間,內置名稱空間
2 局部作用域:局部名稱空間

(3)加載順序,取值順序
加載順序:內置名稱空間先加載到內存。然後是全局名稱空間加載到內存,最後是局部名稱空間(只有函數執行時才加載)
取值順序:
函數先從局部作用域取值,如果沒有在找全局作用域,如果還沒有就找內置名稱空間。也就是從內向外找。
而且只是單向的,找到最後沒有就沒了

globals locals 內置函數
globals 將全局命名空間打印出來
locals 將局部命名空間打印出來

global nonlocal 關鍵字
global
函數裏面可以使用全局命名空間的變量。但是不能改變。如果要改變需要使用global關鍵字聲明全局變量

nonlocal 聲明全局變量,如果存在就更改全局變量。
引用並改變上一層的局部變量。上一層同層的變量都會改變。


(4)函數名:
1 可以相互賦值
def fun1():
print(666)
f1 = func1
f1()

2 可以當成函數的參數
def func2():
print(111)
def func3(argv):
argv()
print(222)
func3(func2)

3 可以當成容器類數據類型的參數
def func11():
print(222)
def func22():
print(333)
def func33():
print(444)
ll = ["func11","func22","func33"]
for i in ll:
i()

4 可以當作函數的參數和返回值
def func():
print(666)
def func1(argv)
print(777)
return argv
res = func1(func)
res()

(5)閉包:
內層函數對外層函數非全局變量的引用
def wrapper():
name = "alex"
def inner():
print((name)
inner()
wrapper()

判斷是不是閉包 inner.__closure__
如果是返回cell 不是返回 None
好處是:如果python檢測是閉包。有一個機制,你的局部作用域不會隨著函數的結束而結束。
比如爬蟲,爬下來的數據,使用閉包可以吧爬下來的數據保存到內存中,下次再爬直接從內存中取
import urlopen,url
def index():
url = "http://www.xiaohua100.com/index.html"
def get():
return urlopen(url).read()
return get
index()()

四 裝飾器

    函數對象
函數是第一類對象:指的是函數可以當作數據傳遞
1 可以被引用 x=1,x=y
def func(x,y):
print(x,y)
f=func
f(1,2)

2 可以當作函數的參數傳入
def foo():
print("form foo")
def bar(x):
x():
bar(foo)
3 可以當作函數的返回值
4 可以當作容器類型的元素

後續內容待補。。。

python修煉第三天