python學習筆記比較全(下)

self 參數

類的方法與普通的函數只有一個特別的區別——它們“必須”有一個額外的第一個參數名稱,但是在調用這個方法的時候你不為這個參數賦值,Python會提供這個值。這個特別的變量指對象本身,按照慣例它的名稱是self。

雖然你可以給這個參數任何名稱,但是“強烈建議”使用self這個名稱——其他名稱都是不贊成使用的。

使用一個標準的名稱有很多優點——1.方便別人閱讀;2.有些IDE(集成開發環境)也可以幫助你。

Python中的self等價於C++中的self指針和Java、C#中的this參考。

例:

class Person:

def sayHi(self): # self參數必須寫

print('Hello, how are you?')

p = Person()

p.sayHi() # self參數不需賦值

print(p) # 打印: <__main__.person instance="" at=""> (已經在__main__模塊中有了一個Person類的實例)

類的變量和對象的變量

類的變量: 由一個類的所有對象(實例)共享使用。當某個對象對類的變量做了改動的時候,這個改動會反映到所有其他的實例上。

對象的變量: 由類的每個對象/實例擁有。它們不是共享的,在同一個類的不同實例中,雖然對象的變量有相同的名稱,但是是互不相關的。

使用的數據成員名稱以“雙下劃線前綴”且不是雙下劃線後綴,比如__privatevar,Python的名稱管理體系會有效地把它作為私有變量。

慣例: 如果某個變量只想在類或對象中使用,就應該以單下劃線前綴。而其他的名稱都將作為公共的,可以被其他類/對象使用。

例:

class Person:

'''Represents a person.'''

population = 0 # 類的變量

def __init__(self, name):

'''Initializes the person's data.'''

# 每創建一個對象都增加

Person.population += 1 # 調用類的變量,必須用 類名.變量名,如果寫 self.變量名 則是對象的變量了

self.name = name # 對象的變量,每個對象獨立的

print('(Initializing %s) We have %d persons here.' % (self.name, Person.population))

def __del__(self):

'''I am dying.'''

print('%s says bye.' % self.name)

Person.population -= 1

def sayHi(self):

self.__sayHi2() # 調用私有方法,外部不能調用的

# 以雙下劃線開頭(但沒有雙下劃線結尾),則變成私有,僅供內部調用

def __sayHi2(self): # 使用 self.population 也可以讀取類的變量,只是改變的時候卻只改變對象的變量

print('Hi, my name is %s. We have %d persons here.' % (self.name, self.population))

swaroop = Person('Swaroop')

swaroop.sayHi() # 打印: Swaroop, 1

kalam = Person('Abdul Kalam')

kalam.sayHi() # 打印: Abdul Kalam, 2

swaroop.sayHi() # 打印: Swaroop, 2

print(Person.population) # 打印: 2

del swaroop # 調用對象的 __del__ 方法

print(Person.population) # 打印: 1

print(Person.__doc__) # 打印類的docstring

print(Person.__init__.__doc__) # 打印類的方法的docstring

繼承

多態現象:一個子類型在任何需要父類型的場合可以被替換成父類型,即對象可以被視作是父類的實例。

被繼承的類被稱為“基本類”或“超類”、“父類”。繼承的類被稱為“導出類”或“子類”。

例:

# 父類

class Member:

def __init__(self, name, age):

self.name = name

self.age = age

print('(Initialized Member: %s)' % self.name)

def tell(self):

print('Member Name:"%s" Age:"%s"' % (self.name, self.age))

def tell2(self):

print('Member haha...')

# 子類

class Student(Member): # 繼承的父類寫括號裡面;多繼承則寫多個,這括號的稱為繼承元組

def __init__(self, name, age, marks):

Member.__init__(self, name, age) # 父類的初始化,需手動寫;Python不會自動調用父類的constructor

self.marks = marks

print('(Initialized Student: %s)' % self.name)

def tell(self):

Member.tell(self) # 調用父類的方法,注意:方法調用之前要加上父類名稱前綴,然後把self變量及其他參數傳遞給它。

print('Marks: "%d"' % self.marks)

s = Student('Swaroop', 22, 75)

s.tell() # 會調用子類的方法

s.tell2() # 子類沒有的,則使用父類的;如果多繼承,且父類都有這個方法,則使用繼承元組中排前面的

特殊的方法

__init__ 方法

__init__ 方法在類的一個對象被建立時,馬上運行。用來對你的對象做初始化。

