Python讀書筆記:細節決定成敗(2)

一個獨行的程式設計師發表於2016-01-30

感謝一個@一個獨行的程式設計師的投遞   來自一個獨行的程式設計師

背景:我本來是一個信奉Java大法好的程式設計師。但是最近由於工作原因,不得不開始學習python。因此,寫下這個讀書筆記,希望能起到一個拋磚引玉的作用。原文中所有引用部分均來自python官方的tutorial

上接:Python讀書筆記:細節決定成敗(1)

8.input() vs raw_input()

他們的作用都是用來讀取命令列或者檔案中的資料,區別在於返回結果

  • input()返回的是numeric,如int,flat,double
  • raw_input()返回的是String

舉個例子:

>>> input()
12+2     #comand line input
14         #ouput
>>> raw_input()
12+2     #comand line input
'12+2'    #ouput

然而在讀過python的原始碼後,你會發現其實input()是通過raw_input來實現的:

def input(prompt):
    return (eval(raw_input(prompt)))

9.Output Formating

從C語言開始,格式化字串就已經為程式設計師所熟知,不管是C/C++還是Java,我覺得都沒有python在輸出格式化方面做的這麼簡練易用。舉兩個例子:

zfill()

pads a numeric string on the left with zeros. It understands about plus and minus signs:

這個函式的厲害之處在於它不僅能夠高位補零,而且可以識別正負號!

>>> '12'.zfill(5)
'00012'
>>> '-3.14'.zfill(7)
'-003.14'

str.format()

當有多個string需要輸出時,這個函式非常的powerful:

>>> print 'We are the {} who say "{}!"'.format('knights', 'Ni')
We are the knights who say "Ni!"

with position:

>>> print '{0} and {1}'.format('spam', 'eggs')
spam and eggs
>>> print '{1} and {0}'.format('spam', 'eggs')
eggs and spam

with keyword:

>>> print 'This {food} is {adjective}.'.format(
...       food='spam', adjective='absolutely horrible')
This spam is absolutely horrible.

combine position with keyword:

>>> print 'The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred',
...                                                    other='Georg')
The story of Bill, Manfred, and Georg.

對於需要遍歷輸出對應項的情況,python更是給出了一個不錯的解決方案—>:,再結合一下position和format,完美!

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
>>> for name, phone in table.items():
...     print '{0:10} ==> {1:10d}'.format(name, phone)
...
Jack       ==>       4098
Dcab       ==>       7678
Sjoerd     ==>       4127

10.Serializing and Deserializing

序列化(serializing)和反序列化(deserializing)是為了資料的易用性而出現的,在不同開發平臺和網際網路中,資料的表示方法一直都是處於百花齊放的局面。直到JSON的出現,才有了一個便於交換(interchange)的資料格式

  • 序列化: 將python中的資料結構以字串形式表示
  • 反序列化: 將上述的字串重建為python中的資料結構
  • JSON: JavaScript Object Notation

簡單來說,只需要記住兩個函式json.dumps()json.load()就可以了。他們的函式原型分別是:

json.dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, encoding="utf-8", default=None, sort_keys=False, **kw)

兩個函式的引數意義相同,可以自行閱讀tutorial瞭解詳情,這裡不展開了。

json.load(fp[, encoding[, cls[, object_hook[, parse_float[, parse_int[, parse_constant[, object_pairs_hook[, **kw]]]]]]]])

11.Class Objects

python是支援OOP的語言,因此接下來幾節介紹python中到的各種物件。

類是一個抽象的概念,類物件(class objects)支援兩種操作(operations):

  • 屬性引用(attribute references)
  • 例項化(instantiation)

與其它大多數OOP語言一樣,python的類也有變數和方法(method),不過卻又略有不同。python的變數(data attribute)是屬於類的,也即是說只要定義了類,那麼不需要例項化,就能夠直接訪問,類似於java中類的靜態變數(static variable).並且可以直接通過賦值(assign)去修改值。舉例:

>>> class Simple:
...     i = 1
...     def foo(self):
...             return "hello world"
... 
>>> Simple.i
1
>>> Simple.i = 2
>>> Simple.i
2

但是類的方法卻必須通過例項化後才能訪問,python中的例項化也有其獨特之處,例項物件(instance object)放在下節講。如果沒有例項化而直接去訪問類中定義的方法,會報unbound method,這是因為方法(method)是必須作用到一個實際的物件上的,而類物件本身是抽象的:

>>> Simple.foo
<unbound method Simple.foo>

至於為什麼類中的方法必須要自帶一個self引數,我後面再講,這也是python作為一個動態語言,與靜態的OOP之間最大的差異!

12.Instance Objects

例項物件(instance object)是一個具體的可操作的物件,其例項化的過程在python的官方解釋中是這麼說明的:

Class instantiation uses function notation. Just pretend that the class object is a parameterless function that returns a new instance of the class.

官方讓我們假設類物件是返回一個例項物件的無參函式,所以例項化的過程就像是得到一個函式的返回結果。(暈嗎?)個人感覺按照C++和Java的構造器(constructor)來理解,也不會出現太大問題。

>>> x = Simple()
>>> x.foo()
'hello world'

既然要例項化,必然躲不過一個詞“初始化”(initialization),python中定義了__init()__這個方法來初始化例項物件。舉個例子:

>>> class A:
...     i = 1
...     def __init__(self):
...             self.i = 3
... 
>>> 
>>> A.i
1    #class attribute
>>> x = A()
>>> x.i
3    #instance attribute
>>> A.i
1    #class attribute

前面我做了比喻,類的變數和Java中的靜態變數類似,但這裡可以看出它們的不同。在Java中靜態變數是屬於類的,被其所有例項共用。然而python的變數不是共用的,所以我才說python的類理解起來更抽象一點,類也是一個物件,不過和例項物件卻不同,更加抽象(暈嗎?)

之所以有這麼大的差異,主要原因是python是一個動態語言,它可以動態新增屬性,這就令很多一直用Java和C++的人不習慣。不過當你習慣之後,你會發覺它這種設計也真是好處多多。比如,你可以隨時給你的類增加新的變數啊~

>>> class A:
...     i = 1
... 
>>> A.j = 2
>>> A.j
2

13.Method Objects

在python中,方法(method)和函式(function)是不同的。方法應該特指在類中定義的,其特徵就是在定義時必須帶上一個引數self。這和其他語言隱式的處理this這個引數不同(兩者作用一樣)。python必須要顯示的指定這個方法作用的物件,這樣的好處是在呼叫時能夠確保方法是繫結(bound)在作用物件上的。因此,類是不能憑空呼叫方法的,必須作用在例項上才行,所以前面章節的例子裡會出現unbound method這個錯誤提示。舉個例子:

>>> class B:
...     def f(self):
...             return "Hello Method"
... 
>>> b = B()    #b is an instance object
>>> b.f()        
'Hello Method'he
>>> B.f(b)    #B is a class object 
'Hello Method'

當類B有了例項b之後,它也是可以呼叫方法f的,因為這一切都只是為了確保這個方法的作用物件是存在的!現在回過頭來看self,其實就是指類的例項本身作為引數傳進這個函式:

the special thing about methods is that the object is passed as the first argument of the function.

這樣也就好解釋為什麼函式本身定義時是可以不用顯示的寫self引數了,因為函式本身可以不屬於任何類。如果有學過pascal這類程式導向的語言,就很好理解這句話了。

>>> def f():        #Void, like a procedure in pascal
...     1 + 2
... 
>>> f()
>>> def ff():        #Return, like a function in pascal
...     return 1 + 2
... 
>>> ff()
3

相關文章