1. 程式人生 > >Python快速學習第五天

Python快速學習第五天

第五天:抽象

1、    函式

檢測函式是否可呼叫:callable

>>> import math

>>> y=math.sqrt

>>> callable(y)

True

>>> x=1

>>> callable(x)

False

   注意:Python3.0不在支援callable,需要使用表示式hasattr(func,_call_call_)代替

   建立函式:def functionname(params):

>>>def fibs(num):

...     'Get fibonaqi sequnce! '

...     result=[0,1]

...     for i in range(num-2):

...            result.append(result[-2]+result[-1])

...     return result

...

>>>fibs(10)

[0, 1,1, 2, 3, 5, 8, 13, 21, 34]

用於def後面的'Getfibonaqi sequnce! '新增文件字串,相當於註釋#,使用help()可以查詢函式的文件字串

help(fibs)

Help on function fibs in module __main__:

fibs(num)

    Getfibonaqi sequnce!

...skipping...

Help on function fibs in module __main__:

fibs(num)

    Getfibonaqi sequnce!

 return後不加值,只表示函式的結束,而沒有返回值,這樣可以避免應該返回序列時,意外返回None

>>> def test():

...     print 'tanggao'

...     return

...     print 'tanggao isgood'

...

>>> x=test()

tanggao

>>> print x

None

2、   引數對外部變數影響

   函式內給引數賦值,不會改變外部變數的值,引數儲存在區域性作用域中

>>> def try_to_change(n):

...     n=3

...

>>> t=4

>>> try_to_change(t)#雖然在函式內部重新賦值,但外部不變

>>> t

4

但是對於可改變的資料結構,如列表,引數的內部賦值會改變外部變數的值

   內部引數與外部變數指向同一個列表,所以會被修改

   若不想改變外部列表,可以傳進一個副本

>>> def change(n):

...    n[0]='tanggao'

...

>>> names=['hello','world']

>>> change(names)

>>> names

['tanggao', 'world']

>>>  #採用普通方法進行模擬 

...

>>> names=['hello','world']

>>> n=names

>>> n[0]='tanggao'

>>> names

['tanggao', 'world']

完整示例——儲存名字,並能用名字、中間名或姓來查詢聯絡人

   若名字為'MagusLie Hetland'儲存格式類似

   data = {

           'first':{ 'Magus': 'Magus Lie Hetland'},

           'middle':{'Lie': 'Magus Lie Hetland'},

           'last':{'Hetland': 'Magus Lie Hetland'}

       }

   注意insert(index,value)函式,在列表的索引位置插入值

Python程式碼  

1.  >>> def init(data):  #data作為儲存表,初始化  

2.      data['first'] = {}  

3.      data['middle'] = {}  

4.      data['last'] = {}  

5.    

6.  >>> def store(data, full_name): #儲存,將全名儲存到表中  

7.      names = full_name.split()  #將名字按空格(即first,middle,last)分開,返回列表,如'Ma Li He'返回['Ma', 'Li', 'He']  

8.      if len(names) == 2: names.insert(1, '')#若無中間名,則插入空來表示中間名['Mr', 'Zha']返回['Mr', '', 'Zha']  

9.      labels = 'first''middle''last'  #元組  

10.     for label, name in zip(labels, names):  #元組與序列間也可使用zip  

11.         people = lookup(data, label, name)  

12.         if people:  

13.             people.append(full_name)  

14.         else:  

15.             data[label][name] = [full_name] #當鍵不存在時,自動新增鍵值對,  

16.                                                                          #但如果輸出不存在鍵對應值,則報錯  

17.   

18. >>> def lookup(data, label, name): #查詢,根據label查詢是name的中間人  

19.     return data[label].get(name)  

20.   

21.               

22. >>> MyNames = {}  

23. >>> init(MyNames)  

24. >>> store(MyNames, 'Magnus Lie Hetland')  

25. >>> lookup(MyNames, 'middle''Lie')  

26. ['Magnus Lie Hetland']  

27. >>> store(MyNames, 'Robin Hood')  

28. >>> store(MyNames, 'Robin Locksley')  

29. >>> lookup(MyNames, 'first''Robin')  

30. ['Robin Hood''Robin Locksley']  

31. >>> store(MyNames, 'Mr. Gumby')  

32. >>> lookup(MyNames, 'middle''')  

33. ['Robin Hood''Robin Locksley''Mr. Gumby']  

   例2. 不可變的數字和可改變的引數

Python程式碼  

1.  >>> def inc(x): return x + 1  

2.    

3.  >>> foo = 10  

4.  >>> inc(foo)  

5.  11  

6.  >>> foo #外部變數未發生變化  

7.  10  

8.  >>> foo = inc(foo) #將foo重新賦值  

