1. 程式人生 > >這是一篇python讀書筆記:13個案列乾貨十足,細節決定成敗

這是一篇python讀書筆記:13個案列乾貨十足,細節決定成敗

這是一篇python讀書筆記:13個案列乾貨十足,細節決定成敗

 

1.[a:b)

在使用list時,我們會常常使用左右區間的位置來賦值(range)或刪除(del)其中的值。一定記住這個區間是一個左閉右開的區間;

>>>a = range(1,6)

>>>a

[1,2,3,4,5]

>>>del a[1,3]

>>> a

[1,4,5]

實際刪除的是1,2號元素,所以剩下的是[1,4,5]

2.Lambda表示式

如果使用過filter/map/reduce這幾個函式,就會知道lambda表示式真的在匿名函式的寫法上非常省時省力,且便於閱讀。舉個例子:

>>> filter(lambda x : x % 2 == 0, range(10))
[0, 2, 4, 6, 8]
>>> map(lambda x, y : x * y, range(1,4), range(1,4))
[1, 4, 9]
>>> reduce(lambda x, y : x + y, range(101))

新增小編學習群813542856即可獲得10套PDF以及大量學習資料

lambda表示式的用法也很簡單,“:”前寫明引數,後面寫表示式(函式體),表示式的結果就是函式返回值,這一點和R語言很像。

3.Tuples

A tuple consists of a number of values separated by commas

元組(tuples)在資料處理方面非常的powerful,因為它可以包含任意型別的變數,且可以巢狀,各個元素間用逗號分隔。但是,請注意:Tuples are immutable!(這一點和String一樣),但是他們可以包含mutable的變數。

>>> t = 12345, 54321, 'hello!'
>>> t[0]
12345
>>> t
(12345, 54321, 'hello!')
>>> # Tuples may be nested:
... u = t, (1, 2, 3, 4, 5)
>>> u
((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))
>>> # Tuples are immutable:
... t[0] = 88888
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> # but they can contain mutable objects:
... v = ([1, 2, 3], [3, 2, 1])
>>> v
([1, 2, 3], [3, 2, 1])

u可以看作一個巢狀的tuple;v可以看做包含了2個list的tuple,而list是可以賦值的mutable變數;但是我們不能直接去修改tuple中元素的值,因為tuple本身是immutable的,搞清楚這一點很重要。

4.unpacking

unpacking應該和tuples結合起來看:如果將一個個變數裝進tuple中被稱作pack的話;那麼將tuple拆分成一個個獨立的變數就叫做unpack。

>>> t = 1, 2, ‘hello’

>>> t

(1, 2, ‘hello’)

>>> x, y, z = t

>>> x

1

>>> y

2

>>> z

‘hello’

值得注意的是:左邊的變數數量一定要與tuple中的元素數量一致!

Sequence unpacking requires the list of variables on the left to have the same number of elements as the length of the sequence.

5.Loop techniques

python對於迴圈的支援非常好,內建了很多有用的函式,這裡以enumerate(), zip(), reversed(), sorted(),iteritems()為例進行說明。

enumerate()

the position index and corresponding value can be retrieved at the same time using the enumerate() function.

可以在迴圈時同時取得下標位置和對應值

>>> for i, v in enumerate([‘tic’, ‘tac’, ‘toe’]):

… print i, v

0 tic

1 tac

2 toe

zip()

To loop over two or more sequences at the same time, the entries can be paired with the zip() function.

在迴圈中如果有兩個幾以上的佇列時,可以通過zip函式進行對應的匹配

>>> questions = [‘name’, ‘quest’, ‘favorite color’]

>>> answers = [‘lancelot’, ‘the holy grail’, ‘blue’]

>>> for q, a in zip(questions, answers):

… print ‘What is your {0}? It is {1}.’.format(q, a)

What is your name? It is lancelot.

What is your quest? It is the holy grail.

What is your favorite color? It is blue.

reversed()

To loop over a sequence in reverse, first specify the sequence in a forward direction and then call the reversed()function.

倒序輸出結果

>>> for i in reversed(xrange(1,10,2)):

… print i

9

7

5

3

1

sorted()

To loop over a sequence in sorted order, use the sorted() function which returns a new sorted list while leaving the source unaltered.

遍歷後返回一個有序佇列,並且不修改原佇列。

>>> basket = [‘apple’, ‘orange’, ‘apple’, ‘pear’, ‘orange’, ‘banana’]

>>> for f in sorted(set(basket)):

… print f

apple

banana

orange

pear

iteritems()

When looping through dictionaries, the key and corresponding value can be retrieved at the same time using the iteritems() method.

當遍歷dictionaries時,可以通過iteritems()來分別獲取key和value

>>> knights = {‘gallahad’: ‘the Pure’, ‘robin’: ‘the brave’}

>>> for k, v in knights.iteritems():

… print k, v

