1. 程式人生 > >Python全棧開發-Day3-Python基礎3

Python全棧開發-Day3-Python基礎3

找到 現在 simon 變量作用域 全局變量 index 全部 dataset 減少

本節內容

  1. 函數基本語法及特性

  2. 參數與局部變量

  3.遞歸

  4.函數式編程介紹

  5.高階函數

1.函數基本語法及特性

 三種編程範式:

   1、面向過程:過程——> def

   2、面向對象:類——> class

   3、函數式編程:函數——> def

函數是什麽?

函數一詞來源於數學,但編程中的「函數」概念,與數學中的函數是有很大不同的,編程中的函數在英文中也有很多不同的叫法。在C中只有function,在Java裏面叫做method。

定義: 函數是指將一組語句的集合通過一個名字(函數名)封裝起來,要想執行這個函數,只需調用其函數名即可

使用函數的好處:

  1. 減少重復代碼
  2. 使程序變的可擴展
  3. 使程序變得易維護

語法定義

1 2 3 4 5 def test(x):#函數定義方法、函數名、變量 ‘‘‘The function difinition!‘‘‘ #對該函數的描述   x+=1 #函數體
  return x #返回值 test(1) #調用函數

函數:

  def func1():

    ‘‘‘testing1‘‘‘

    print(‘in the func1‘)

    return 0

過程:

  def func2():

    ‘‘‘testing2‘‘‘

    print(‘in the func2‘)

由上得出,過程就是沒有返回值的函數。

可以帶參數

1 2 3 4 5 6 7 8 9 10 11 12 13 #下面這段代碼 a,b = 5,8 c = a**b print(c) #改成用函數寫 def calc(x,y): res = x**y return res #返回函數執行結果 c = calc(a,b) #結果賦值給c變量 print(c)

return的作用

  1、終止函數的運行,即return後面的代碼都將不會被執行

  2、return給調用該函數的位置,返回一個值。如,x=test1(),x就會接收到return的返回值

  3、後續程序有時需要根據之前函數return返回值的不同,進行不同的判斷和運算。

return的返回值

  return 1, ‘hello‘, [‘alex‘,‘wupeiqi‘], {‘name’:‘alex‘}

  所以,return的個數沒規定,類型沒規定。把return後面的內容放入元組中全部返回,本質上return還是返回了一個值。如果之前有一個函數def test():, 用return test 時,返回值是test函數的內存地址。

2.函數參數與局部變量

調用方法:

  1、test()執行,()表示調用函數test,()可以有參數也可以沒有

參數

  1、形參和實參

  形參:形式參數,不是實際存在的,是虛擬變量,在定義函數和函數體的時候使用形參,目的是在函數調用時接收實參(實參個數、類型應與形參一一對應)

  實參:實際參數,調用函數時傳給函數的參數,可以是常量,變量,表達式,函數,傳給形參

  區別:形參是虛擬的,不占用內存空間,形參變量只有在被調用時才分配內存單元,實參是一個變量,占用內存空間,數據傳送單向,實參傳送給形參,不能形參傳給實參。

  2、關鍵字調用,與形參順序無關;位置調用與形參一一對應。

    【註意】:關鍵字參數不能寫在位置參數之前

  3、默認參數

    def test(x,y=2):

      print(x,y)

    test(1)

    上述代碼在定義函數時對形參賦值的過程叫做設置默認參數,被賦的值叫做對應形參的默認參數。

    默認參數特點:調用函數時,默認參數非必須傳遞

  4、參數組:

    1)def test(*args):

       print(args)

      test(1,2,3,4,5) #或者等價於後面這種賦值方式: test(*[1,2,3,4,5])

      輸出:(1,2,3,4,5)

      這時候會把5個位置實參全部傳給形參args,並且以元組的形式保存下來。定義位置調用參數組時,以*開頭即可,args的名字可以是任意的。但編寫規範就是*args。

    2)def test2(**kwargs):

        print(kwargs)

      test2(name=‘gavin‘,age=25,sex=‘M‘) #或者等價於後面這種賦值方式: test2(**{‘name’:‘gavin‘,‘age‘:25,‘sex‘:‘M‘})

      輸出:{‘name’:‘gavin‘,‘age‘:25,‘sex‘:‘M‘}

      這時候會把3個關鍵字調用的實參全部傳遞給形參kwargs,並且以字典的方式保存,關鍵字為key,給關鍵字賦的值為value。定義關鍵字調用參數組時,以**開頭,kwargs的名字可以是任意的,但是編寫規範就是**kwargs。

    3)小結:

      *args把N個位置參數,轉換成元組的方式

      **kwargs把N個關鍵字參數,轉換成字典的方式

      【註意】: 參數組一定要放在形參的最後面

           位置參數一定要寫在關鍵字參數之前。所以對應的,形參部分先寫*args,再寫**kwargs。

      

局部變量 

1 2 3 4 5 6 7 8 9 10 name = "Alex Li" def change_name(name): print("before change:",name) name = "金角大王,一個有Tesla的男人" print("after change", name) change_name(name) print("在外面看看name改了麽?",name)

輸出

1 2 3 before change: Alex Li after change 金角大王,一個有Tesla的男人 在外面看看name改了麽? Alex Li

全局與局部變量

