[Pycharm] Symbol Review

From: http://learnpythonthehardway.org/book/ex37.htmlhtml

 

1. with X as Y: passpython

1.1 yield express

2. exec編程

2.1 namespaceapp

3. lambdaide

3.1 map函數式編程

3.2 map and reduce函數

4. raise工具

  


KEYWORD DESCRIPTION EXAMPLE
and Logical and. True and False == False
as (1) Part of the with-as statement. with X as Y: pass
assert Assert (ensure) that something is true. assert False, "Error!"
break Stop this loop right now. while True: break
class Define a class. class Person(object)
continue Don't process more of the loop, do it again. while True: continue
def Define a function. def X(): pass
del Delete from dictionary. del X[Y]
elif Else if condition. if: X; elif: Y; else: J
else Else condition. if: X; elif: Y; else: J
except If an exception happens, do this. except ValueError, e: print e
exec (2) Run a string as Python. exec 'print "hello"'
finally Exceptions or not, finally do this no matter what. finally: pass
for Loop over a collection of things. for X in Y: pass
from Importing specific parts of a module. from x import Y
global Declare that you want a global variable. global X
if If condition. if: X; elif: Y; else: J
import Import a module into this one to use. import os
in Part of for-loops. Also a test of X in Y. for X in Y: pass also 1 in [1] == True
is Like == to test equality. 1 is 1 == True
lambda (3) Create a short anonymous function. s = lambda y: y ** y; s(3)
not Logical not. not True == False
or Logical or. True or False == True
pass
This block is empty. def empty(): pass
print Print this string. print 'this string'
raise (4) Raise an exception when things go wrong. raise ValueError("No")
return Exit the function with a return value. def X(): return Y
try Try this block, and if exception, go to except. try: pass
while While loop. while X: pass
with With an expression as a variable do. with X as Y: pass
yield (1.1) Pause here and return to caller. def X(): yield Y; X().next()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

 

 

 

 

 

 

 

 


1. with-as statement(也稱context manager)


From: http://zhoutall.com/archives/325oop

 

(1) 常見寫法,但比較囉嗦

try:
    f = open('xxx')
except:
    print 'fail to open'
    exit(-1)
try:
    do something
except:
    do something
finally:
    f.close()

 

(2) 使用封裝如何?不用反覆寫finally,但致使:全部的函數都要被 controlled_execution( ) 下,太累贅。

def controlled_execution(callback):
    set things up
    try:
        callback(thing)
    finally:
        tear things down
 
def my_function(thing):
    do something
 
controlled_execution(my_function)

 

(3) 另外一個辦法是使用生成器,可是隻須要生成一次數據,咱們用for-in結構去調用他:

def controlled_execution():  //由於thing只有一個,因此yield語句只須要執行一次,從代碼可讀性也就是優雅的角度來講這簡直是糟糕透了
    set things up
    try:
        yield thing  //--> see "yield" finally:
        tear things down
         
for thing in controlled_execution():
    do something with thing

 

(4) with-as新方案

class controlled_execution:
    def __enter__(self):
        set things up
        return thing
    def __exit__(self, type, value, traceback):
        tear things down
         
with controlled_execution() as thing:
        do something

當python執行這一句時,會調用__enter__函數,而後把該函數return的值傳給as後指定的變量。以後,python會執行下面do something的語句塊。最後不論在該語句塊出現了什麼異常,都會在離開時執行__exit__。

另外,__exit__除了用於tear things down,還能夠進行異常的監控和處理,注意後幾個參數。要跳過一個異常,只須要返回該函數True便可。

 

在python2.5及之後,file對象已經寫好了__enter____exit__函數,咱們能夠這樣測試:

>>> f = open("x.txt")
>>> f
<open file 'x.txt', mode 'r' at 0x00AE82F0>
>>> f.__enter__()
<open file 'x.txt', mode 'r' at 0x00AE82F0>
>>> f.read(1)
'X'
>>> f.__exit__(None, None, None)
>>> f.read(1)
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>

 

以後,咱們若是要打開文件並保證最後關閉他,只須要這麼作:

with open("x.txt") as f:
    data = f.read()
    do something with data

 

若是有多個項,咱們能夠這麼寫:

with open("x.txt") as f1, open('xxx.txt') as f2:
    do something with f1,f2

 

上文說了__exit__函數能夠進行部分異常的處理,若是咱們不在這個函數中處理異常,他會正常拋出,這時候咱們能夠這樣寫(python 2.7及以上版本,以前的版本參考使用contextlib.nested這個庫函數):

try:
    with open( "a.txt" ) as f :
        do something
except xxxError:
    do something about exception

 

總之,with-as表達式極大的簡化了每次寫finally的工做,這對保持代碼的優雅性是有極大幫助的。

 

 


1.1 yield


 From: http://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/

  
清單 1. 簡單輸出斐波那契數列前 N 個數
 def fab(max): 
    n, a, b = 0, 0, 1 
    while n < max: 
        print b         // 不太好! 其實改成yield就行了。
        a, b = b, a + b 
        n = n + 1

執行 fab(5),咱們能夠獲得以下輸出:

 >>> fab(5) 
 1 
 1 
 2 
 3 
 5

結果沒有問題,但有經驗的開發者會指出,直接在 fab 函數中用 print 打印數字會致使該函數可複用性較差,由於 fab 函數返回 None,其餘函數沒法得到該函數生成的數列。

要提升 fab 函數的可複用性,最好不要直接打印出數列,而是返回一個 List。

 

如下是 fab 函數改寫後的第二個版本:

清單 2. 輸出斐波那契數列前 N 個數第二版
 def fab(max): 
    n, a, b = 0, 0, 1 
    L = [] 
    while n < max: 
        L.append(b) 
        a, b = b, a + b 
        n = n + 1 
    return L       // 暫用內存太大!

可使用以下方式打印出 fab 函數返回的 List:

 >>> for n in fab(5): 
 ...     print n 
 ... 
 1 
 1 
 2 
 3 
 5

改寫後的 fab 函數經過返回 List 能知足複用性的要求,可是更有經驗的開發者會指出,該函數在運行中佔用的內存會隨着參數 max 的增大而增大。

 

若是要控制內存佔用,最好不要用 List來保存中間結果,而是經過 iterable 對象來迭代。例如,在 Python2.x 中,代碼:

清單 3. 經過 iterable 對象來迭代
for i in range(1000): pass  //會致使生成一個 1000 個元素的 List

for i in xrange(1000): pass // iterable對象是解決的辦法!

在每次迭代中返回下一個數值,內存空間佔用很小。由於 xrange 不返回 List,而是返回一個 iterable 對象。

 

利用 iterable 咱們能夠把 fab 函數改寫爲一個支持 iterable 的 class,如下是第三個版本的 Fab:

清單 4. 第三個版本
 class Fab(object): 

    def __init__(self, max): 
        self.max = max 
        self.n, self.a, self.b = 0, 0, 1 

    def __iter__(self): 
        return self 

    def next(self): 
        if self.n < self.max: 
            r = self.b 
            self.a, self.b = self.b, self.a + self.b 
            self.n = self.n + 1 
            return r 
        raise StopIteration()

Fab 類經過 next() 不斷返回數列的下一個數,內存佔用始終爲常數:

 >>> for n in Fab(5): 
 ...     print n 
 ... 
 1 
 1 
 2 
 3 
 5

然而,使用 class 改寫的這個版本,代碼遠遠沒有初版的 fab 函數來得簡潔。

 

若是咱們想要保持初版 fab 函數的簡潔性,同時又要得到 iterable 的效果,yield 就派上用場了:

清單 5. 使用 yield 的第四版
 def fab(max): 
    n, a, b = 0, 0, 1 
    while n < max: 
        yield b 
        # print b 
        a, b = b, a + b 
        n = n + 1 

第四個版本的 fab 和初版相比,僅僅把 print b 改成了 yield b,就在保持簡潔性的同時得到了 iterable 的效果。

調用第四版的 fab 和第二版的 fab 徹底一致:

 >>> for n in fab(5):   // for執行一次函數,其實只是調用了函數內的一次運算;再調一次就再繼續算一次!
 ...     print n 
 ... 
 1 
 1 
 2 
 3 
 5
 