注意,這個名稱的開始和結尾都是雙下劃線。( __init__ 方法類似於C++、C#和Java中的 constructor )

例:

class Person:

def __init__(self, name):

self.test_name = name

def sayHi(self):

print('Hello, my name is ' + self.test_name)

self.test = 'sss' # 屬性可以隨處定義,不需事先定義

print('the test is ' + self.test)

p = Person('Swaroop')

p.sayHi() # 打印: Swaroop , sss

print('the Person test is ' + p.test) # 打印: sss

p.test2 = 'haha...'

print('the Person test2 is ' + p.test2) # 打印: haha...

名稱 說明

__init__(self,...) 這個方法在新建對象恰好要被返回使用之前被調用。

__del__(self) 在對象要被刪除之前調用。如使用 del 刪除時。

__str__(self) 在我們對對象使用 print 語句或是使用 str() 的時候調用。

__lt__(self,other) 當使用 小於 運算符 (

__gt__(self,other) 當使用 大於 運算符 (>) 的時候調用。

__eq__(self,other) 當使用 等於 運算符 (==) 的時候調用。

__ne__(self,other) 當使用 不等於 運算符 (!=) 的時候調用。

__le__(self,other) 當使用 小於等於 運算符 (<=) 的時候調用。

__ge__(self,other) 當使用 大於等於 運算符 (>=) 的時候調用。

__add__(self,other)當使用 加 運算符 (+) 的時候調用。

__getitem__(self,key) 使用x[key]索引操作符的時候調用。

__len__(self) 對序列對象使用內建的 len() 函數的時候調用。

try ... except (處理異常)

使用 try ... except 語句來處理異常。

except 從句可以專門處理單一的錯誤或異常,或者一組包括在圓括號內的錯誤/異常。沒有給出錯誤或異常的名稱,則處理所有的錯誤和異常。

如果某個錯誤或異常沒有被處理,默認的Python處理器就會被調用。它會終止程序的運行,並且打印一個消息。

還可以關聯上一個 else 從句,當沒有異常發生的時候執行。

常見異常(可避免的):

使用不存在的字典關鍵字 將引發 KeyError 異常。

搜索列表中不存在的值 將引發 ValueError 異常。

調用不存在的方法 將引發 AttributeError 異常。

引用不存在的變量 將引發 NameError 異常。

未強制轉換就混用數據類型 將引發 TypeError 異常。

導入一個並不存在的模塊將引發一個 ImportError 異常。

try ... finally

假如希望在無論異常發生與否的情況下都執行一段代碼,可以使用 finally 塊來完成。

注意,在一個 try 塊下,你可以同時使用 except 從句和 finally 塊。

如果在 finally 前面的 try 或者 except, else 等裡面有 return 語句,會先跳去執行 finally 再執行 return

raise 語句

可以使用 raise 語句引發異常(拋出異常)。你還得指明錯誤/異常的名稱和伴隨異常觸發的異常對象。

可以引發 Error 或 Exception 類的直接或間接導出類。

在Python 3裡,拋出自定義異常的語法有細微的變化。

Python 2 Python 3

① raise MyException MyException

② raise MyException, 'error message' raise MyException('error message')

③ raise MyException, 'error message', a_traceback raise MyException('error message').with_traceback(a_traceback)

④ raise 'error message' unsupported(不支持)

說明:

① 拋出不帶自定義錯誤信息的異常,這種最簡單的形式下,語法沒有改變。

② 拋出帶自定義錯誤信息的異常時:Python 2用一個逗號來分隔異常類和錯誤信息;Python 3把錯誤信息作為參數傳遞給異常類。

③ 拋出一個帶用戶自定義回溯(stack trace,堆棧追蹤)的異常。在Python 2和3裡這語法完全不同。

④ 在Python 2裡,可以僅僅拋出一個異常信息。在Python 3裡,這種形式不再被支持。2to3將會警告你它不能自動修復這種語法。

例:

raise RuntimeError("有異常發生")

生成器的 throw 方法

在Python 2裡,生成器有一個 throw()方法。

調用 a_generator.throw()會在生成器被暫停的時候拋出一個異常,然後返回由生成器函數獲取的下一個值。

Python 2 Python 3

① a_generator.throw(MyException) a_generator.throw(MyException) # 沒有變化

② a_generator.throw(MyException, 'error message') a_generator.throw(MyException('error message'))

③ a_generator.throw('error message') unsupported(不支持)

說明:

① 最簡單的形式下,生成器拋出不帶用戶自定義錯誤信息的異常。這種情況下,從Python 2到Python 3語法上沒有變化 。

② 如果生成器拋出一個帶用戶自定義錯誤信息的異常,你需要將這個錯誤信息字符串(error string)傳遞給異常類來以實例化它。

③ Python 2還支持拋出只有異常信息的異常。Python 3不支持這種語法,並且2to3會顯示一個警告信息,告訴你需要手動地來修復這處代碼。

例(3.x)語法:

# 定義一個異常類,繼承 Exception

class ShortInputException(Exception):

'''A user-defined exception class.'''

def __init__(self, length, atleast):

Exception.__init__(self)

self.length = length

self.atleast = atleast

try:

s = input('Enter something --> ') # Python 2 的輸入是 raw_input()

if len(s) < 3:

raise ShortInputException(len(s), 3) # 引發異常;Python 2可以寫:raise ShortInputException,(len(s), 3)

# 捕獲 EOFError 異常

except EOFError:

print('\\nWhy did you do an EOF on me?')

# 捕獲一組錯誤/異常,Python 2 時應該寫: “except (RuntimeError, ImportError), e:”

except (RuntimeError, ImportError) as e:

pass

# Python 2 時應該寫: “except ShortInputException, x:”

except ShortInputException as x:

print('ShortInputException: The input was of length %d,\\

was expecting at least %d' % (x.length, x.atleast))

# 捕獲所有異常

except:

print('\\nWhy did you do an Exception on me?')

# 沒有任何異常時執行

else:

print('No exception was raised.')

# 不管是否有異常,都會執行

finally:

print('finally .....')

lambda 形式

lambda 語句被用來創建新的函數對象,並且在運行時返回它們。

注意, lambda 形式中,只能使用表達式。

例:

def make_repeater(n):

return lambda s: s*n # 注意: lambda 返回的是函數,而不是表達式的值

# 注意, twice 接收的是函數, 而不是表達式的值, 所以 twice 是一個函數,而不是值

twice = make_repeater(2)

print(twice('word ')) # 因為 twice 是一個函數,這裡是調用這個函數,打印結果: word word

print(make_repeater(3)(5)) # 這裡的“make_repeater(3)”可以認為是匿名函數,打印結果: 15

# 上面例子貌似太過複雜,下面是簡單點的寫法

# 記住, twice2 是一個函數

twice2 = lambda s: s*2

print(twice2('word ')) # 打印: word word

print(twice2(5)) # 打印: 10

# 上面的 twice2 相當於正常的函數這樣寫(lambda 後面的是參數,而結果是返回冒號後面的表達式):

def twice3(s):

return s*2

print(twice3('word ')) # 打印: word word

print(twice3(5)) # 打印: 10

# 可認為 lambda 是一個匿名函數

print((lambda s: s*2)('word ')) # 打印: word word

# 而 def 是不能申明匿名函數的

print((def (s): return s*2)(10)) # 這寫法將會報錯

print((def twice3(s): return s*2)(10)) # 這寫法也同樣會報錯

# lambda 可以有多個參數

twice4 = lambda x,y: x*y

print(twice4('word ', 3)) # 打印: word word word

print(twice4(5, 3)) # 打印: 15

exec 和 eval

exec 用來執行儲存在字符串或文件中的Python語句。

eval 用來計算存儲在字符串中的有效Python表達式。

exec 跟 eval 是相似的,但是 exec 更加強大並更具有技巧性。

eval 只能執行單獨一條表達式;但是 exec 能夠執行多條語句,導入(import),函數聲明

實際上 exec 能執行整個Python程序的字符串。

Python 2 與 Python 3 的比較

Python 2 Python 3

① exec codeString exec(codeString)

② exec codeString in global_namespace exec(codeString, global_namespace)

③ exec codeString in global_namespace, local_namespace exec(codeString, global_namespace, local_namespace)

說明:

① 就像 print 語句在Python 3裡變成了一個函數一樣, exec 語句在Python 3裡也變成一個函數。

② exec 可以指定名字空間,代碼將在這個由全局對象組成的私有空間裡執行。

③ exec 還可以指定一個本地名字空間(比如一個函數里聲明的變量)。

例:

exec('print("Hello World")') # 執行打印語句

print(eval('2*3')) # 打印:6

execfile 語句

Python 2裡的 execfile 語句也可以像執行Python代碼那樣使用字符串。不同的是 exec 使用字符串,而 execfile 則使用文件。

在Python 3裡,execfile 語句已經被去掉了。如果你真的想要執行一個文件裡的Python代碼(但是你不想導入它),你可以通過打開這個文件,讀取它的內容,然後調用 compile()全局函數強制Python解釋器編譯代碼,然後調用 exec() 函數。

Python 2 寫的: execfile('a_filename')

Python 3 寫的: exec(compile(open('a_filename', 'rb').read(), 'a_filename', 'exec'))

assert 語句

assert 語句用來聲明某個條件是真的。

當 assert 語句失敗的時候,會引發一個 AssertionError 錯誤。

比較常用於檢驗錯誤。

例:

assert 2 >= 1 # 正常運行

assert 0 >= 1 # 出現錯誤

repr 函數

repr 函數用來取得對象的規範字符串表示。反引號(也稱轉換符)可以完成相同的功能。

注意,在大多數時候有 eval(repr(object)) == object。

基本上, repr 函數和反引號用來獲取對象的可打印的表示形式。

你可以通過定義類的 __repr__ 方法來控制你的對象在被repr函數調用的時候返回的內容。

例:

i = ["item"]

print(repr(i)) # 打印:['item']

yield 用法

1) 包含 yield 的函數是一個 Generator, 與平常的函數不同

例:

def gen():

print 'enter'

yield 1

print 'next'

yield 2

print 'next end'

print('begin...')

gen() # 直接調用,發現打印沒有執行(與平常的函數不同)

# 從容器裡拿到 iterator 的時候它還什麼也不是,處在容器入口處,對於數組來說就是下標為-1的地方,對於函數來說就是函數入口嘛事沒幹,但是萬事俱備就欠 next 。

print('end...')

print

for i in gen():

print('...%d...' % i)

# 開始 for in , next 讓 itreator 爬行到 yield 語句存在的地方並返回值,

# 再次 next 就再爬到下一個 yield 語句存在的地方並返回值,依次這樣直到函數返回(容器盡頭)。

上面代碼的輸出是:

begin...

end...

enter

...1...

next

...2...

next end

2) Generator 裡面的 send(msg) 與 next()

調用 for in 時,相當於是使用 next() 語句或是 send(None)

如果沒有接收值則使用 send 發送的值必須是 None ,否則會出錯的,因為 yield 語句沒有接收這個值,但 send 又必須傳參數的。

例,用上例的 gen() 函數

c = gen()

print(c.next()) # 調用第一個 yield

print(c.send(None)) # 調用第二個 yield, 這裡 next() 與 send(None) 是同樣效果的

print(c.next()) # 第三次調用則出錯了,因為數組下標越界, 拋出 StopIteration 的異常; 但會把最後的“next end”打印出來,前兩個是沒法把它打印出來的

# send(msg) 貌似沒法把 msg 傳到參數中

def gen2(m):

for i in range(10):

print(m)

yield i + 101

d = gen2('***')

print(c.next())

print(c.send(5555)) # 打印的依然是 ***, 而不是 5555

3) throw() 與 close() 中斷 Generator

中斷 Generator 是一個非常靈活的技巧,可以通過 throw 拋出一個 GeneratorExit 異常來終止 Generator 。 Close() 方法作用是一樣的,其實內部它是調用了 throw(GeneratorExit) 的。我們看:

def close(self):

try:

self.throw(GeneratorExit)

except (GeneratorExit, StopIteration):

pass

else:

raise RuntimeError("generator ignored GeneratorExit") # Other exceptions are not caught

因此,當我們調用了 close() 方法後,再調用 next() 或是 send(msg) 的話會拋出一個異常

例,繼續用前面例的 gen() 函數

c = gen()

print(c.next()) # 調用第一個 yield

c.close()

print(c.next()) # 調用第二個 yield 出錯了,拋出 StopIteration 的異常, 因為前面的 close 已經關閉它了

正則表達式

正則表達式有強大並且標準化的方法來處理字符串查找、替換以及用複雜模式來解析文本。

正則表達式的語法比程序代碼更緊湊,格式更嚴格,比用組合調用字符串處理函數的方法更具有可讀性。

還可以在正則表達式中嵌入註釋信息,這樣就可以使它有自文檔化的功能。

匹配符:

^ 匹配字符串開始位置。在多行字符串模式匹配每一行的開頭。

$ 匹配字符串結束位置。在多行字符串模式匹配每一行的結尾。

. 匹配除了換行符外的任何字符,在 alternate 模式(re.DOTALL)下它甚至可以匹配換行。

\\A 匹配字符串開頭

\\Z 匹配字符串結尾

\\b 匹配一個單詞邊界。即 \\w 與 \\W 之間。

\\B 匹配一個非單詞邊界;相當於類 [^\\b]。

\\d 匹配一個數字。

\\D 匹配一個任意的非數字字符。

