python 學習筆記day06-錯誤和異常、函數基礎

錯誤和異常

    基本概念

        錯誤

            從軟件方面來說,錯誤是語法或是邏輯上的

            - 語法錯誤指示軟件的結構上有錯誤,導致不能被解釋器解釋或編譯器無法編譯,這些錯誤必須在程序執行前糾正

            - 邏輯錯誤可能是由於不完整或是不合法的輸入所致,還可能十邏輯無法生成、計算,或是輸出結果需要的無法執行

        異常

            當python檢測到一個錯誤時,解釋器就會指出當前流已經無法繼續執行下去,這時候就出現了異常        

            異常是因爲程序出現了錯誤而在正常控制流以外採取的行爲

            這個行爲又分爲兩個階段:

            - 首先是引起異常發生的錯誤

            - 然後是檢測(和採取可能的措施)階段

        python中的異常

            當程序運行時,因爲遇到未解的錯誤而導致終止運行,便會出現tarceback消息,打印異常

異常
描述
NameError
未聲明/初始化對象
IndexError
序列中沒有此索引
SyntaxError
語法錯誤
KeyboardInterrupt
用戶中斷執行
EOFError
沒有內建輸入,到達EOF標記
IOError
輸入/輸出操作失敗

    檢測和處理異常

        try.except語句

            定義了進行異常監控的一段代碼,並且提供了處理異常的機制

            try:

                try_suite #監控這裏的異常

            except Exception[,reason]

                except_sutie # 異常處理代碼

                >>> try:
                ...   f = open('foo.txt')
                ... except IOError:
                ...   print "No such file!"
                ...
                No such file!

                #!/usr/bin/env pytyon

                import time

                for i in range(1,11):
                    print i
                    try:

                         time.sleep(1)
                    except KeyboardInterrupt:
                         break/pass
                 print 'done'


        帶有多個except的try語句

            可以把多個except語句連接在一起,處理一個try塊中可能發生的多種異常

            

                >>> try:

                ...   data = int(raw_input('input a number: '))

                ... except KeyboardInterrupt:    

                ...   print 'user cancelled'

                ... except ValueError:

                ...   print 'you must input a number!'   

                ... 

                input a number: hello

                you must input a number!

習題訓練:簡化除法判斷

    編寫除法程序

    1、提示用戶輸入一個數字作爲除數

    2、如果用戶按下Ctrl+C或Ctrl+D則退出程序

    3、如果用戶輸入非數字字符,提示用戶應該輸入數字

    4、如果用戶輸入0,提示用戶0不能作爲除數

#!/usr/bin/env python


try:

    num = int(raw_input('number: '))

    result = 100 / num

except (KeyboardInterrupt,EOFError):

    print "User cancelled"

except (ValueError,ZeroDivisionError):

    print "Invalib input!"

        捕獲所有異常

            如果出現的異常沒有出現在指定要捕獲的異常列表中,程序仍然會中斷,可以使用

            在異常繼承的樹結構中,BaseException實在最頂層的,所以使用它可以捕獲任意類型的異常

                >>> try:

                ...   data = int(raw_input("input a number: "))

                ... except BaseException:

                ...   print "\nsome error"

                ... 

                input a number: ^C

                some error

        異常參數

            異常也可以有參數,異常引發後它會被傳遞給異常處理器

            當異常被引發後參數是你爲附加幫助信息傳遞給異常處理器的

                >>> try:

                ...   data = 10 / 0 

                ... except ZeroDivisionError,e:  

                #異常名字(如果有多個用()括起來,用逗號隔開),第二個參數是存儲異常原因的變量

                ...   print "Error",e

                ... 

                Error integer division or modulo by zero

        else子句

            在try範圍中沒有異常被檢測到時,執行else子句

            在else範圍中的任何代碼運行前,try範圍中的所有代碼必須完全成功

            

                >>> try:

                ...   res = 10 / int(raw_input("Input a number: "))

                ... except BaseException,e:

                ...   print "Error:",e

                ... else:

                ...   print res

                ... 

                Input a number: 5

                2

        finally子句

            finally子句是無論異常是否發生,是否捕捉都會執行的一段代碼

            如果打開文件後,因爲發生異常導致文件沒有關閉,可能會發生數據損壞。使用finally可以保證文件總是能正常關閉

                >>> try:
                ...   try:
                ...     ccfile = open('carddata.txt','r')
                ...     txns = ccfile.readlines()
                ...   except IOError:
                ...     log.write("no txns this month\n")
                ... finally:
                ...   if ccfile:
                ...     ccfile.close()
                ...