也能夠手動調用 fab(5) 的 next() 方法(由於 fab(5) 是一個 generator 對象,該對象具備 next() 方法),這樣咱們就能夠更清楚地看到 fab 的執行流程:

清單 6. 執行流程
 >>> f = fab(5)  // fab(5) 是iterable function,這裏就是指的fab的實例
 >>> f.next()    // 與清單4 中的next比較下,實際上是相同的思想
 1 
 >>> f.next() 
 1 
 >>> f.next() 
 2 
 >>> f.next() 
 3 
 >>> f.next() 
 5 
 >>> f.next() 
 Traceback (most recent call last): 
  File "<stdin>", line 1, in <module> 
 StopIteration

當函數執行結束時,generator 自動拋出 StopIteration 異常,表示迭代完成。在 for 循環裏,無需處理 StopIteration 異常,循環會正常結束。

 

 

 

 


2. exec


 From: http://blog.sina.com.cn/s/blog_76e94d210100w1bl.html

 

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

例如,咱們能夠在運行時生成一個包含Python代碼的字符串,而後使用exec語句執行這些語句。

下面是一個簡單的例子。

>>> exec 'print "Hello World"'
Hello World

 

eval語句用來計算存儲在字符串中的有效Python表達式。下面是一個簡單的例子。

>>> eval_r('2*3')
6

eval_r(str [ globals [ locals ]])函數將字符串str當成有效python表達式來求值,並返回計算結果。

一樣地, exec語句將字符串str當成有效Python代碼來執。.提供給exec的代碼的名稱空間和exec語句的名稱空間相同。

最後,execfile(filename [, globals [, locals ]]) 函數能夠用來執行一個文件。

 
  
>>> eval_r('3+4')
7
>>> exec 'a=100' 
>>> a 
100 
>>> execfile(r'd:\code\ex\test.py')
hello world!
>>>
 
  

默認的,eval_r(), exec, execfile() 所運行的代碼都位於當前的名字空間中.

eval_r(), exec 和 execfile()函數 也能夠接受一個或兩個可選字典參數做爲代碼執行的全局名字空間局部名字空間。

 

 

 

 


2.1 Python命名空間和做用域


From: http://blog.cipherc.com/2015/04/25/python_namespace_and_scope/#assignment-rule

 

Namespace(只)是 從名字到對象的一個映射 (a mapping from name to objects) 

大部分namespace都是按Python中的字典來實現的。

 

有一些常見的namespace:built-in中的集合( abs() 函數等)、一個模塊中的全局變量等。

從某種意義上來講,一個對象(object)的全部屬性(attribute)也構成了一個namespace.

 

在程序執行期間,可能(實際上是確定)會有多個名空間同時存在。不一樣namespace的建立/銷燬時間也不一樣。此外,兩個不一樣namespace中的兩個相同名字的變量之間沒有任何聯繫。

 

scope

Scope是Python程序的一塊文本區域(textual region)

在該文本區域中,對namespace是能夠直接訪問,而不須要經過屬性來訪問。

Scope是定義程序該如何搜索確切地「名字-對象」的名空間的層級關係。(The 「scope」 in Python defines the 「hirerchy level」 in which we search namespaces for certain 「name-to-object」 mappings.)

直接訪問:對一個變量名的引用會在全部namespace中查找該變量,而不是經過屬性訪問。

屬性訪問:全部名字後加.的都認爲是屬性訪問。如 module_name.func_name,須要指定 func_name 的名空間,屬於屬性訪問;而 abs(-1),abs 屬於直接訪問。

  

scope 與 namespace的關係

在Python中,scope是由namespace按特定的層級結構組合起來的。

scope必定是namespace,但namespace不必定是scope。 // 感受namespace範圍更大?

 

LEGB-rule

在一個Python程序運行中,至少有4個scopes是存在的

直接訪問一個變量可能在這四個namespace中逐一搜索。

  • Local (innermost) 

    包含局部變量。
    好比一個函數/方法內部。

  • Enclosing

    包含了非局部(non-local)也非全局(non-global)的變量。
    好比兩個嵌套函數,內層函數可能搜索外層函數的namespace,但該namespace對內層函數而言既非局部也非全局。

  • Global (next-to-last)

    當前腳本的最外層。
    好比當前模塊的全局變量。

  • Built-in (outtermost)

    Python __builtin__ 模塊。
    包含了內建的變量/關鍵字等。

     