\\s 匹配任何空白字符;它相當於類 [ \\t\\n\\r\\f\\v]。

\\S 匹配任何非空白字符;它相當於類 [^ \\t\\n\\r\\f\\v]。

\\w 匹配任何字母數字字符;它相當於類 [a-zA-Z0-9_]。

\\W 匹配任何非字母數字字符;它相當於類 [^a-zA-Z0-9_]。

x? 匹配可選的x字符。即是0個或者1個x字符。

x* 匹配0個或更多的x。

x+ 匹配1個或者更多x。

x{n,m} 匹配n到m個x,至少n個,不能超過m個。

(a|b|c) 匹配單獨的任意一個a或者b或者c。

(x) 捕獲組,小括號括起來即可,它會記憶它匹配到的字符串。

可以用 re.search() 返回的匹配對象的 groups()函數來獲取到匹配的值。

\\1 記憶組,它表示記住的第一個分組;如果有超過一個的記憶分組,可以使用 \\2 和 \\3 等等。

記憶組的內容也要小括號括起來。

(?iLmsux) iLmsux的每個字符代表一種匹配模式

re.I(re.IGNORECASE): 忽略大小寫(括號內是完整寫法,下同)

re.M(re.MULTILINE): 多行模式,改變'^'和'$'的行為(參見上圖)

re.S(re.DOTALL): 點任意匹配模式,改變'.'的行為

re.L(re.LOCALE): 使預定字符類 \\w \\W \\b \\B \\s \\S 取決於當前區域設定

re.U(re.UNICODE): 使預定字符類 \\w \\W \\b \\B \\s \\S \\d \\D 取決於unicode定義的字符屬性

re.X(re.VERBOSE): 鬆散正則表達式模式。這個模式下正則表達式可以是多行,忽略空白字符,並可以加入註釋。

(?:表達式) 無捕獲組。與捕獲組表現一樣,只是沒有內容。

(?P<name>表達式) 命名組。與記憶組一樣,只是多了個名稱。/<name>

(?P=name) 命名組的逆向引用。