在子程序中定義的變量稱為局部變量,在程序的一開始定義的變量稱為全局變量。 全局變量作用域是整個程序(包括所有函數的內部),局部變量作用域是定義該變量的子程序。 當全局變量與局部變量同名時: 在定義局部變量的子程序內,局部變量起作用;在其它地方全局變量起作用。

在函數內修改全局變量

  name=‘gavin

  def change_name(name):

    global name

    name=‘Gavin Simons‘

    pass

  chang_name(name)

  在上述這種情況下,在函數內部使用global指令,聲明了name為全局變量,此時在函數內部再修改name時,修改的是全局變量。同時如果在函數內部聲明全局變量之前,即在文件開頭並沒有相同名字的全局變量,則函數內的全局變量會被新創建,在函數外部也可以進行調用。但是,雖然這樣可行,但是永遠不要這麽幹(包括在函數內修改全局變量和在函數內創建全局變量),因為這麽做很難去調試,不知道是那個函數創建或修改了全局變量。

局部變量和全局變量的特殊情況

   names=[‘Gavin‘,‘Simons‘,‘Jack‘,‘Rain‘]

  def chang_name():

    names[0] = ‘詹姆斯西蒙斯’

    print(‘inside func‘,names)

  change_name()

  print(names)

   輸出:inside func [‘詹姆斯西蒙斯‘,‘Simons‘,‘Jack‘,‘Rain‘]

     [‘詹姆斯西蒙斯‘,‘Simons‘,‘Jack‘,‘Rain‘]

  所以只有像簡單的數據類型(比如,字符串和整數)是不能在函數中修改的。但是復雜的數據類型(比如,列表、字典、集合、類,元組在什麽時候都不能改)這些都是在局部裏面可以直接改全局的。因為存放方式和簡單數據類型不同,後者存放的是地址,而不是具體的值。

    

3. 遞歸

在函數內部,可以調用其他函數。如果一個函數在內部調用自身本身,這個函數就是遞歸函數。

1 2 3 4 5 6 7 8 9 10 11 12 13 def calc(n): print(n) if int(n/2) ==0: return n return calc(int(n/2)) calc(10) 輸出: 10 5 2 1

遞歸特性:

1. 必須有一個明確的結束條件

2. 每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減少

3. 遞歸效率不高,遞歸層次過多會導致棧溢出(在計算機中,函數調用是通過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞歸調用的次數過多,會導致棧溢出)

堆棧掃盲http://www.cnblogs.com/lln7777/archive/2012/03/14/2396164.html

遞歸函數實際應用案例,二分查找

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35] def binary_search(dataset,find_num): print(dataset) if len(dataset) >1: mid = int(len(dataset)/2) if dataset[mid] == find_num: #find it print("找到數字",dataset[mid]) elif dataset[mid] > find_num :# 找的數在mid左面 print("\033[31;1m找的數在mid[%s]左面\033[0m" % dataset[mid]) return binary_search(dataset[0:mid], find_num) else:# 找的數在mid右面 print("\033[32;1m找的數在mid[%s]右面\033[0m" % dataset[mid]) return binary_search(dataset[mid+1:],find_num) else: if dataset[0] == find_num: #find it print("找到數字啦",dataset[0]) else: print("沒的分了,要找的數字[%s]不在列表裏" % find_num) binary_search(data,66)

  

4.函數式編程介紹  

函數是Python內建支持的一種封裝,我們通過把大段代碼拆成函數,通過一層一層的函數調用,就可以把復雜任務分解成簡單的任務,這種分解可以稱之為面向過程的程序設計。函數就是面向過程的程序設計的基本單元。

函數式編程中的函數這個術語不是指計算機中的函數(實際上是Subroutine),而是指數學中的函數,即自變量的映射。也就是說一個函數的值僅決定於函數參數的值,不依賴其他狀態。比如sqrt(x)函數計算x的平方根,只要x不變,不論什麽時候調用,調用幾次,值都是不變的。

Python對函數式編程提供部分支持。由於Python允許使用變量,因此,Python不是純函數式編程語言。

一、定義

簡單說,"函數式編程"是一種"編程範式"(programming paradigm),也就是如何編寫程序的方法論。

主要思想是把運算過程盡量寫成一系列嵌套的函數調用。舉例來說,現在有這樣一個數學表達式:

  (1 + 2) * 3 - 4

傳統的過程式編程,可能這樣寫:

  var a = 1 + 2;

  var b = a * 3;

  var c = b - 4;

函數式編程要求使用函數,我們可以把運算過程定義為不同的函數,然後寫成下面這樣:

  var result = subtract(multiply(add(1,2), 3), 4);

因此,函數式編程的代碼更容易理解。

要想學好函數式編程,不要玩py,玩Erlang,Haskell。

    

5.高階函數

變量可以指向函數,函數的參數能接收變量,那麽一個函數就可以接收另一個函數作為參數,這種函數就稱之為高階函數。

即把函數本身當作一個參數,傳給另一個函數。

1 2 3 4 5 6 def add(x,y,f): #f為一個函數形參 return f(x) + f(y) res = add(3,-6,abs)#abs是函數實參,其實就是函數abs的內存地址 print(res)

Python全棧開發-Day3-Python基礎3