* 那麼,這麼多的做用域,Python是按什麼順序搜索對應做用域的呢?

* 著名的」LEGB-rule」,即scope的搜索順序:

Local -> Enclosing -> Global -> Built-in

 

當有一個變量在 local 域中找不到時,Python會找上一層的做用域,即 enclosing 域(該域不必定存在)。
enclosing 域還找不到的時候,再往上一層,搜索模塊內的 global 域。最後,會在 built-in 域中搜索。
對於最終沒有搜索到時,Python會拋出一個 NameError 異常。

做用域能夠嵌套。好比模塊導入時。

這也是爲何不推薦使用 from a_module import * 的緣由,導入的變量可能被當前模塊覆蓋。

 

兩條很重要的規則:

  1. 賦值語句一般隱式地會建立一個局部(local)變量,即使該變量名已存在於賦值語句發生的上一層做用域中;
  2. 若是沒有global關鍵字聲明變量,對一個變量的賦值老是認爲該變量存在於最內層(innermost)的做用域中;

也就是說在做用域內有沒有發生賦值是不同的。

 

可是,在這點上,Python 2和Python 3又有不一樣, Python access non-local variable:

Python’s scoping rules indicate that a function defines a new scope level,
and a name is bound to a value in only one scope level – it is statically scoped.

…

In Python 2.x, it is not possible to modify a non-local variable;
1) you have either read-only access to a global or non-local variable,
2) or read-write access to a global variable by using the global statement,
3) or read-write access to a local variable (by default).

In Python 3.x, the nonlocal statement has been introduced with a similar effect
to global, but for an intermediate scope.
View Code

 

 

循環中的大坑

CipherChen@CIPHERC ~/Development/Workspace/test_python $ python2
Python 2.7.9 (default, Jan 25 2015, 13:42:57)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.56)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> for i in range(10): print i
...
0
1
2
3
4
5
6
7
8
9
>>> print i
9                <---- 大坑
>>>

for 後面跟着的變量(target list)在循環結束後是不會被刪除的,
但若是 for 循環的序列爲空,這些變量是徹底不會被賦值的。

這在Python中是個大坑啊。

避免這個坑的解決辦法就是規範命名規範。
好比用於循環的變量儘可能使用單字符。在任何有疑議的狀況能夠直接將索引值初始化。

很不幸,Python 3中這點沒有改變。

 

 

是否 引入新的做用域

class A(object):
    a = 3
    b = list(a + i for i in range(10))

cipher@Rachel ~/Development/Workspace/test_Python $ python a.py
Traceback (most recent call last): File "a.py", line 3, in <module> class A(object): File "a.py", line 5, in A b = list(a + i for i in range(10)) File "a.py", line 5, in <genexpr> b = list(a + i for i in range(10)) NameError: global name 'a' is not defined

class沒有做用域(scope),但有一個局部的名空間(namespace),它並不構成一個做用域。
---- 這意味着在類定義中的表達式能夠訪問該名空間。

但在類體(class body)中, 對 b 的賦值表達式中,該表達式引入了一個新的做用域該做用域並不能訪問類的名空間

就像剛剛說的,函數會引入一個新的做用域(以前定義的a失效了),因此報錯!

class C(object):
    a = 2
    def foo(self):
        return a    # NameError: name 'a' is not defined, use return self.__class__.a

 

未引入新的做用域的例子,因此能夠執行 print a

Python 2.7.9 (default, Jan 25 2015, 13:42:57)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.56)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> [a for a in range(3)]
[0, 1, 2]  
>>> print a   //未引入新的做用域 就能夠直接讀出持續的值 2

 

要解決這個問題(哪一個問題?),有幾種解決辦法:

1. 用生成器表達式

b = [a + i for i in range(10)]

 

2. 用函數/lambda引入新的做用域

b = (lambda a: ((a + i for i in range(10))))(a)

 

 