f = open('abc.txt','r')

try:

  data = f.read()

finally:

  f.close()

        with子句

            with語句是用來簡化代碼的

            在將打開文件的操作放在with語句中,代碼塊結束後,文件將自動關閉

                >>> with open("get-pip.py") as f:
                ...   data = f.readlines()
                ...
                >>> f.closed
                True


    觸發異常

        raise語句

            要想引發異常,最簡單的形式就是輸入關鍵字raise,後面跟要引發的異常的名稱

            執行raise語句時,Python會創建指定的異常類的一個對象

            raise語句還可指定對異常對象進行初始化的參數

                >>> number = 3
                >>> try:
                ...   if number < 10:
                ...     raise ValueError,'Number is too smalle.'  #(必須是系統存在的異常,可自定義異常產生原因)
                ... except ValueError,e:
                ...   print 'Error:',e
                ...
                Error: Number is too smalle.


        斷言

            斷言是一句必須等價於布爾值爲真的判定

            此外,發生異常也意味着表達式爲假

                >>> number = 3
                >>> try:
                ...   assert number > 10,'number is too small'
                ... except AssertionError,e:
                ...   print 'Error:',e
                ...
                Error: number is too small
函數基礎

    創建函數

        def語句

            函數用def語句創建,語法如下:

            def function_name(arguments):

                "function_documentation_string"

                function_body_sutie

            標題行由def關鍵字,函數的名字,以及參數的集合(如果有的話)組成

            def子句的剩餘部分包括了一個雖然可選但是強烈推薦的文檔字串,和必須的函數體

        前向引用

            函數不允許在函數未聲明之前對其引用或者調用

            def foo():

                print "in foo"

                bar()

            foo()    #報錯,因爲bar沒有定義

            ---------------------------------------------

            def foo():

                print “in foo”

                bar()

            def bar():

                print "in bar"

            foo() # 正常執行,雖然bar的定義在foo定義後面

        函數屬性

            函數屬性是python另外一個使用了句點屬性標識並擁有名字空間的領域

            >>> def foo():
            ...   'foo() -- properly create doc string'
            ...
            >>> foo.__doc__
            'foo() -- properly create doc string'
            >>> foo.version = 1.0
            >>> foo.version
            1.0

        內部函數

            在函數體內創建另外一個函數是完全合法的,這種函數叫做內部/內嵌函數

            >>> def foo():
            ...   def bar():
            ...     print 'bar() is called'
            ...   print 'foo() is called'
            ...   bar()
            ...
            >>> foo()
            foo() is called
            bar() is called
            >>> bar()
            Traceback (most recent call last):
              File "<stdin>", line 1, in <module>
            NameError: name 'bar' is not defined


    調用函數

        函數操作符

            使用一對圓括號()調用函數,如果沒有圓括號,只是對函數的引用

            任何輸入的參數都必須放置在括號中

            >>> def foo():
            ...   print "hello world!"
            ...
            >>> foo()
            hello world!
            >>> foo
            <function foo at 0xb70a2bc4>

####引用:當你定義一個函數的時候,在內存中會分配一塊內存,函數名指向這塊內存,此爲函數引用,當你在把foo 賦值給一個變量,這個變量的作用和foo是一樣的。都是指向的一塊內存地址

