1,前言
前面的備忘錄提到了python的基本教程,基本上本文例子都是沈潔元的簡明教程裡面的內容,這兩篇都是讀書筆記,算不上派生,主要也是自己備忘用的,譯者見諒。
基本上本文的解釋是自己的理解,沒有採用書本中的講解,覺得自己解釋可能更容易記住。
上篇備忘主要是面向過程來講述的,其實python是凡事都是對象的一種解釋語言。包括類型int啊等等都是對象,與C/C++顯然不同,在這兩個語言中,類型是作為原子來定義的,主要是用來分配記憶體位元組而用,沒有所謂方法,當然這點在VC中做了一定改變,比如對字串的處理顯然是比C要方便一些。
python和perl,還是Python容易懂些,效率差了
2,物件導向的python
2.1,類建立一個新類型,而對象這個類的 執行個體。
2.2,對象可以使用普通的 屬於 對象的變數儲存資料。屬於一個對象或類的變數被稱為域。對象也可以使用 屬於 類的函數來具有功能。這樣的函數被稱為類的方法。域和方法可以合稱為類的屬性。
2.3,域有兩種類型——屬於每個執行個體/類的對象或屬於類本身。它們分別被稱為執行個體變數和類變數。類使用class關鍵字建立。類的域和方法被列在一個縮排塊中。
3,類
3.1,self參數
類的方法與普通的函數只有一個特別的區別——它們必須有一個額外的第一個參數名稱,但是在調用這個方法的時候你不為這個參數賦值,Python會提供這個值。這個特別的變數指對象本身,按照慣例它的名稱是self。
self 本身不需要賦值,由python自動完成功能,如果你的執行個體調用一個方法,例如:假如你有一個類稱為MyClass和這個類的一個執行個體MyObject。當你調用這個對象的方法MyObject.method(arg1, arg2)的時候,這會由Python自動轉為MyClass.method(MyObject, arg1, arg2)
3.2,建立一個類
我們看下面這個例子:
#!/usr/bin/python # Filename: simplestclass.py class Person: pass # An empty block p = Person() print p
如果你去掉pass前面的縮排,會提示錯誤,期待一個縮排,一定要記住python是由縮排來區別語句塊的,習慣C的人要留心。
結果列印的是這個執行個體的記憶體位址。
再者要注意的是:python中表示空語句必須寫個pass,而不是像C中括弧一括完事,因為python是用縮排來區別語句塊的。所以你不縮排,解譯器就不懂了。
3.3,對象的方法
對象方法與函數類似,只不過多了一個額外的self變數。
我們來看一個方法:
#!/usr/bin/python # Filename: method.py class Person: def sayHi(self): print 'Hello, how are you?' p = Person() p.sayHi()
# This short example can also be written as Person().sayHi()
要注意sayHi方法沒有任何參數。我個人覺得之所以需要一個self做方法預設參數可能是由於python是門解釋型語言,便於解譯器解釋。剛學這隻是種感覺,不對之處請指正。
3.4,一些特殊方法
這裡面其實涉及了一些並不陌生的概念
3.4.1 __init__方法
這個方法其實就是建構函式啊,大家懂了吧,而且上篇沒有提到,python是變數不需要事前聲明的,說實話看到下面這個例子,還是多少有點不適應
#!/usr/bin/python # Filename: class_init.py class Person: def __init__(self, name): self.name = name def sayHi(self): print 'Hello, my name is', self.name p = Person('Swaroop') p.sayHi() # This short example can also be written as Person('Swaroop').sayHi()
這裡面的屬性域沒有聲明啊,也不說什麼類型,在文法嚴格C++中顯的是相當糟糕。
建立一個類的新執行個體的時候,把參數包括在圓括弧內跟在類名後面,從而傳遞給__init__方法。
這個你要是習慣C++/Java之類的強制類型申明語言,看到這個self.name很不適應。還是把self參數當成系統需要的參數就好了。
下面這個例子可以解釋一下為什麼執行個體的屬性域可以不用聲明,對於python而已,建立執行個體適合,調用的__init__方法
#!/usr/bin/python# Filename: objvar.pyclass Person: '''Represents a person.''' population = 0 def __init__(self, name): '''Initializes the person's data.''' self.name = name print '(Initializing %s)' % self.name # When this person is created, he/she # adds to the population Person.population += 1 def __del__(self): '''I am dying.''' print '%s says bye.' % self.name Person.population -= 1 if Person.population == 0: print 'I am the last one.' else: print 'There are still %d people left.' % Person.population def sayHi(self): '''Greeting by the person. Really, that's all it does.''' print 'Hi, my name is %s.' % self.name def howMany(self): '''Prints the current population.''' if Person.population == 1: print 'I am the only person here.' else: print 'We have %d persons here.' % Person.populationswaroop = Person('Swaroop')swaroop.sayHi()swaroop.howMany()kalam = Person('Abdul Kalam')kalam.sayHi()kalam.howMany()swaroop.sayHi()swaroop.howMany()
觀察可以發現__init__方法用一個名字來初始化Person執行個體。在這個方法中,我們讓population增加1,這是因為我們增加了一個人。同樣可以發現,self.name的值根據每個對象指定,這表明了它作為對象的變數的本質。
運行上述指令碼,提示Exception AttributeError: "'NoneType' object has no attribute 'population'" in <bound method Person.__del__ of <__main__.Person instance at 0xb7746eec>> ignored;
原因是對象銷毀時,全域變數的問題。
我另寫了一篇備忘,記錄學習一下錯誤和心得,這裡先列出遇到的問題。記住一點,不要使用__def__方法。
你只能使用self變數來參考同一個對象的變數和方法。這被稱為 屬性參考 。
在這個程式中,我們還看到docstring對於類和方法同樣有用。我們可以在運行時使用Person.__doc__和Person.sayHi.__doc__來分別訪問類與方法的文檔字串。
就如同__init__方法一樣,還有一個特殊的方法__del__,它在對象消逝的時候被調用。對象消逝即對象不再被使用,它所佔用的記憶體將返回給系統作它用。在這個方法裡面,我們只是簡單地把Person.population減1。
當對象不再被使用時,__del__方法運行,但是很難保證這個方法究竟在 什麼時候 運行。
我們正常運行一次:
我們在這個指令碼裡面添加:
print Person.__doc__
print Person.sayHi.__doc__
我們看下運行結果:
b2c@b2c-server:~$ python demo.py
(Initializing Swaroop)
Hi, my name is Swaroop.
I am the only person here.
(Initializing Abdul Kalam)
Hi, my name is Abdul Kalam.
We have 2 persons here.
Hi, my name is Swaroop.
We have 2 persons here.
Represents a person.
Greeting by the person.
Really, that's all it does.
Abdul Kalam says bye.
There are still 1 people left.
Swaroop says bye.
I am the last one.
有沒有發現什嗎?可以看到我們的文檔字串或者說是解說文字不是最後顯示,而指令碼中其實是最後兩條語句,這個是因為__del__方法,指令碼執行最後,執行個體被銷毀,所以方法執行,出現提示。明白了沒。
所以這個__del__是解構函式,類似概念。
這裡面多說一句,python其實類中成員預設都是公開的,私人成員是後來語言加入的特性,以雙底線__作為標誌。如一個變數__var為私人變數,包括子類在內的外部調用都是無效的。python 是採用從新命名這個私人變數名字而避開外部調用的,非常簡單,所以會提示你找不到。
縮排要注意邏輯對齊!
3.5,繼承
物件導向的核心概念之一,為了代碼重用和邏輯相關性而定義。有過OOP基礎的都應該不陌生。
子類型執行個體可以自然的被當作父類型使用,支援多重繼承。
#!/usr/bin/python# Filename: inherit.pyclass SchoolMember: '''Represents any school member.''' def __init__(self, name, age): self.name = name self.age = age print '(Initialized SchoolMember: %s)' % self.name def tell(self): '''Tell my details.''' print 'Name:"%s" Age:"%s"' % (self.name, self.age),class Teacher(SchoolMember): '''Represents a teacher.''' def __init__(self, name, age, salary): SchoolMember.__init__(self, name, age) self.salary = salary print '(Initialized Teacher: %s)' % self.name def tell(self): SchoolMember.tell(self) print 'Salary: "%d"' % self.salaryclass Student(SchoolMember): '''Represents a student.''' def __init__(self, name, age, marks): SchoolMember.__init__(self, name, age) self.marks = marks print '(Initialized Student: %s)' % self.name def tell(self): SchoolMember.tell(self) print 'Marks: "%d"' % self.markst = Teacher('Mrs. Shrividya', 40, 30000)s = Student('Swaroop', 22, 75)print # prints a blank linemembers = [t, s]for member in members: member.tell() # works for both Teachers and Students
這個例子可以看出繼承的基本含義。另外說一點,子類建構函式必須人工構造父類的建構函式,不能自動完成,這點與其他OOP語言有點區別。
Python不會自動調用基本類的constructor,你得親自專門調用它。
4,I/O
4.1,檔案
你可以通過建立一個file類的對象來開啟一個檔案。
這個IO操作還是比較方便,能直接調用file()
#!/usr/bin/python# Filename: using_file.pypoem = '''\Programming is funWhen the work is doneif you wanna make your work also fun: use Perl!'''f = file('poem.txt', 'w') # open for 'w'ritingf.write(poem) # write text to filef.close() # close the filef = file('poem.txt')# if no mode is specified, 'r'ead mode is assumed by defaultwhile True: line = f.readline() if len(line) == 0: # Zero length indicates EOF break print line, # Notice comma to avoid automatic newline added by Pythonf.close() # close the file
我們通過指明我們希望開啟的檔案和模式來建立一個file類的執行個體。模式可以為讀模式('r')、寫入模式('w')或追加模式('a')。事實上還有多得多的模式可以使用,你可以使用help(file)來瞭解它們的詳情。
如果沒有指定模式,讀將作為預設模式。
在一個迴圈中,我們使用readline方法讀檔案的每一行。這個方法返回包括行末分行符號的一個完整行。所以,當一個 空的 字串被返回的時候,即表示檔案末已經到達了,於是我們停止迴圈。
這裡面有個小疑問就是while語句的true是根據上下文來判斷的嗎?我改成f也是可以的.
注意,因為從檔案讀到的內容已經以分行符號結尾,所以我們在print語句上使用逗號來消除自動換行。最後,我們用close關閉這個檔案。
4.2 儲存空間
Python提供一個標準的模組,稱為pickle。使用它你可以在一個檔案中儲存任何Python對象,之後你又可以把它完整無缺地取出來。這被稱為 持久地 儲存對象。
還有另一個模組稱為cPickle,它的功能和pickle模組完全相同,只不過它是用C語言編寫的,因此要快得多(比pickle快1000倍)。C就是牛逼啊。哈哈
#!/usr/bin/python# Filename: pickling.pyimport cPickle as p#import pickle as pshoplistfile = 'shoplist.data'# the name of the file where we will store the objectshoplist = ['apple', 'mango', 'carrot']# Write to the filef = file(shoplistfile, 'w')p.dump(shoplist, f) # dump the object to a filef.close()del shoplist # remove the shoplist# Read back from the storagef = file(shoplistfile)storedlist = p.load(f)print storedlist
首先,請注意我們使用了import..as文法。這是一種便利方法,以便於我們可以使用更短的模組名稱。在這個例子中,它還讓我們能夠通過簡單地改變一行就切換到另一個模組(cPickle或者pickle)!在程式的其餘部分的時候,我們簡單地把這個模組稱為p。
為了在檔案裡儲存一個對象,首先以寫入模式開啟一個file對象,然後調用儲存器模組的dump函數,把對象儲存到開啟的檔案中。這個過程稱為 儲存 。
接下來,我們使用pickle模組的load函數的返回來取回對象。這個過程稱為 取儲存 。
這個是涉及I/O操作用的
5,異常處理
應該說進階語言裡面都有異常處理的內容。
我們程式出現問題的適合,解譯器會告訴我們出錯了,有些時候對使用者顯示這些顯然是不友好的。所以,有點類似catch...throw,這裡面有try...except。
#!/usr/bin/python# Filename: try_except.pyimport systry: s = raw_input('Enter something --> ')except EOFError: print '\nWhy did you do an EOF on me?' sys.exit() # exit the programexcept: print '\nSome error/exception occurred.' # here, we are not exiting the programprint 'Done'
這個程式運行以後,按“Ctrl+C”或者“Ctrl+D”看看結果。。
5.2,自訂異常
可以自己定義異常來顯示。
你可以使用raise語句 引發 異常。你還得指明錯誤/異常的名稱和伴隨異常 觸發的 異常對象。你可以引發的錯誤或異常應該分別是一個Error或Exception類的直接或間接匯出類。
自己定義的異常類要是Exception類的子類。
這裡,我們建立了我們自己的異常類型,其實我們可以使用任何預定義的異常/錯誤。這個新的異常類型是ShortInputException類。它有兩個域——length是給定輸入的長度,atleast則是程式期望的最小長度。
在except從句中,我們提供了錯誤類和用來表示錯誤/異常對象的變數。這與函數調用中的形參和實參概念類似。在這個特別的except從句中,我們使用異常對象的length和atleast
#!/usr/bin/python# Filename: raising.pyclass ShortInputException(Exception): '''A user-defined exception class.''' def __init__(self, length, atleast): Exception.__init__(self) self.length = length self.atleast = atleasttry: s = raw_input('Enter something --> ') if len(s) < 3: raise ShortInputException(len(s), 3) # Other work can continue as usual hereexcept EOFError: print '\nWhy did you do an EOF on me?'except ShortInputException, x: print 'ShortInputException: The input was of length %d, \ was expecting at least %d' % (x.length, x.atleast)else: print 'No exception was raised.'
這裡,我們建立了我們自己的異常類型,其實我們可以使用任何預定義的異常/錯誤。這個新的異常類型是ShortInputException類。它有兩個域——length是給定輸入的長度,atleast則是程式期望的最小長度。
在except從句中,我們提供了錯誤類和用來表示錯誤/異常對象的變數。這與函數調用中的形參和實參概念類似。在這個特別的except從句中,我們使用異常對象的length和atleast域來為使用者列印一個恰當的訊息.
5.3,try..finally
單詞意思可知,finally是無論異常發生與否都要完成的動作。
#!/usr/bin/python# Filename: finally.pyimport timetry: f = file('poem.txt') while True: # our usual file-reading idiom line = f.readline() if len(line) == 0: break time.sleep(2) print line,finally: f.close() print 'Cleaning up...closed the file'
睡了2秒,是故意延長時間,好讓你按“Ctrl+C”,按了你也發現,檔案還是關閉了最後。
6,python標準庫
6.1,sys模組
顧名思義,系統庫。
#!/usr/bin/python# Filename: cat.pyimport sysdef readfile(filename): '''Print a file to the standard output.''' f = file(filename) while True: line = f.readline() if len(line) == 0: break print line, # notice comma f.close()# Script starts from hereif len(sys.argv) < 2: print 'No action specified.' sys.exit()if sys.argv[1].startswith('--'): option = sys.argv[1][2:] # fetch sys.argv[1] but without the first two characters if option == 'version': print 'Version 1.2' elif option == 'help': print '''\This program prints files to the standard output.Any number of files can be specified.Options include: --version : Prints the version number --help : Display this help''' else: print 'Unknown option.' sys.exit()else: for filename in sys.argv[1:]: readfile(filename)
這裡面說明一下:argv自動將指令檔名認為是argv[0],從0開始計數,與C語言一樣,如果出現argv[1][2:]則是第二個參數,使用者角度是第一個參數拋棄前兩個字元,截取剩餘字元的意思。
至於argv[1:]則應該是從使用者角度的第一個參數依次到參數列表的最後。
readfile()函數輸出檔案內容,首先判斷參數數量,少於2個顯然是沒有輸入檔案名稱,給出提示反饋,如果參數是以--開頭的則拋棄前兩個字元,截取剩下字元通過流程匹配分別輸出提示。最後,把參數列表中的檔案一個個輸出就是了
這裡面有三個模組比較常用先記下:sys.stdin、sys.stdout和sys.stderr它們分別對應你的程式的標準輸入、標準輸出和標準錯誤流。
6.2,OS模組
這個模組包含普遍的作業系統功能。如果你希望你的程式能夠與平台無關的話,這個模組是尤為重要的。即它允許一個程式在編寫後不需要任何改動,也不會發生任何問題,就可以在Linux和Windows下運行。一個例子就是使用os.sep可以取代作業系統特定的路徑分割符。
這個對於我那是相當重要了,畢竟現在用LINUX案頭的人簡直是鳳毛麟角啊。
os模組裡面有很多方法很有用,平時可以查看一下文檔。
os.name字串指示你正在使用的平台.os.getcwd()函數得到當前工作目錄。os.linesep字串給出當前平台使用的行終止符。os.path.isfile()和os.path.isdir()函數分別檢驗給出的路徑是一個檔案還是目錄。類似地,os.path.existe()函數用來檢驗給出的路徑是否真地存在。
基本上python基本東西都在這裡麼了,當然講的也是皮毛,在以後真正開發中我會不斷新增內容和學習備忘的。