訪問權限表 (難點

Can access class attributes Python 2 Python 3
list comp. iterable Y Y
list comp. expression Y N
gen expr. iterable Y Y
gen expr. expression N N
dict comp. iterable Y Y
dict comp. expression N N
 
 
 

3. lambda


 
簡單來講,編程中提到的 lambda 表達式,一般是在 須要一個函數,可是又不想費神去命名一個函數的場合下使用,也就是指 匿名函數
舉一個普通的 Python 例子:將一個 list 裏的每一個元素都平方:
map( lambda x: x*x, [y for y in range(10)] )
這個寫法要好過
def sq(x):
    return x * x

map(sq, [y for y in range(10)])
由於後者多定義了一個(污染環境的)函數, 尤爲若是這個函數只會使用一次的話
並且第一種寫法實際上更易讀,由於那個映射到列表上的函數具體是要作什麼,很是一目瞭然。若是你仔細觀察本身的代碼,會發現這種場景其實很常見:你在某處就真的只須要一個能作一件事情的函數而已,連它叫什麼名字都可有可無。Lambda 表達式就能夠用來作這件事。

進一步講,匿名函數本質上就是一個函數,它所抽象出來的東西是一組運算。這是什麼意思呢?類比
a = [1, 2, 3]
f = lambda x : x + 1
你會發現, 等號右邊的東西 徹底能夠脫離 等號左邊的東西而存在,等號左邊的 名字只是右邊之 實體的標識符。
若是你能習慣 [1, 2, 3] 單獨存在,那麼 lambda x : x + 1 也能單獨存在其實也就不難理解了,它的意義就是給「某個數加一」這一運算自己。

如今回頭來看 map() 函數,它能夠將一個函數映射到一個可枚舉類型上面。沿用上面給出的 a 和 f,能夠寫:
map(f, a)
也就是將函數 f 依次套用在 a 的每個元素上面,得到結果 [2, 3, 4]。如今用 lambda 表達式來替換 f,就變成:
map( lambda x : x + 1, [1, 2, 3] )
若是能將「遍歷列表,給遇到的每一個元素都作某種 運算」的過程從一個循環裏抽象出來成爲一個函數 map,而後用 lambda 表達式將這種 運算做爲參數傳給 map 的話,考慮事情的思惟層級會高出一些來,須要顧及的細節也少了一點。
Python 之中,相似能用到 lambda 表達式的「高級」函數還有 reduce、filter 等等,不少語言也都有這樣的工具(不過這些特性最好不要在 Python 中用太多,緣由詳見 的評論部分)。
這種可以接受一個函數做爲參數的函數叫作「高階函數」(higher-order function),是來自函數式編程(functional programming)的思想。

和其餘不少語言相比,Python 的 lambda 限制多多,最嚴重的當屬它只能由一條表達式組成。這個限制主要是爲了防止濫用,由於當人們發覺 lambda 很方便,就比較容易濫用,但是用多了會讓程序看起來不那麼清晰,畢竟每一個人 對於抽象層級的忍耐 / 理解程度都有所不一樣。
 
 

 

lambda的主體是一個表達式,而不是一個代碼塊。僅僅能在lambda表達式中封裝有限的邏輯進去。

lambda表達式是起到一個函數速寫的做用。容許在代碼內嵌入一個函數的定義。

以下例子:定義了一個lambda表達式,求三個數的和。

一種表達式,能夠帶參數的表達式,參數即給最外層的lambda的賦值,而後return表達式的計算結果。

  

  • lambda表達式也能夠用在def函數中。

看例子:

這裏定義了一個action函數,返回了一個lambda表達式。其中lambda表達式獲取到了上層def做用域的變量名x的值。

a是action函數的返回值,a(22),便是調用了action返回的lambda表達式。

 

  • 這裏也能夠把def直接寫成lambda形式。以下

 

 
lambdarange/list 的結合, 如何理解邏輯
 
 一個例子:用lambda表達式求n的階乘。

 
 
 
 

3.1 map


 
map函數會根據提供的函數對指定序列作映射。
map函數的定義:
map(function, sequence[, sequence, ...]) -> list
經過定義能夠看到,這個函數的第一個參數是一個函數,剩下的參數是一個或多個序列,返回值是一個集合。
function能夠理解爲是一個一對一或多對一函數,map的做用是以參數序列中的每個元素調用function函數,返回包含每次function函數返回值的list。
好比要對一個序列中的每一個元素進行平方運算:
map(lambda x: x ** 2, [1, 2, 3, 4, 5])

返回結果爲:
[1, 4, 9, 16, 25]
在參數存在多個序列時,會依次以每一個序列中相同位置的元素作參數調用function函數。
好比要對兩個序列中的元素依次求和。
map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])

map返回的list中第一個元素爲,參數序列1的第一個元素加參數序列2中的第一個元素(1 + 2),
list中的第二個元素爲,參數序列1中的第二個元素加參數序列2中的第二個元素(3 + 4),
依次類推,最後的返回結果爲:
[3, 7, 11, 15, 19]
要注意function函數的 參數數量,要和map中提供的 集合數量相匹配。
 
若是集合長度不相等,會以最小長度對全部集合進行截取。
當函數爲None時,操做和zip類似:
map(None, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])

返回結果爲:
[(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]
 
 
 

3.2 map and reduce


 

提起map和reduce想必你們並不陌生,Google公司2003年提出了一個名爲MapReduce的編程模型[1],用於處理大規模海量數據,並在以後普遍的應用於Google的各項應用中,2006年Apache的Hadoop項目[2]正式將MapReduce歸入到項目中。

好吧,閒話少說,今天要介紹的是Python函數式編程中的另外兩個內建函數 map()reduce(),而不是Google的MapReduce。

 

1.map()

格式:map( func, seq1[, seq2...] )

Python函數式編程中的map()函數是將func做用於seq中的每個元素,並用一個列表給出返回值。若是func爲None,做用同zip()// 同3.1

當seq只有一個時,將func函數做用於這個seq的每一個元素上,獲得一個新的seq。

下圖說明了只有一個seq的時候map()函數是如何工做的(本文圖片來源:《Core Python Programming (2nd edition)》)。

map-一個seq

能夠看出,seq中的每一個元素都通過了func函數的做用,獲得了func(seq[n])組成的列表。

 

下面舉一個例子進行說明。假設咱們想要獲得一個列表中數字%3的餘數,那麼能夠寫成下面的代碼。 
# 使用map
print map( lambda x: x%3, range(6) )  # [0, 1, 2, 3, 4, 5] --> [0, 1, 2, 0, 1, 2]
 
#使用列表解析
print [x%3 for x in range(6)]         # [0, 1, 2, 0, 1, 2] 多於一個range,就沒辦法搞了

這裏又和上次的filter()同樣,使用了列表解析的方法代替map執行。那麼,何時是列表解析沒法代替map的呢

原來,當seq多於一個時,map能夠並行地對每一個seq執行以下圖所示的過程:

map-多個seq

也就是說每一個seq的同一位置的元素在執行過一個多元的func函數以後,獲得一個返回值,這些返回值放在一個結果列表中。

下面的例子是求兩個列表對應元素的積,能夠想象,這是一種可能會常常出現的情況,而若是不是用map的話,就要使用一個for循環,依次對每一個位置執行該函數。

print map( lambda x, y: x*y, [1, 2, 3], [4, 5, 6] )  # [4, 10, 18]

 

也能夠是一個元組。下面的代碼不止實現了乘法,也實現了加法,並把積與和放在一個元組中。

還有就是上面說的func是None的狀況,它的目的是將多個列表相同位置的元素歸併到一個元組,在如今已經有了專用的函數zip()了。

print map( None, [1, 2, 3], [4, 5, 6] )  # [(1, 4), (2, 5), (3, 6)]
print zip( [1, 2, 3], [4, 5, 6] )        # [(1, 4), (2, 5), (3, 6)]

須要注意的是,不一樣長度的多個seq是沒法執行map函數的,會出現類型錯誤。

 

2.reduce()

格式:reduce( func, seq[, init] )

reduce函數即爲化簡,它是這樣一個過程:

"每次迭代,將上一次的迭代結果(第一次時爲init的元素,如沒有init則爲seq的第一個元素)與下一個元素一同執行一個二元的func函數。"

在reduce函數中,init是可選的,若是使用,則做爲第一次迭代的第一個元素使用。

簡單來講,能夠用這樣一個形象化的式子來講明:

reduce( func, [1, 2, 3] ) = func( func(1, 2), 3)

下面是reduce函數的工做過程圖:

reduce

舉個例子來講,階乘是一個常見的數學方法,Python中並無給出一個階乘的內建函數,咱們可使用reduce實現一個階乘的代碼。

n = 5
print reduce(lambda x,y: x*y, range(1, n + 1))  # 120

那麼,若是咱們但願獲得2倍階乘的值呢?這就能夠用到init這個可選參數了。

m = 2
n = 5
print reduce( lambda x,y: x*y, range( 1, n + 1 ), m )  # 240

 

 

 

4. raise


From: http://www.cnblogs.com/IPrograming/p/Python_error_handler.html

 

1. 拋出異常和自定義異常

Python用異常對象(exception object)表示異常狀況,遇到錯誤後,會引起異常。

若是異常對象並未被處理或捕捉,程序就會用所謂的回溯(Traceback,一種錯誤信息)終止執行。

 

1.1 raise 語句

Python中的raise 關鍵字用於引起一個異常,基本上和C#和Java中的throw關鍵字相同,以下所示:

複製代碼
1 # -- coding: utf-8 --
2 
3 def ThorwErr():
4     raise Exception("拋出一個異常")     # 關鍵字後面是拋出是一個通用的異常類型(Exception),
5 
6 # Exception: 拋出一個異常
7 ThorwErr()raise
複製代碼

通常來講拋出的異常越詳細越好,Python在exceptions模塊內建了不少的異常類型,經過使用dir函數來查看exceptions中的異常類型,以下:

import exceptions

# ['ArithmeticError', 'AssertionError'.....]
print dir(exceptions)

 

傳遞異常

捕捉到了異常,可是又想從新引起它(傳遞異常),可使用不帶參數的raise語句便可:

複製代碼
 1 # -- coding: utf-8 --
 2 class MuffledCalculator:
 3     muffled = False
 4     def calc(self,expr):
 5         try:
 6             return eval(expr)
 7         except ZeroDivisionError:
 8             if self.muffled:
 9                 print 'Division by zero is illegal'
10             else:
11                 raise
複製代碼

 

1.2 自定義異常類型

Python中也能夠自定義本身的特殊類型的異常,只須要要從Exception類繼承(直接或間接)便可:

class SomeCustomException(Exception):
    pass

 

2. 捕捉異常

和C#中的try/catch相似,Python中使用try/except關鍵字來捕捉異常,以下:

# -- coding: utf-8 --

try:
    print 2/0
except ZeroDivisionError:
    print '除數不能爲0'

 

2.1 捕捉多個異常 (如下兩種選擇)

在一個except語句只捕捉其後聲明的異常類型,若是可能會拋出的是其餘類型的異常就須要再增長一個except語句了,或者也能夠指定一個更通用的異常類型好比:Exception,以下:

複製代碼
# -- coding: utf-8 --
try:
    print 2/'0'
except ZeroDivisionError:
    print '除數不能爲0'
except Exception:
    print '其餘類型異常'
複製代碼

 爲了捕獲多個異常,除了聲明多個except語句以外,還能夠在一個except語句以後將多個異常做爲元組列出來便可:

# -- coding: utf-8 --
try:
    print 2/'0'
except (ZeroDivisionError,Exception):
    print '發生了一個異常'

 

2.2獲取異常信息

每一個異常都會有一些異常信息,通常狀況下咱們應該把這些異常信息記錄下來:

# -- coding: utf-8 --
try:
    print 2/'0'
except (ZeroDivisionError,Exception) as e:
    # unsupported operand type(s) for /: 'int' and 'str'
    print e

 

3. finally子句

finally子句和try子句聯合使用可是和except語句不一樣,finally無論try子句內部是否有異常發生,都會執行finally子句內的代碼。全部通常狀況下,finally本身經常用於關閉文件或者在Socket中。

複製代碼
# -- coding: utf-8 --
try:
    print 2/'0'
except (ZeroDivisionError,Exception):
    print '發生了一個異常'
finally:
    print '無論是否發生異常都執行'
複製代碼
相關文章
相關標籤/搜索