(?#...) “#”後面的將會作為註釋而忽略掉。例如:“ab(?#comment)cd”匹配“abcd”

(?=...) 之後的字符串需要匹配表達式才能成功匹配。不消耗字符串內容。 例:“a(?=\\d)”匹配“a12”中的“a”

(?!...) 之後的字符串需要不匹配表達式才能成功匹配。不消耗字符串內容。 例:“a(?!\\d)”匹配“abc”中的“a”

(?<=...) 之前的字符串需要匹配表達式才能成功匹配。不消耗字符串內容。 例:“(?<=\\d)a”匹配“2a”中的“a”

(?

注:上面4個表達式的裡面匹配的內容只能是一個字符,多個則報錯。

(?(id/name)yes-pattern|no-pattern) 如果編號為 id 或者別名為 name 的組匹配到字符串,則需要匹配yes-pattern,否則需要匹配no-pattern。 “|no-pattern”可以省略。如:“(\\d)ab(?(1)\\d|c)”匹配到“1ab2”和“abc”

元字符:

"[" 和 "]"

它們常用來匹配一個字符集。字符可以單個列出,也可以用“-”號分隔的兩個給定字符來表示一個字符區間。

例如,[abc] 將匹配"a", "b", 或 "c"中的任意一個字符;也可以用區間[a-c]來表示同一字符集,和前者效果一致。

元字符在類別裡並不起作用。例如,[a$]將匹配字符"a" 或 "$" 中的任意一個;"$" 在這裡恢復成普通字符。

也可以用補集來匹配不在區間範圍內的字符。其做法是把"^"作為類別的首個字符;其它地方的"^"只會簡單匹配 "^"字符本身。

例如,[^5] 將匹配除 "5" 之外的任意字符。

特殊字符都可以包含在一個字符類中。如,[\\s,.]字符類將匹配任何空白字符或","或"."。

反斜槓 "\"。

做為 Python 中的字符串字母,反斜槓後面可以加不同的字符以表示不同特殊意義。

它也可以用於取消所有的元字符,這樣你就可以在模式中匹配它們了。

例如,需要匹配字符 "[" 或 "\",可以在它們之前用反斜槓來取消它們的特殊意義: \\[ 或 \\\\。

建議使用原始字符串:

建議在處理正則表達式的時候總是使用原始字符串。如: r'\\bROAD$', 而不要寫成 '\\\\bROAD$'

否則,會因為理解正則表達式而消耗大量時間(正則表達式本身就已經夠讓人困惑的了)。

無捕獲組:

有時你想用一個組去收集正則表達式的一部分,但又對組的內容不感興趣。你可以用一個無捕獲組“(?:...)”來實現這項功能。

除了捕獲匹配組的內容之外,無捕獲組與捕獲組表現完全一樣;可以在其中放置任何字符、匹配符,可以在其他組(無捕獲組與捕獲組)中嵌套它。

無捕獲組對於修改已有組尤其有用,因為可以不用改變所有其他組號的情況下添加一個新組。

捕獲組和無捕獲組在搜索效率方面也一樣。

命名組:

與用數字指定組不同的是,它可以用名字來指定。除了該組有個名字之外,命名組也同捕獲組是相同的。

(?P<name>...) 定義一個命名組,(?P=name) 則是對命名組的逆向引用。/<name>

MatchObject 的方法處理捕獲組時接受的要麼是表示組號的整數,要麼是包含組名的字符串。所以命名組可以通過數字或者名稱兩種方式來得到一個組的信息。

鬆散正則表達式:

為了方便閱讀和維護,可以使用鬆散正則表達式,它與普通緊湊的正則表達式有兩點不同:

1, 空白符被忽略。空格、製表符(tab)和回車會被忽略。如果需要匹配他們,可以在前面加一個“\\”來轉義。

2, 註釋被忽略。註釋以“#”開頭直到行尾,與python代碼中的一樣。

使用鬆散正則表達式,需要傳遞一個叫 re.VERBOSE的 參數。詳細見下面例子。

例如:

# 必須引入 re 標準庫

import re

# 字符串替換: sub() 與 subn()

s = '100 NORTH MAIN ROAD'

# 將字符串結尾的單詞“ROAD”替換成“RD.”;該 re.sub() 函數執行基於正則表達式的字符串替換。

print(re.sub(r'\\bROAD$', 'RD.', s)) # 打印: 100 NORTH MAIN RD.

## subn() 與 sub() 作用一樣,但返回的是包含新字符串和替換執行次數的兩元組。

print(re.subn(r'\\bROAD$', 'RD.', s)) # 打印: ('100 NORTH MAIN RD.', 1)

# 字符串分割, split()

# 在正則表達式匹配的地方將字符串分片,將返回列表。只支持空白符和固定字符串。可指定最大分割次數,不指定將全部分割。

print(re.split(r'\\s+', 'this is a test')) # 打印: ['this', 'is', 'a', 'test']

print(re.split(r'\\W+', 'This is a test.', 2)) # 指定分割次數,打印:['this', 'is', 'a test']

# 如果你不僅對定界符之間的文本感興趣,也需要知道定界符是什麼。在 RE 中使用捕獲括號,就會同時傳回他們的值。

print(re.split(r'(\\W+)', 'This is a test.', 2)) # 捕獲定界符,打印:['this', ' ', 'is', ' ', 'a test']

## `MatchObject` 實例的幾個方法

r = re.search(r'\\bR(OA)(D)\\b', s)

print(r.groups()) # 返回一個包含字符串的元組,可用下標取元組的內容,打印: ('OA', 'D')

print(r.group()) # 返回正則表達式匹配的字符串,打印: ROAD

print(r.group(2)) # 返回捕獲組對應的內容(用數字指明第幾個捕獲組),打印: D

print(r.start()) # 返回匹配字符串開始的索引, 打印: 15

print(r.end()) # 返回匹配字符串結束的索引,打印: 19

print(r.span()) # 返回一個元組包含匹配字符串 (開始,結束) 的索引,打印: (15, 19)

# 匹配多個內容, findall() 返回一個匹配字符串行表

p = re.compile('\\d+')

s0 = '12 drummers drumming, 11 pipers piping, 10 lords a-leaping'

print(p.findall(s0)) # 打印: [12, 11, 10]

print(re.findall(r'\\d+', s0)) # 也可這樣寫,打印: [12, 11, 10]

# 匹配多個內容, finditer() 以迭代器返回

iterator = p.finditer(s0)

# iterator = re.finditer(r'\\d+', s0) # 上句也可以這樣寫

for match in iterator:

print(match.group()) # 三次分別打印:12、 11、 10

# 記憶組

print(re.sub('([^aeiou])y$', 'ies', 'vacancy')) # 將匹配的最後兩個字母替換掉,打印: vacanies

print(re.sub('([^aeiou])y$', r'\\1ies', 'vacancy')) # 將匹配的最後一個字母替換掉,記憶住前一個(小括號那部分),打印: vacancies

print(re.search('([^aeiou])y$', 'vacancy').group(1)) # 使用 group() 函數獲取對應的記憶組內容,打印: c

# 記憶組(匹配重複字符串)

p = re.compile(r'(?P<word>\\b\\w+)\\s+\\1') # 注意, re.match() 函數不能這樣用,會返回 None/<word>

p = p.search('Paris in the the spring')

# p = re.search(r'(?P<word>\\b\\w+)\\s+\\1', 'Paris in the the spring') # 這一句可以替換上面兩句/<word>

print(p.group()) # 返回正則表達式匹配的所有內容,打印: the the

print(p.groups()) # 返回一個包含字符串的元組,打印: ('the',)

# 捕獲組

r = re.search(r'\\bR(OA)(D)\\b', s) # 如過能匹配到,返回一個 SRE_Match 類(正則表達式匹配對象);匹配不到則返回“None”

# `MatchObject` 實例的幾個方法

if r: # 如果匹配不到,則 r 為 None,直接執行下面語句則會報錯;這裡先判斷一下,避免這錯誤

print(r.groups()) # 返回一個包含字符串的元組,可用下標取元組的內容,打印: ('OA', 'D')

print(r.group()) # 返回正則表達式匹配的字符串,打印: ROAD

print(r.group(2)) # 返回捕獲組對應的內容(用數字指明第幾個捕獲組),打印: D

# 無捕獲組

print(re.match("([abc])+", "abcdefab").groups()) # 正常捕獲的結果: ('c',)

print(re.match("(?:[abc])+", "abcdefab").groups()) # 無捕獲組的結果: ()

# 命名組

m = re.match(r'(?P<word>\\b\\w+\\b) *(?P<word2>\\b\\w+\\b)', 'Lots of punctuation')/<word2>/<word>

print(m.groups()) # 返回正則表達式匹配的所有內容,打印:('Lots', 'of')

print(m.group(1)) # 通過數字得到對應組的信息,打印: Lots

print(m.group('word2')) # 通過名稱得到對應組的信息,打印: of

# 命名組 逆向引用

p = re.compile(r'(?P<word>\\b\\w+)\\s+(?P=word)') # 與記憶組一樣用法, re.match() 函數同樣不能這樣用,會返回 None/<word>

p = p.search('Paris in the the spring') # r'(?P<word>\\b\\w+)\\s+(?P=word)' 與 r'(?P<word>\\b\\w+)\\s+\\1' 效果一樣/<word>/<word>

print(p.group()) # 返回正則表達式匹配的所有內容,打印: the the

print(p.groups()) # 返回一個包含字符串的元組,打印: ('the',)

# 使用鬆散正則表達式,以判斷羅馬數字為例

pattern = '''

^ # beginning of string

(M{0,3}) # thousands - 0 to 3 Ms

(CM|CD|D?C{0,3}) # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 Cs),

# or 500-800 (D, followed by 0 to 3 Cs)

(XC|XL|L?X{0,3}) # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 Xs),

# or 50-80 (L, followed by 0 to 3 Xs)

(IX|IV|V?I{0,3}) # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 Is),

# or 5-8 (V, followed by 0 to 3 Is)

$ # end of string

'''

print(re.search(pattern, 'M')) # 這個沒有申明為鬆散正則表達式,按普通的來處理了,打印: None

print(re.search(pattern, 'M', re.VERBOSE).groups()) # 打印: ('M', '', '', '')

# (?iLmsux) 用法

# 以下這三句的寫法都是一樣的效果,表示忽略大小寫,打印: ['aa', 'AA']

print(re.findall(r'(?i)(aa)', 'aa kkAAK s'))

print(re.findall(r'(aa)', 'aa kkAAK s', re.I))

print(re.findall(r'(aa)', 'aa kkAAK s', re.IGNORECASE))

# 可以多種模式同時生效

print(re.findall(r'(?im)(aa)', 'aa kkAAK s')) # 直接在正則表達式裡面寫

print(re.findall(r'(aa)', 'aa kkAAK s', re.I | re.M)) # 在參數裡面寫

print(re.findall(r'(aa)', 'aa kkAAK s', re.I or re.M))

# 預編譯正則表達式解析的寫法

# romPattern = re.compile(pattern) # 如果不是鬆散正則表達式,則這樣寫,即少寫 re.VERBOSE 參數

romPattern = re.compile(pattern, re.VERBOSE)

print(romPattern.search('MCMLXXXIX').groups()) # 打印: ('M', 'CM', 'LXXX', 'IX')

print(romPattern.search('MMMDCCCLXXXVIII').groups()) # 打印: ('MMM', 'DCCC', 'LXXX', 'VIII')

# match()、search()、sub()、findall() 等等都可以這樣用

match() vs search()

match() 函數只檢查 RE 是否在字符串開始處匹配,而 search() 則是掃描整個字符串。記住這一區別是重要的。

match() 只報告一次成功的匹配,它將從 0 處開始;如果匹配不是從 0 開始的, match() 將不會報告它。

search() 將掃描整個字符串,並報告它找到的第一個匹配。

例:

print(re.match('super', 'superstition').span()) # 打印: (0, 5)

print(re.match('super', 'insuperable')) # 打印: None

print(re.search('super', 'superstition').span()) # 打印: (0, 5)

print(re.search('super', 'insuperable').span()) # 打印: (2, 7)

Python標準庫:

os 模塊

這個模塊包含普遍的操作系統功能。如果你希望你的程序能夠與平臺無關的話,這個模塊是尤為重要的。

os.sep 獲取操作系統特定的路徑分割符。比如在Linux、Unix下它是'/',在Windows下它是'\\\\',而在Mac OS下它是':'。

os.name 字符串指示你正在使用的平臺。比如對於Windows,它是'nt',而對於Linux/Unix用戶,它是'posix'。

os.getcwd() 函數得到當前工作目錄,即當前Python腳本工作的目錄路徑。

os.getenv(key) 函數用來讀取環境變量。

os.putenv(key, value) 函數用來設置環境變量。

os.listdir(path) 返回指定目錄下的所有文件和目錄名。

os.remove(filePath) 函數用來刪除一個文件。

os.system(shellStr) 函數用來運行shell命令,windows平臺則是運行批處理命令。

os.linesep 字符串給出當前平臺使用的行終止符。例如,Windows使用'\\r\\n',Linux使用'\\n'而Mac使用'\\r'。

os.path.split(pathname) 函數返回一個路徑的目錄名和文件名。

os.path.isfile(path) 函數檢驗給出的路徑是否一個文件。

os.path.isdir(path) 函數分別檢驗給出的路徑是否目錄。

os.path.existe(path) 函數用來檢驗給出的路徑是否真地存在。

unittest 模塊(單元測試)

單元測試的好處:

在編寫代碼之前,通過編寫單元測試來強迫你使用有用的方式細化你的需求。

在編寫代碼時,單元測試可以使你避免過度編碼。當所有測試用例通過時,實現的方法就完成了。

重構代碼時,單元測試用例有助於證明新版本的代碼跟老版本功能是一致的。

在維護代碼期間,可驗證代碼是否破壞原有代碼的狀態。

在團隊編碼中,縝密的測試套件可以降低你的代碼影響別人代碼的機率,提前發現代碼與其他人的不可以良好工作。

單元測試的原則:

完全自動運行,而不需要人工干預。單元測試幾乎是全自動的。

自主判斷被測試的方法是通過還是失敗,而不需要人工解釋結果。

獨立運行,而不依賴其它測試用例(即使測試的是同樣的方法)。即,每一個測試用例都是一個孤島。

例:

#### roman1.py 文件的內容 ####

# 定義異常類型(這裡僅做範例,不執行什麼)

class OutOfRangeError(ValueError): pass

class NotIntegerError(ValueError): pass

roman_numeral_map = (('M', 1000),

('CM', 900), ('D', 500), ('CD', 400), ('C', 100),

('XC', 90), ('L', 50), ('XL', 40), ('X', 10),

('IX', 9), ('V', 5), ('IV', 4), ('I', 1))

# 被測試函數

def to_roman(n):

'''convert integer to Roman numeral'''

# 數值範圍判斷

if not ( 0 < n < 4000 ):

raise OutOfRangeError('number out of range (must be less than 4000)')

# 類型判斷, 內建的 isinstance() 方法可以檢查變量的類型

# isinstance(n, int) 與 type(n) is int 等效

if not isinstance(n, int):

raise NotIntegerError('non-integers can not be converted')

result = ''

for numeral, integer in roman_numeral_map:

while n >= integer:

result += numeral

n -= integer

return result

#### 測試文件的內容 ####

import roman1 # 導入被測試的類

import unittest

# 需繼承 unittest 模塊的TestCase 類。TestCase 提供了很多可以用於測試特定條件的有用的方法。

class KnownValues(unittest.TestCase):

def setUp(self):

"""初始化"""

#執行數據庫連接,數據初始化等,此函數可不寫

pass

# setUp 和 tearDown 在執行每個測試函數的前後都會執行

def tearDown(self):

"""銷燬"""

pass

# 每一個獨立的測試都有它自己的不含參數及沒有返回值的方法。如果方法不拋出異常而正常退出則認為測試通過;否則,測試失敗。

# 測試本身是類一個方法,並且該方法以 test 開頭命名。如果不是 test 開頭,則不會執行。

def test_to_roman_known_values(self):

# 對於每一個測試用例, unittest 模塊會打印出測試方法的 docstring ,並且說明該測試失敗還是成功。

# 失敗時必然打印docstring, 成功時需使用“-v”命令行參數來查看。

'''to_roman 方法傳回的值與用例的數據不相等時,則測試不通過'''

# 測試的用例,一般是所有明顯的邊界用例。

known_values = ( (1, 'I'), (2, 'II'), (3, 'III'), (4, 'IV'),

(5, 'V'), (6, 'VI'), (7, 'VII'), (8, 'VIII'),

(9, 'IX'), (10, 'X'), (50, 'L'), (100, 'C'),

(500, 'D'), (1000, 'M'), (31, 'XXXI'), (148, 'CXLVIII'),

(3888, 'MMMDCCCLXXXVIII'), (3940, 'MMMCMXL'), (3999, 'MMMCMXCIX') )

for integer, numeral in known_values:

result = roman1.to_roman(integer) # 這裡調用真實的方法。如果該方法拋出了異常,則測試被視為失敗。

self.assertEqual(numeral, result) # 檢查兩個值是否相等。如果兩個值不一致,則拋出異常,並且測試失敗。

self.assertNotEqual(0, result, '這兩個值不應該相等') # 檢查兩個值是否不相等。

self.assertTrue(5 > 0, '5 > 0 都出錯,不是吧')

self.assertFalse(5 < 0)

# 對於每一個失敗的測試用例, unittest 模塊會打印出詳細的跟蹤信息。

# 如果所有返回值均與已知的期望值一致,則 self.assertEqual 不會拋出任何異常,於是此次測試最終會正常退出,這就意味著 to_roman() 通過此次測試。

assert 5 > 0 # 為了更靈活的判斷,可使用 assert

# 測試異常,讓被測試的方法拋出異常,這裡來驗證異常類型。如果預期的異常沒有拋出,則測試失敗。

def test_over_value(self):

'''參數過大或者過小時, to_roman 方法應該拋出異常信息'''

# assertRaises 方法需要以下參數:你期望的異常、你要測試的方法及傳入給方法的參數。

#(如果被測試的方法需要多個參數的話,則把所有參數依次傳入 assertRaises, 它會正確地把參數傳遞給被測方法的。)

self.assertRaises(roman1.OutOfRangeError, roman1.to_roman, 4000)

# 注意是把 to_roman() 方法作為參數傳遞;沒有調用被測方法,也不是把被測方法作為一個字符串名字傳遞進去

self.assertRaises(roman1.OutOfRangeError, roman1.to_roman, 0)

self.assertRaises(roman1.OutOfRangeError, roman1.to_roman, -1)

# 驗證參數類型

def test_non_integer(self):

'''如果參數不是 int 類型時, to_roman 方法應該拋出異常'''

self.assertRaises(roman1.NotIntegerError, roman1.to_roman, 0.5)

self.assertRaises(roman1.NotIntegerError, roman1.to_roman, 6.0)

# 在說明每個用例的詳細執行結果之後, unittest 打印出一個簡述來說明“多少用例被執行了”和“測試執行了多長時間”。

if __name__ == '__main__':

# main 方法會執行每個測試用例

unittest.main()

with 關鍵字

從Python 2.5開始有,需要 from __future__ import with_statement。自python 2.6開始,成為默認關鍵字。

with 是一個控制流語句, 跟 if/for/while/try 之類的是一類的,with 可以用來簡化 try finally 代碼,看起來可以比 try finally 更清晰。

with obj 語句在控制流程進入和離開其後的相關代碼中,允許對象obj管理所發生的事情。

執行 with obj 語句時,它執行 obj.__enter__() 方法來指示正在進入一個新的上下文。當控制流離開該上下文的時候,它就會執行 obj.__exit__(type, value, traceback)。

"上下文管理協議"context management protocol: 實現方法是為一個類定義 __enter__ 和 __exit__ 兩個函數。

with expresion as variable的執行過程是,首先執行 __enter__ 函數,它的返回值會賦給 as 後面的 variable, 想讓它返回什麼就返回什麼,如果不寫 as variable,返回值會被忽略。

然後,開始執行 with-block 中的語句,不論成功失敗(比如發生異常、錯誤,設置sys.exit()),在with-block執行完成後,會執行__exit__函數。

這樣的過程其實等價於:

try:

執行 __enter__()

執行 with_block.

finally:

執行 __exit__()

只不過,現在把一部分代碼封裝成了__enter__函數,清理代碼封裝成__exit__函數。

例:

import sys

class test:

def __enter__(self):

print("enter...")

return 1

def __exit__(self,*args):

print("exit...")

return True

with test() as t:

print("t is not the result of test(), it is __enter__ returned")

print("t is 1, yes, it is {0}".format(t))

raise NameError("Hi there")

sys.exit()

print("Never here")

注意:

1) t不是test()的值,test()返回的是"context manager object",是給with用的。t獲得的是__enter__函數的返回值,這是with拿到test()的對象執行之後的結果。t的值是1.

2) __exit__函數的返回值用來指示with-block部分發生的異常是否要 re-raise ,如果返回 False,則會拋出 with-block 的異常,如果返回 True,則就像什麼都沒發生。