gallahad the pure

robin the brave

6.Modules

很多人在開發時往往會涉及第三方package和多個指令碼的情況,但是其實很多時候有些細節上的東西沒有弄明白往往會出現事倍功半的效果。剩下兩節就好好講清楚Modules和Packages的關係,不感興趣的可以跳過。

A module is a file containing Python definitions and statements. The file name is the module name with the suffix .py appended. Within a module, the module’s name (as a string) is available as the value of the global variable __name__.

module就是一個包含了一些定義(函式,類,變數,物件等)和語句的檔案,一般以”.py”作為字尾,編譯後的python檔案以”.pyc”作字尾。在module內,有一個全域性變數”__name__”,可以通過dir()函式來檢視當前環境中有哪些已定以的變數和函式。

以經典的fibonacci數列為例,假設下面這段程式碼是寫在”fibo.py”這個檔案中:

# Fibonacci numbers module

def fib(n): # write Fibonacci series up to n

a, b = 0, 1

while b < n:

print b,

a, b = b, a+b

def fib2(n): # return Fibonacci series up to n

result = []

a, b = 0, 1

while b < n:

result.append(b)

a, b = b, a+b

return result

現在如果我們想要在命令列或者終端中使用這個函式,我們可以import這個module:

>>> import fibo

>>> fibo.fib(1000)

1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987

>>> fibo.fib2(100)

[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

你還可以給這個一個簡單的別名,使程式碼更簡潔:

>>> fib = fibo.fib

>>> fib(500)

1 1 2 3 5 8 13 21 34 55 89 144 233 377

7.Packages

(1)Packages are a way of structuring Python’s module namespace by using “dotted module names”.

(2)A package is A collection of modules

簡單來說,package就是一個有結構的module的集合,以便於實現某些特定功能和用途,比較出名的packages有:NumPy, PIL(Python Imaging Library)等等。

它與modules最大的不同在於import時的細節,一定要注意語法!

假設我們有個叫做”sound”的package,它主要用來處理多種不同格式的音訊檔案,如:mp3,wmv,wma等。它的結構如下:

sound/ Top-level package
 __init__.py Initialize the sound package
 formats/ Subpackage for file format conversions
 __init__.py
 wavread.py
 wavwrite.py
 aiffread.py
 aiffwrite.py
 auread.py
 auwrite.py
 ...
 effects/ Subpackage for sound effects
 __init__.py
 echo.py
 surround.py
 reverse.py
 ...
 filters/ Subpackage for filters
 __init__.py
 equalizer.py
 vocoder.py
 karaoke.py
 ...

python官方不建議import整個package,因為它會降低程式碼的可讀性。

Note that in general the practice of importing * from a module or package is frowned upon, since it often causes poorly readable code.

因此,我們有必要學會如何科學正確的import我們需要的submodule或subpackage.假設我們只需要echo.py這個module,我們可以單獨import它:

>>>import sound.effects.echo

>>>#This loads the submodule sound.effects.echo. It must be referenced with its full name. 必須使用全名去呼叫echo中的函式

>>>sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)

>>>#An alternative way of importing the submodule is: 另一種import方法:

>>>from sound.effects import echo

>>>#This also loads the submodule echo, and makes it available without its package prefix, so it can be used as follows:通過from關鍵字,我們可以在呼叫時省去包名的字首

>>>echo.echofilter(input, output, delay=0.7, atten=4)

>>>#Yet another variation is to import the desired function or variable directly:如果你知道要呼叫什麼函式,甚至可以直接import這個函式

>>>from sound.effects.echo import echofilter

>>>#Again, this loads the submodule echo, but this makes its function echofilter() directly available:這樣的話,你就可以像呼叫本地函式一樣,省去所有字首

>>>echofilter(input, output, delay=0.7, atten=4)

通過三種import方法的對比,相信大家能夠根據自己的實際情況找到最適合自己的方法。

但是,這裡有一點語法上的細節,需要注意!

Note that when using from package import item, the item can be either a submodule (or subpackage) of the package, or some other name defined in the package, like a function, class or variable. The import statement first tests whether the item is defined in the package; if not, it assumes it is a module and attempts to load it. If it fails to find it, an ImportError exception is raised.

當使用from package import item這種語法結構時,item可以是一個submodule或subpackage,甚至是package中定義的一個函式,類和變數等物件;import會先假設item是一個物件,去測試其是否被定義;如果沒有找到,它會嘗試去載入,如果仍然沒有找到,那麼這時候會報ImportError

Contrarily, when using syntax like import item.subitem.subsubitem, each item except for the last must be a package; the last item can be a module or a package but can’t be a class or function or variable defined in the previous item.

相反,如果使用item.subitem.subsubitem這樣的語法結構時,除了最後一個item可以是module或者package以外,上級(字首)的所有item必須且只能是package,請謹記!

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