9.  >>> foo  

10. 11  

   使用列表外部變數foo改變了

Python程式碼  

1.  >>> def inc(x): x[0] = x[0] + 1  

2.    

3.  >>> foo = [10]  

4.  >>> inc(foo)  

5.  >>> foo  

6.  [11]  

3. 關鍵字引數和預設值

   位置:是指根據引數的對應位置傳參,如def a(a,b,c):,呼叫a(1,2,3),1傳給a,2傳給b,3傳給c,這樣引數位置容易記混。

   關鍵字引數,適用於大規模程式,清晰

Python程式碼  

1.  >>> def hello(name, greeting):  

2.      print '%s, %s!' %(greeting, name)  

3.    

4.        

5.  >>> hello('sun''Hello')  #位置引數  

6.  Hello, sun!  

7.  >>> hello(name = 'Sun', greeting = 'Hello')  #關鍵字引數  

8.  Hello, Sun!  

9.  >>> hello(greeting = 'Hello', name = 'Sun'#關鍵字引數,不必關心位置  

10. Hello, Sun!  

   預設值

Python程式碼  

1.  >>> def hello(name = 'world', greeting = 'Hello'):  

2.      print '%s, %s!' %(greeting, name)  

3.    

4.        

5.  >>> hello()  

6.  Hello, world!  

7.  >>> hello('Sun')  

8.  Hello, Sun!  

9.  >>> hello(greeting = 'Hi')  

10. Hi, world!  

   位置引數與關鍵字引數混用,將位置引數放在前面。儘量避免這麼用,容易引起混亂。

Python程式碼  

1.  >>> def hello(name, greeting = 'Hello', punc = '!'):  

2.      print '%s, %s%s' %(greeting, name, punc)  

3.    

4.        

5.  >>> hello('Sun')  

6.  Hello, Sun!  

7.  >>> hello('Sun''Hi')  

8.  Hi, Sun!  

9.  >>> hello('Sun', punc = '..')  

10. Hello, Sun..  

11. >>> hello()   #因為name是必須要有,若有預設值,則可沒有  

12.   

13. Traceback (most recent call last):  

14.   File "<pyshell#385>", line 1, in <module>  

15.     hello()  

16. TypeError: hello() takes at least 1 argument (0 given)  

17. >>>   

4. 收集引數——在定義時使用*或**,用來收集引數,允許使用不定數量的引數

   *:收集其餘的位置引數並作為元組 返回

Python程式碼  

1.  >>> def print_params2(title, *params):  

2.      print title  

3.      print params  

4.    

5.        

6.  >>> print_params2('Param:', 1, 2, 3)  

7.  Param:  

8.  (1, 2, 3)  #以元組形式返回  

9.  >>> print_params2('Param:'#不提供收集元素時,返回空元組  

10. Param:  

11. ()  

12. >>> print_params2('Param:', 1)   

13. Param:  

14. (1,) #只有一個元素時,仍為元組  

   **:收集其餘的關鍵字引數並作為字典 返回,可與其他混用

Python程式碼  

1.  >>> def print_params3(x, y, z = 3, *pospar, **keypar):  

2.      print x, y, z  

3.      print pospar  

4.      print keypar  

5.    

6.        

7.  >>> print_params3(1,2,3,4,5,6,7, fool = 1, bar = 2)  

8.  1 2 3  

9.  (4, 5, 6, 7)  

10. {'fool': 1, 'bar': 2}  

11. >>> print_params3(1,2)  

12. 1 2 3  

13. ()  

14. {}  

5. 收集引數的翻轉過程——在呼叫時使用*或**,將引數分配到定義的引數中,用於字典或列表分割時

   用於列表

Python程式碼  

1.  >>> def add(x,y): return x + y  

2.    

3.  >>> params = (1,2)  

4.  >>> add(*params)  

5.  3  

   用於字典

Python程式碼  

1.  >>> def hello(name, greeting):  

2.      print '%s, %s!' %(greeting, name)  

3.    

4.        

5.  >>> params = {'name''Sir Robin''greeting''Welcome'}  

6.  >>> hello(**params)  

7.  Welcome, Sir Robin!  

8.    

9.     

   引數使用例項

Python程式碼  

1.  #模擬步長大於0的range()  

2.  >>> interval(10)  

3.  start = 0 stop = 10 step =  1  

4.  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]  

5.  >>> def interval(start, stop=None, step=1):  

6.      'Imitates range() for step > 0'  

7.      if stop is None: #若未給stop指定值  

8.          start, stop = 0, start #多個賦值,0賦值給start,start的值賦值給stop  

9.      result = []  

10.     i = start  

11.     while i < stop:  

12.         result.append(i)  

13.         i += step  

14.     return result  

15.   

16. #  

17. >>> def story(**kwds):  

18.     return '%(job)s called %(name)s.' %kwds  

19.   

20. >>> def power(x, y ,*others):  

21.     if others:  

22.         print 'Received redundant parameters:',others  

23.     return pow(x,y)  

24.   

25. #使用  

26. >>> params = {'job':'language','name':'python'}  

27. >>> print story(**params) #呼叫時分割字典,定義中收集  

28. language called python.  

29. >>> del params['job']  

30. >>> print story(job='test', **params)  

31.   

32. >>> power(2,3,'test')  

33. Received redundant parameters: test  

34.   

35. >>> params = (5,) * 2 #即(5,5)  

36. >>> power(*params) #先分割,在賦給x,y  

37. 3125  

6.作用域

   x = 1, 將名字x引用到值1上,類似字典

   內建函式vars()返回這個字典

Python程式碼  

1.  >>> x = 1  

2.  >>> scope = vars()  

3.  >>> scope['x']  

4.  1  

5.  >>> scope['x'] += 1 #一般情況下,vars()返回的字典不能修改  

6.  >>> x  

7.  2  

   區域性變數,全域性變數

   函式內部訪問全域性變數,慎用!

Python程式碼  

1.  >>> def com(para): print para + external  

2.    

3.  >>> external = 'external'  

4.  >>> com('param ')  

5.  param external  

   若全域性變數與區域性變數名字相同,會被區域性變數覆蓋,可使用global()類似vars(),獲得全域性變數的字典

Python程式碼  

1.  >>> def com(para): print para + globals()['para']  

2.    

3.  >>> para = 'berry'  

4.  >>> com('test ')  

5.  test berry  

   重繫結全域性變數,將變數引用到其他新值——函式內部宣告全域性變數

Python程式碼  

1.  >>> x = 1  

2.  >>> def change_global():  

3.      global x  

4.      x = x + 1  

5.    

6.        

7.  >>> change_global()  

8.  >>> x  

9.  2  

   巢狀作用域——函式中定義函式,例如閉包

   外部作用域中的變數一般不能被改變,但是用閉包,每次呼叫外層函式,內部函式都會被重新繫結,也即外部作用域factor每次都有一個新值

Python程式碼  

1.  >>> def multiplier(factor):  

2.      def multiplyByFactor(number):  

3.          return number * factor  

4.      return multiplyByFactor  #返回一個函式,這時並未呼叫  

5.    

6.  >>> double = multiplier(2)  #double是一個函式  

7.  >>> double   #double是一個函式  

8.  <function multiplyByFactor at 0x0214C6F0>  

9.  >>> double(5)  #呼叫multiplyByFactor(number)  

10. 10  

11. >>> multiplier(2)(5) #效果同上  

12. 10  

   7. 遞迴——每呼叫一個函式,都會建立一個新的名稱空間,意味著當函式呼叫自身時,實際上呼叫的是兩個不同的函式

    階乘

Python程式碼  

1.  >>> def factorial(n):  

2.      if n == 1:  

3.          return 1  

4.      else:  

5.          return n * factorial(n-1)  

6.    

7.  >>> factorial(5)  

8.  120  

    冪

Python程式碼  

1.  >>> def power(x, n):  

2.      if n == 0:  

3.          return 1  

4.      else:  

5.          return x * power(x, n - 1)  

6.    

7.        

8.  >>> power(2,3)  

9.  8  

   遞迴例項——二元搜尋

   前提:排好序

   若上下限相同,則那就是數字所在位置,返回;

   否則,找到兩者的中間,查詢數字是在左側還是右側,繼續查詢數字所在的那半部分。

Python程式碼  

1.  >>> def search(sequence, number, lower = 0, upper = None):  

2.      if upper is None: upper = len(sequence) - 1  

3.      if lower == upper:  

4.          assert number == sequence[upper]  

5.          return upper  

6.      else:  

7.          middle = (lower + upper) // 2  

8.          if number > sequence[middle]:  

9.              return search(sequence, number, middle + 1, upper)  

10.         else:  

11.             return search(sequence, number, lower, middle)  

12.   

13.           

14. >>> seq = [34, 67, 8, 123, 4, 100, 95]  

15. >>> seq.sort()  

16. >>> seq  

17. [4, 8, 34, 67, 95, 100, 123]  

18. >>> search(seq, 34)  

19. 2  

總結:

元組輸出格式化,直接使用鍵,而不需要加引號

Python程式碼  

1.  >>> d = {'a':1, 'b':2}  

2.  >>> print '%(a)s corresponds to %(b)s.' %d #注意a有括號,無引號  

3.  1 corresponds to 2.