在Python2.5中, file objec t擁有 __enter__ 和 __exit__ 方法,__enter__ 返回 object 自己,而 __exit__ 則關閉這個文件:

要打開一個文件,處理它的內容,並且保證關閉它,你就可以簡簡單單地這樣做:

with open("x.txt") as f:

data = f.read()

do something with data

補充:

數據庫的連接好像也可以和with一起使用,我在一本書上看到以下內容:

conn = sqlite.connect("somedb")

with conn:

conn.execute("insert into sometable values (?,?)",("foo","bar"))

在這個例子中,commit()是在所有with數據塊中的語句執行完畢並且沒有錯誤之後自動執行的,如果出現任何的異常,將執行rollback()

操作,再次提示異常

#####################################################

範例:

1.運行系統命令行

import os

os_command = 'echo haha...'

# 運行命令行,返回運行結果(成功時返回0,失敗返回1或以上的出錯數字)

result = os.system(os_command)

if result == 0:

print('run Successful')

else:

print('run FAILED')

# 注:os.system()函數不推薦使用,它容易引發嚴重的錯誤。(可能是因為不具備可移植性)

#os.system(os_command) # 這命令會彈出一個黑乎乎的cmd運行窗口,而且無法獲得輸出

p = os.popen(os_command) # 捕獲運行的屏幕輸出,以文件類型接收,不再另外彈出窗口

print(p.read()) # p 是個文件類型,可按文件的操作

2.獲取系統時間

import time,datetime

time.sleep(2) # 時間暫停兩秒

print(time.strftime('%Y-%m-%d %H:%M:%S')) # 打印如: 2011-04-13 18:30:10

print(time.strftime('%Y-%m-%d %A %X', time.localtime(time.time()))) # 顯示當前日期; 打印如: 2011-04-13 Wednesday 18:30:10

print(time.strftime("%Y-%m-%d %A %X", time.localtime())) # 顯示當前日期; 打印如: 2011-04-13 Wednesday 18:30:10

print(time.time()) # 以浮點數形式返回自Linux新世紀以來經過的秒數; 打印如: 1302687844.7

print(time.ctime(1150269086.6630149)) #time.ctime([sec]) 把秒數轉換成日期格式,如果不帶參數,則顯示當前的時間。打印如: Wed Apr 13 21:13:11 2011

# 得到今天的日期

print(datetime.date.today()) # 打印如: 2011-04-13

# 得到前一天的日期

print(datetime.date.today() + datetime.timedelta(days=-1)) # 打印如: 2011-04-12

print(datetime.date.today() - datetime.timedelta(days=1)) # 打印如: 2011-04-14

# 得到10天后的時間

print(datetime.date.today() + datetime.timedelta(days=10)) # 打印如: 2011-04-23

# 得到10小時後的時間,上面的 days 換成 hours

print(datetime.datetime.now() + datetime.timedelta(hours=10)) # 打印如: 2011-04-14 04:30:10.189000

#兩日期相減(也可以大於、小於來比較):

d1 = datetime.datetime(2005, 2, 16)

d2 = datetime.datetime(2004, 12, 31)

print((d1 - d2).days) # 打印: 47

#運行時間:

starttime = datetime.datetime.now()

time.sleep(1) # 暫停1秒

endtime = datetime.datetime.now()

print((endtime - starttime).seconds) # 秒, 打印: 1

print((endtime - starttime).microseconds) # 微秒; 打印: 14000

日期格式化符號:

%%: %號本身

%A: 本地星期(全稱),如:Tuesday %a: 本地星期(簡稱),如:Tue