####調用:即執行函數體中的語句,將foo()賦值給b,foo() 函數中的函數體會被執行,b得到的是foo()函數的return結果,如果在函數中沒有顯示定義return,則返回none,此時b的值即爲none。

        關鍵字參數

            關鍵字參數的概念僅僅針對函數調用

            這種理念是讓調用者通過函數調用中的參數名字來區分參數

            這種規範允許參數確實或者不按順序

            >>> def getinfo(name,age):
            ...   print "%s 's age is %s" % (name,age)
            ...
            >>> getinfo(23,'bob')
            23 's age is bob
            >>> getinfo(age=23,name = 'bob')
            bob 's age is 23


        參數組

            python允許程序員執行一個沒有顯示定義參數的函數

            相應的方法是通過一個把元組(非關鍵字參數)或字典(關鍵字參數)作爲參數組傳遞給函數

            func(*tuple_grp_nonkv_args,**dict_grp_kw_args)

            >>> def foo(*args):
            ...   print args
            ...
            >>> foo()
            ()
            >>> foo(10)
            (10,)
            >>> foo(10,20,'hello')
            (10, 20, 'hello')

            >>> def add(x,y):
            ...   return x + y
            ...
            >>> add(10,20)
            30
            >>> add([10,20])
            Traceback (most recent call last):
              File "<stdin>", line 1, in <module>
            TypeError: add() takes exactly 2 arguments (1 given)
            >>> add(*[10,20])  #“解開”
            30

            >>> def bar(**args):
            ...   print args
            ...
            >>> bar(name='bob',age=20)
            {'age': 20, 'name': 'bob'}
            >>> bar()
            {}

            >>> def func1(args,*non_kwagrs,**kwargs):
            ...   print args
            ...   print non_kwagrs
            ...   print  kwargs
            ...
            >>> func1()
            Traceback (most recent call last):
              File "<stdin>", line 1, in <module>
            TypeError: func1() takes at least 1 argument (0 given)
            >>> func1(10)
            10
            ()
            {}
            >>> func1(10,20,30,name='bb')
            10
            (20, 30)
            {'name': 'bb'}
習題訓練:數學遊戲

    編寫一個簡單的加減法數學遊戲

    1、隨機生成兩個100以內的數字

    2、隨機選擇家法或是減法

    3、總是是用大的數字減去小的數字

    4、如果用戶打錯三次,程序給出正確答案

#!/usr/bin/env python


import random


def add(x,y):

    return x + y

def sub(x,y):

    return x - y


def probe():

    CMDs = {'+': add,'-': sub}

   #CMDS = {'+': lambda x,y: x + y,'-': lambda x,y: x-y} #可以不用定義上面的兩個函數,簡化代碼

    nums = [random.randint(1,50) for i in range(2)]

    nums.sort(reverse=True)

    op = random.choice('+-')

    answer = CMDs[op](*nums)

    prompt = "%s %s %s = " % (nums[0],op,nums[1])

    tries = 0


    while tries < 3:

        try:

            result = int(raw_input(prompt))

        except:

            continue

        

        if answer == result:

            print "Very good!!!"

            break

        print "Wrong answer."

        tries += 1

    else:

        print "\033[31;1m%s%s\033[0m" %(prompt,answer)

if __name__ == '__main__':

    while True:

        probe()

        try:

            yn = raw_input("Continue(y/n)? ").strip()[0]

        except(KeyboardInterrupt,EOFError):

            print "\nBye-Bye"

            yn = 'n'

        except IndexError:

            continue

        if yn in 'Nn':

            break

    匿名函數

        lambda

            python允許lambda關鍵字創造匿名函數

            匿名是因爲不需要以標準的def方式來聲明

             一個完成的lambda“語句”代表了一個表達式,這個表達式的定義體必須和聲明放在同一行

            lambda[arg1[,arg2,...argN]]:expression

            

            >>> a = lambda x,y:x + y

            >>> print a(3,4)

            7

            應用實例見上面的數學遊戲程序

        filter()函數

            filter(func,seq):調用一個布爾函數func來迭代遍歷每個序列中的元素;返回一個使func返回值爲true的元素的序列

            如果布爾函數比較簡單,直接使用lambda匿名函數就顯得非常方便了

            

            >>> data = filter(lambda x: x % 2,[num for num in range(10)])

            >>> print data

            [1, 3, 5, 7, 9]

        map()函數

        reduce()函數

            reduce(func,seq[,init]):將二元函數作用於seq序列的元素,每次攜帶一對(先前的結果以及下一個序列元素),連續的將現有的結果和下一個給值作用在獲得的隨後的結果上,最後減少序列爲一個單一的返回值

            

            >>> data = reduce(lambda x,y: x + y,range(1,6))

            >>> print data

            15

習題訓練:

家庭理財系統

記賬:    

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章