%B: 本地月份(全稱),如:February %b: 本地月份(簡稱),如:Feb

%c: 本地相應的日期表示和時間表示,如:02/15/11 16:50:57

%d: 月內中的一天(0-31),如:15

%H: 24進制小時數(0-23)

%I: 12進制小時數(01-12)

%j: 年內的一天(001-366),如:046

%M: 分鐘(00-59),如:50 %m: 月份(01-12),如:02

%p: 上下午(本地A.M.或P.M.的等價符),如:PM

%S: 秒鐘(00-59),如:57

%X: 本地的時間,如:16:50:57 %x: 本地的日期,如:02/15/11

%Y: 四位的年(000-9999) %y: 兩位數的年份表示(00-99)

%U: 年裡的星期數(00-53)從星期天開始,如:07

%W: 年裡的星期數(00-53)從星期一開始,如:07

%w: 星期(0-6),星期天為星期的開始,如:2 (星期天為0)

%Z: 當前時區的名稱,如:中國標準時間

%z: 當前時區的名稱,如:中國標準時間

3.創建目錄

import os

pathDir = r'D:\\Work' # 不同系統的目錄寫法有所不同

if not os.path.exists(pathDir):

os.mkdir(pathDir) # 創建目錄, os.makedirs(pathDir) 創建多個不存在的目錄

target = pathDir + os.sep + 'test.txt'

print(target)

# 注意os.sep變量的用法, os.sep 是目錄分隔符,這樣寫方便移植。即在Linux、Unix下它是'/',在Windows下它是'\\\\',而在Mac OS下它是':'。

4.文件操作(讀寫txt文件)

filePath = 'poem.txt'

f = open(filePath, 'w') # 以寫的模式打開文件,Python 2.x 需將 open() / io.open() 改成 file()

for a in range( 0, 10 ):

s = "%5d %5d\\n" % (a, a*a)

f.write( s ) # 把文本寫入文件

f.close() # 關閉io流

f2 = open(filePath) # 沒有提供模式,則默認是讀取,即 'r'

while True:

line = f2.readline()

if len(line) == 0: # 讀取結束

break

print(line, end=' ') # 避免print自動換行, 此行Python2.x應該寫:“print line,”

f2.close() # close the file

# 刪除文件

import os

os.remove(filePath)

說明:

一、在pythony 3.0 已經廢棄了 file 類。

二、pythony 3.0 內置 open() 函數的構造函數是:

open(file, mode="r", buffering=None, encoding=None, errors=None, newline=None, closefd=True)

1.mode(模式):

r: 讀,只能讀文件,如果文件不存在,會發生異常

w: 寫,只能寫文件,如果文件不存在,創建該文件;如果文件已存在,先清空,再打開文件

a: 打開供追加

b: 二進制模式;一般是組合寫法,如: rb 以二進制讀方式打開;wb 以二進制寫方式打開

t: 文本模式

+: 打開一個磁盤文件供更新,一般是組合使用,如:

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

wb+: 以二進制寫方式打開,可以讀、寫文件,如果文件不存在,創建該文件;如果文件已存在,先清空,再打開文件

u: 通用換行模式

默認的模式是 rt,即打開供讀取的文本模式。

2.buffering 關鍵字參數的期望值是以下三個整數中的一個以決定緩衝策略:

0: 關閉緩衝

1: 行緩衝

> 1: 所填的 int 數=緩衝區大小

默認: 完全緩衝

3.encoding 默認的編碼方式獨立於平臺。

4.關閉文件描述符 closefd 可以是 True 或 False 。

如果是 False,此文件描述符會在文件關閉後保留。若文件名無法奏效的話,那麼必須設為 True 。

三、清空文件內容

f.truncate()

注意:當以 "r+","rb+","w","wb","wb+"等模式時可以執行該功能,即具有可寫模式時才可以。

四、文件的指針定位與查詢

(1)文件指針:

文件被打開後,其對象保存在 f 中, 它會記住文件的當前位置,以便於執行讀、寫操作,

這個位置稱為文件的指針( 一個從文件頭部開始計算的字節數 long 類型 )。

(2)文件打開時的位置:

以"r","r+","rb+" 讀方式, "w","w+","wb+"寫方式 打開的文件,

一開始,文件指針均指向文件的頭部。

(3)獲取文件指針的值:

L = f.tell()

(4)移動文件的指針

f.seek(偏移量, 選項) # 偏移量 是 long 或者 int 類型,計算偏移量時注意換行符是2,漢字可能是2或3

選項 =0 時, 表示將文件指針指向從文件頭部到 "偏移量"字節處。

選項 =1 時, 表示將文件指針指向從文件的當前位置,向後移動 "偏移量"字節。

選項 =2 時, 表示將文件指針指向從文件的尾部,,向前移動 "偏移量"字節。

五、從文件讀取指內容

1.文本文件(以"rt"方式打開的文件)的讀取

s = f.readline()

返回值: s 是字符串,從文件中讀取的一行,含行結束符。

說明: (1)如果 len(s) = 0 表示已到文件尾(換行符也是有長度的,長度為2)

(2)如果是文件的最後一行,有可能沒有行結束符

2.二進制文件(以"rb"、"rb+"、"wb+" 方式打開的文件)的讀取

s = f.read(n)

說明: (1)如果 len( s ) =0 表示已到文件尾

(2)文件讀取後,文件的指針向後移動 len(s) 字節。

(3)如果磁道已壞,會發生異常。

六、向文件寫入一個字符串

f.write( s )

參數: s 要寫入的字符串

說明: (1)文件寫入後,文件的指針向後移動 len(s) 字節。

(2)如果磁道已壞,或磁盤已滿會發生異常。

七、常用文件操作參考

[1.os]

1.重命名:os.rename(old, new)

2.刪除:os.remove(file)

3.列出目錄下的文件:os.listdir(path)

4.獲取當前工作目錄:os.getcwd()

5.改變工作目錄:os.chdir(newdir)

6.創建多級目錄:os.makedirs(r"c:\\python\\test")

7.創建單個目錄:os.mkdir("test")

8.刪除多個目錄:os.removedirs(r"c:\\python") #刪除所給路徑最後一個目錄下所有空目錄。

9.刪除單個目錄:os.rmdir("test")

10.獲取文件屬性:os.stat(file)

11.修改文件權限與時間戳:os.chmod(file)

12.執行操作系統命令:os.system("dir")

13.啟動新進程:os.exec(), os.execvp()

14.在後臺執行程序:osspawnv()

15.終止當前進程:os.exit(), os._exit()

16.分離文件名:os.path.split(r"c:\\python\\hello.py") --> ("c:\\\\python", "hello.py")

17.分離擴展名:os.path.splitext(r"c:\\python\\hello.py") --> ("c:\\\\python\\\\hello", ".py")

18.獲取路徑名:os.path.dirname(r"c:\\python\\hello.py") --> "c:\\\\python"

19.獲取文件名:os.path.basename(r"r:\\python\\hello.py") --> "hello.py"

20.判斷文件是否存在:os.path.exists(r"c:\\python\\hello.py") --> True

21.判斷是否是絕對路徑:os.path.isabs(r".\\python\") --> False

22.判斷是否是目錄:os.path.isdir(r"c:\\python") --> True

23.判斷是否是文件:os.path.isfile(r"c:\\python\\hello.py") --> True

24.判斷是否是鏈接文件:os.path.islink(r"c:\\python\\hello.py") --> False

25.獲取文件大小:os.path.getsize(filename)

26.*******:os.ismount("c:\\\") --> True

27.搜索目錄下的所有文件:os.path.walk()

28.文件的訪問時間 : os.path.getatime(myfile) # 這裡的時間以秒為單位,並且從1970年1月1日開始算起

29.文件的修改時間: os.path.getmtime(myfile)

[2.shutil]

1.複製單個文件:shultil.copy(oldfile, newfle)

2.複製整個目錄樹:shultil.copytree(r".\\setup", r".\\backup")

3.刪除整個目錄樹:shultil.rmtree(r".\\backup")

[3.tempfile]

1.創建一個唯一的臨時文件:tempfile.mktemp() --> filename

2.打開臨時文件:tempfile.TemporaryFile()

[4.StringIO] #cStringIO是StringIO模塊的快速實現模塊

1.創建內存文件並寫入初始數據:f = StringIO.StringIO("Hello world!")

2.讀入內存文件數據: print f.read() #或print f.getvalue() --> Hello world!

3.想內存文件寫入數據:f.write("Good day!")

4.關閉內存文件:f.close()

[5.glob]

1.匹配文件:glob.glob(r"c:\\python\\*.py")

5.文件操作(遍歷目錄和文件名)

import os

import os.path

rootdir = r"D:\\Holemar\\1.notes\\28.Python\\test"

# os.walk 返回一個三元組,其中parent表示所在目錄, dirnames是所有目錄名字的列表, filenames是所有文件名字的列表

for parent,dirnames,filenames in os.walk(rootdir):

# 所在目錄

print("parent is:" + parent)

# 遍歷此目錄下的所有目錄(不包含子目錄)

for dirname in dirnames:

print(" dirname is:" + dirname)

# 遍歷此目錄下的所有文件

for filename in filenames:

print(" filename with full path:" + os.path.join(parent, filename))

# 列表顯示出某目錄下的所有文件及目錄(不包括子目錄的內容)

ls = os.listdir(rootdir)

6.文件操作(分割路徑和文件名)

import os.path

#常用函數有三種:分隔路徑,找出文件名,找出盤符(window系統),找出文件的擴展名。

spath = "d:/test/test.7z"

# 下面三個分割都返回二元組

# 分隔目錄和文件名

p,f = os.path.split(spath) # 注意二元組的接收

print("dir is:" + p) # 打印: d:/test

print(" file is:" + f) # 打印: test.7z

# 分隔盤符和文件名

drv,left = os.path.splitdrive(spath)

print(" driver is:" + drv) # 打印: d:

print(" left is:" + left) # 打印: /test/test.7z

# 分隔文件和擴展名

f,ext = os.path.splitext(spath)

print(" f is: " + f) # 打印: d:/test/test

print(" ext is:" + ext) # 打印: 7z

7.儲存器

pickle標準模塊。它可以在一個文件中儲存任何Python對象,之後又可以把它完整無缺地取出來。這被稱為 持久地 儲存對象。

在pythony 3.0 已經移除了 cPickle 模塊,可以使用 pickle 模塊代替。

import pickle as p # 這裡使用 as 簡稱,方便更改模塊時只需改一行代碼

# import cPickle as p # Python 2.x 有這個模塊(比pickle快1000倍)

# 將會把資料保存在這個文件裡面

shoplistfile = 'shoplist.data'

# 需要保存的資料

shoplist = ['apple', 'mango', 'carrot', 2, 5]

# 寫入文件

f = open(shoplistfile, "wb") # 以二進制寫入,Python2.x時可不用二進制,但3.x必須

p.dump(shoplist, f) # dump the object to a file

f.close()

# 取出資料

f = open(shoplistfile, "rb") # 以二進制讀取

storedlist2 = p.load(f)

print(storedlist2)

f.close()

# 刪除文件

import os

os.remove(shoplistfile)

8.url編碼操作

import urllib,sys

s = '杭州'

print(urllib.quote(s)) # url 轉碼,打印如: %E6%9D%AD%E5%B7%9E

print(urllib.unquote('%E6%9D%AD%E5%B7%9E')) # url 解碼,打印如: 杭州

# 按所用的編碼來轉碼

print(urllib.quote(s.decode(sys.stdin.encoding).encode('utf8'))) # 打印如: %E6%9D%AD%E5%B7%9E

print(urllib.quote(s.decode(sys.stdin.encoding).encode('gbk'))) # 打印如: %BA%BC%D6%DD

print(urllib.quote(s.decode('gbk').encode('utf8'))) # 指定編碼來轉碼

print(urllib.quote(u'中國'.encode('utf8'))) # unicode編碼的,需encode一下;否則中文會出錯

# decode就是把其他編碼轉換為unicode,等同於unicode函數;encode就是把unicode編碼的字符串轉換為特定編碼。

# 一些不希望被編碼的url

print urllib.quote("http://localhost/index.html?id=1") # 打印: http%3A//localhost/index.html%3Fid%3D1

print urllib.quote("http://localhost/index.html?id=1",":?=/") # 打印: http://localhost/index.html?id=1

# 查看

print(u'中國'.__class__) # 打印: <type>

print('中國'.__class__) # 打印: <type>

9.數據庫連接

cx_Oracle : 是一個用來連接並操作 Oracle 數據庫的 Python 擴展模塊, 支持包括 Oracle 9.2 10.2 以及 11.1 等版本。

安裝:

需先oracle安裝客戶端,並配置環境變量:

ORACLE_HOME=D:\\Oracle\\Ora81

   PATH=D:\\Oracle\\Ora81\\bin;(其他path的地址)

下載 cx_Oracle 安裝包: http://www.python.net/crew/atuining/cx_Oracle/

Oracle 示例:

import cx_Oracle

print(cx_Oracle.version) # 打印出版本信息

# 建立連接, 3種不同寫法

conn = cx_Oracle.connect('username/pwssword@localhost:1521/db_name') # 參數連寫

conn = cx_Oracle.connect('username', 'pwssword', 'ip_address:1521/db_name') # 分開3個參數寫

dsn_tns = cx_Oracle.makedsn('localhost', 1521, 'db_name')

conn = cx_Oracle.connect('username', 'pwssword', dsn_tns) # 分開5個參數寫

MySQLdb : MySQL 數據庫的 Python 擴展模塊

import MySQLdb

下載地址(tar安裝包): http://sourceforge.net/projects/mysql-python

(exe安裝文件) http://www.lfd.uci.edu/~gohlke/pythonlibs/

mongodb:

下載數據庫安裝文件: http://www.mongodb.org/downloads

import pymongo

其他數據庫:

postgresql PostgreSQL psycopg version 1.x, http://initd.org/projects/psycopg1

postgresql_psycopg2 PostgreSQL psycopg version 2.x, http://initd.org/projects/psycopg2

sqlite3 SQLite No adapter needed if using Python 2.5+ Otherwise, pysqlite, http://initd.org/tracker/pysqlite

ado_mssql Microsoft SQL Server adodbapi version 2.0.1+, http://adodbapi.sourceforge.net/

MySQL 示例:

# 0. 導入模塊(如果導入出錯,說明安裝驅動不成功)

import MySQLdb

# 1. 數據庫聯結,默認host為本機, port為3306(各數據庫的連接寫法有所不同)

conn = MySQLdb.connect(host="localhost", port=3306, user="root", passwd="root", db="testdb")

# conn = MySQLdb.Connection(host="localhost", port=3306, user="root", passwd="root", db="testdb") # 與上句一樣

# 2. 選擇數據庫(如果前面還沒有選擇數據庫的話)

conn.select_db('database name')

# 3. 獲得cursor

cursor = conn.cursor()

# 4.1 執行SQL,查詢和增刪改都這樣寫; 查詢返回查詢結果的行數,增刪改返回影響的行數

cursor.execute("SELECT * FROM tb_member")

# 4.1.1. cursor位置設定及讀取結果(僅查詢時可這樣用)

# cursor.scroll(int, mode) # mode可為相對位置或者絕對位置,分別為relative和absolute。

cursor.scroll(0)

# 4.1.2. Fetch 及 獲取結果(每次Fetch,結果集都會下移,下次獲取的是剩下的結果集,除非再 cursor.scroll() 移動結果集)

print(cursor.fetchone()) # 獲取對應位置的資料,返回一個一維元組,打印如:(1L, 'stu1', 'm')

print(cursor.fetchall()) # 返回結果是個二維元組(所有結果) 打印如:((1L, 'stu1', 'm'), (2L, 'stu2', 'f'))

# 4.2 execute SQL, 返回影響的行數

rows = cursor.execute("delete from tb_member where memid=2")

print(rows) # 返回影響的行數(整數類型), 打印如:1

# 5. 關閉連接

cursor.close()

conn.close()

10.需注意的默認參數

# 默認參數: 如果調用的時候沒指定,那它會是函數定義時的引用;

# 因此,默認參數建議使用基本類型;如果不是基本類型,建議寫 None,然後在函數里面設默認值

##### 範例1,默認參數如果是 []、{} ,將會影響全局 ########

def t1(a, b = []):

b.append(a)

print('%s %s' % (id(b), b))

t1(1) # 打印: 12523400 [1]

t1(2) # 打印: 12523400 [1, 2]

t1(3, b=[]) # 打印: 12545000 [3]

def t2(a, b = {}):

b[len(b)] = a

print('%s %s' % (id(b), b))

t2(1) # 打印: 12540928 {0: 1}

t2(2) # 打印: 12540928 {0: 1, 1: 2}

t2(3, b={}) # 打印: 11547392 {0: 3}

##### 範例2,如果默認的是其它的函數調用,同樣原理,默認值只是函數定義時的引用,後面不再改變 ########

import time

def cc(a,b = time.time()):print('%s %s' % (a,b))

cc(1) # 打印: 1 1306501851.48

cc(1,b=2) # 打印: 1 2

cc(2) # 打印: 2 1306501851.48

##### 範例3,只是為了更好的理解上述所講 ########

def aa():

print('aa...')

return []

# 只在函數定義時,執行被調用的 aa(), 後面不再執行

def bb(a,b = aa()):

b.append(1)

print('%s %s' % (id(b), b))

bb(1) # 打印: 12542840 [1]

bb(2) # 打印: 12542840 [1, 1]

################################################

# 範例4, 為避免上面的出錯,正確的寫法是這樣的:

def t1(a, b = None):

b = b or []

b.append(a)

print('%s %s' % (id(b), b))

def t2(a, b = None):

b = b or {}

b[len(b)] = a

print('%s %s' % (id(b), b))

import time

def cc(a, b = None):

b = b or time.time()

print('%s %s' % (a,b))

11. 隨機數

from random import randint # 產生隨機整數

for i in xrange(100):

print( randint(10, 90) ) # 產生 10~90 的隨機整數

12. 條件參數列表

在實際開發中,我們會遇到如下一種需求:

1. 默認條件有 (a, b, c, d ...),總之很多。

2. 調用者可以傳遞 (b = False, c = False) 來提供 "非" 條件,其他默認為 True。

3. 或者傳遞 (b = True, c = True),其他默認為 False。

4. 還可以用 (all = True, ...) 來明確指定默認值。

def test(**on):

# 全部條件列表

accept_args = ("a", "b", "c", "d", "e")

# 默認條件

default = on.pop("all", None)

# 如果沒有顯式指明默認條件,則檢查參數列:

# 1. 如果有任何一個 True 條件則默認值為 False。

# 2. 如果全部為 False,則默認值為 True。

if default is None: default = not(True in on.values())

# 使用 setdefault 補全參數字典

for k in accept_args: on.setdefault(k, default)

return on

print test(b = False, e = False) # 顯示:{'a': True, 'c': True, 'b': False, 'e': False, 'd': True}

print test(c = True) # 顯示:{'a': False, 'c': True, 'b': False, 'e': False, 'd': False}

print test(a = True, e = False) # 顯示:{'a': True, 'c': False, 'b': False, 'e': False, 'd': False}

print test(all = True, c = False, e = True) # 顯示:{'a': True, 'c': False, 'b': True, 'e': True, 'd': True}

print test(all = True, c = False, e = False) # 顯示:{'a': True, 'c': False, 'b': True, 'e': False, 'd': True}

print test(all = False, c = True, e = True) # 顯示:{'a': False, 'c': True, 'b': False, 'e': True, 'd': False}

13. 斷點調試

import pdb; pdb.set_trace() # 運行到這語句,會出現斷點

輸入命令:

命令的詳細幫助: h

查看代碼上下文, l(小寫L)

監視變量: p 變量名

單步執行: n

加入斷點: b 行號

跳出斷點: c

執行到函數返回前: r

14. 修改註冊表(使用 _winreg, python3.x是 winreg 模塊, 內置模塊)

官方的參考文檔:

http://docs.python.org/library/_winreg.html

http://www.python.org/doc/2.6.2/library/_winreg.html

1. 讀取

讀取用的方法是OpenKey方法:打開特定的key

hkey = _winreg.OpenKey(key,sub_key,res=0,sam=KEY_READ)

_winreg.CloseKey(hkey) # 關閉之前打開的,如果不關閉則在對象被銷燬時關閉

例子:

import _winreg

key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, r"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\{0E184877-D910-4877-B 4C2-04F487B6DBB7}")

#獲取該鍵的所有鍵值,遍歷枚舉

try:

i=0

while 1:

# EnumValue方法用來枚舉鍵值,EnumKey用來枚舉子鍵

print _winreg.EnumValue(key,i) # 打印: (name,value,type)

i+=1

except WindowsError:

print

#假如知道鍵名,也可以直接取值

print _winreg.QueryValueEx(key,"ExplorerStartupTraceRecorded") # 打印: (value,type)

2. 創建 修改註冊表

創建key:_winreg.CreateKey(key,sub_key)

創建key:_winreg.CreateKeyEx(key, sub_key[, res[, sam]])

刪除key: _winreg.DeleteKey(key,sub_key)

刪除鍵值: _winreg.DeleteValue(key,value)

給新建的key賦值: _winreg.SetValue(key,sub_key,type,value)

例子:

import _winreg

key=_winreg.OpenKey(_winreg.HKEY_CURRENT_USER,r"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer")

# 刪除鍵(沒有時會報錯)

_winreg.DeleteKey(key, "Advanced")

# 刪除鍵值(沒有時會報錯)

_winreg.DeleteValue(key, "IconUnderline")

# 創建新的項

newKey = _winreg.CreateKey(key,"MyNewkey")

# 給新創建的項,添加鍵值(會多一個項:ValueName, 默認的值是ValueContent)

_winreg.SetValue(newKey,"ValueName", _winreg.REG_SZ, "ValueContent")

3. 訪問遠程註冊表

# 第二參數必須是HKEY_CURRENT_USER、HKEY_LOCAL_MACHINE等預先定義好的值,拿到返回的key後就可以進行操作了

key = _winreg.ConnectRegisty("IP地址或者機器名", _winreg.HKEY_CURRENT_USER)

實例: 修改IE代理服務器

import _winreg # python3 則寫 winreg

import ctypes

#proxy = "127.0.0.1:8000"

proxy = "http=127.0.0.1:8580;https=127.0.0.1:8580;ftp=127.0.0.1:8580" # 代理服務器地址

ProxyOverride = '<local>;192.168.*;127.*' # 不使用代理服務器的IP段,或者域名段,可以用*代表任意長字符串,如: 192.168.*/<local>

root = _winreg.HKEY_CURRENT_USER

proxy_path = r"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"

hKey = _winreg.OpenKey(root, proxy_path)

# value 是代理是否開啟的標誌,0表示不使用代理,1表示使用

value, type = _winreg.QueryValueEx(hKey, "ProxyEnable")

if value: # value 為 0 時

print("原本已使用代理")

else:

print("原本還沒使用代理")

# 修改代理設置

hKey = _winreg.CreateKey(root, proxy_path)

_winreg.SetValueEx(hKey, "ProxyEnable", 0, _winreg.REG_DWORD, 0) # 最後的參數是代理的開關,0為關閉代理,1為開啟

_winreg.SetValueEx(hKey, "ProxyServer", 0, _winreg.REG_SZ, proxy)

# 不使用代理服務器的IP段,或者域名段,可以用*代表任意長字符串

_winreg.SetValueEx(hKey, "ProxyOverride", 0, _winreg.REG_SZ, ProxyOverride)

_winreg.SetValueEx(hKey, "MigrateProxy", 0, _winreg.REG_DWORD, 1) # 是否所有協議使用相同代理服務器: 0為否,1為是

# 最後,關閉註冊表連接

_winreg.CloseKey(hKey)

# IE Reload註冊表的信息, 因為修改註冊表之後, ie不會馬上生效, 需要這一段; 但在win7系統似乎有點問題

INTERNET_OPTION_REFRESH = 37

INTERNET_OPTION_SETTINGS_CHANGED = 39

internet_set_option = ctypes.windll.Wininet.InternetSetOptionW

internet_set_option(0, INTERNET_OPTION_REFRESH, 0, 0)

internet_set_option(0, INTERNET_OPTION_SETTINGS_CHANGED, 0, 0)

14. 修改註冊表(使用 win32api, win32con 模塊,需安裝)

1. 下載和安裝模塊: http://starship.python.net/crew/mhammond/downloads/

下載像“pywin32-212.6.win32-py2.6.exe”來安裝

2. 註冊表基本項

項名 描述

HKEY_CLASSES_ROOT 是HKEY_LOCAL_MACHINE\\Software 的子項,保存打開文件所對應的應用程序信息

HKEY_CURRENT_USER 是HKEY_USERS的子項,保存當前用戶的配置信息

HKEY_LOCAL_MACHINE 保存計算機的配置信息,針對所有用戶

HKEY_USERS 保存計算機上的所有以活動方式加載的用戶配置文件

HKEY_CURRENT_CONFIG 保存計算機的硬件配置文件信息

3. 打開註冊表

win32api.RegOpenKey(key, subkey, reserved, sam)

win32api.RegOpenKeyEx(key, subkey, reserved, sam)

兩個函數的參數用法一樣。參數含義如下:

Key:必須為表1中列出的項。

SubKey:要打開的子項。

Reserved:必須為0。

Sam:對打開的子項進行的操作,包括 win32con.KEY_ALL_ACCESS、 win32con.KEY_READ、 win32con.KEY_WRITE 等

4. 關閉註冊表

win32api.RegCloseKey(key)

其參數只有一個,其含義如下:

Key:已經打開的註冊表項的句柄。

如:

key = win32api.RegOpenKey(win32con.HKEY_CURRENT_USER, 'Software', 0, win32con.KEY_READ)

print key # 顯示: <pyhkey>

win32api.RegCloseKey(key)

print key # 顯示: <pyhkey>

5. 讀取項值

win32api.RegQueryValue(key,subKey) # 讀取項的默認值;其參數含義如下:

Key:已打開的註冊表項的句柄。

subKey:要操作的子項。

win32api.RegQueryValueEx(key,valueName) # 讀取某一項值;其參數含義如下:

Key:已經打開的註冊表項的句柄。

valueName:要讀取的項值名稱。

win32api.RegQueryInfoKey(key) # RegQueryInfoKey函數查詢項的基本信息; 返回項的子項數目、項值數目,以及最後一次修改時間

python學習筆記比較全(下)


分享到:


相關文章: