Python之路--python基礎3

python基礎3
一、函數基本語法及特性
二、函數參數
三、局部變量和全局變量
四、返回值
嵌套函數
五、遞歸函數
六、匿名函數
七、高階函數
八、內置函數
九、函數式編程python

在編程語言中的函數並不是數學意義上的函數(老是返回根據參數計算獲得的結果),編程語言中的函數也稱爲過程,在使用這個函數的時候有可能不會返回一個結果或者說返回的結果不是數學意義上的函數執行的結果。程序員

1、函數基本語法及特性

一、抽象和結構

抽象是程序可以被別人理解的關鍵所在(不管對編寫程序仍是閱讀程序來講,這都相當重要)。
程序應很是抽象,以下載網頁、計算使用頻率、打印每一個單詞的使用頻率。下面將上述簡單描述轉換爲一個Python程序:express

page = download_page()
freqs = compute_frequencies(page)
for word, freq in freqs:
    print(word, freq)

看到這些代碼,任何人都知道這個程序是作什麼的。至於具體該如何作那麼咱們就得在函數中得出定義。編程

在好比打印斐波那契數(一種數列,其中每一個數都是前兩個數的和)app

fibs = [0,1]
for i in range(8):
    fibs.append(fibs[-2] + fibs[-1])
print(fibs)

上述代碼會打印出斐波那契數的前十個,固然你也能夠指定要打印數的個數:編程語言

num = int(input("How many Fibonacci numbers do you want?"))
fib = [0,1]
for i in range(num-2):
    fibs.append(fibs[-2] + fibs[-1])
print(fibs)

當咱們在其餘地方想使用這些數的時候,你可能會想到我再把這個循環再寫一次,對於這段代碼是能夠的,可是對於更加複雜的代碼你還願意去重寫嗎?真正的程序員會去抽象程序,把一些想要實現的功能抽象爲函數,直接調用這個函數來實現指定的功能,讓程序更加簡潔易懂而且下降代碼的重複率。真正的程序員會像下面這樣作:函數式編程

num = int(input("How many Fibonacci numbers do you want?"))
print(fibs(num))

二、函數的定義

def 函數名():
    函數體

例如:函數

def hello():
    print("Hello world!")

三、給函數編寫文檔

要給函數編寫文檔,以確保其餘人可以理解,可添加註釋。放在函數開頭的字符串成爲文檔字符串(docstring),將做爲函數的一部分存儲起來。例如:ui

def square(x):
    'Calculates the square of the number x.'
    return x * x

能夠像下面這樣訪問文檔字符串:spa

>>> square.__doc__
'Calculates the square of the number x.'

特殊的內置函數help頗有用。在交互式解釋器中,可以使用它獲取有關函數的信息,其中包含函數的文檔字符串。

>>> help(square)
Help on function square in module __main__:
square(x)
Calculates the square of the number x.

2、函數的參數

爲了讓一個函數更通用,在定義函數的時候可讓函數接收數據,函數接收的數據就是函數的參數。

一、參數的基本應用

(1)定義帶參數的函數


示例以下:

def add(a,b):
    c = a + b
    print(c)

(2)調用帶參數的函數


以上面的add函數爲例,咱們調用該函數,代碼以下:

def add(a,b):
    c = a + b
    print(c)
   
add(11,22)   #調用帶參數的函數時,須要在小括號中傳遞數據

(3)調用函數時參數的順序


>>> def test(a,b):
...     print(a,b)
... 
>>> test(1,2)
1 2
>>> test(b=1,a=2)
2 1
>>> 
>>> test(b=1,2)
  File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument
>>> 
>>>

經過以上代碼咱們能夠看出,函數的參數在調用的過程當中是一一對應的,若是不指定那個實參是那個對應的形參時,會默認按實參的順序將實參賦值給形參。

(4)總結


  • 定義時小括號中的參數,用來接收參數用的,稱爲「形參」
  • 調用時小括號中的參數,用來傳遞給函數的,稱爲「實參」

二、參數的高級應用

(1)缺省參數


調用函數時,缺省參數的值若是沒有傳入,則被認爲是默認值。缺省參數就是給參數設定默認值,若是在傳參過程當中,缺省參數傳入值的話則依照傳入的值,若是沒有傳入值則按照默認的值。以下代碼:

def sum(a,b=11):
    result = a + b 
    print("%d+%d=%d"%(a,b,result))

sum(11,22)    #調用函數時會將11和22分別賦值給a和b
sum(10,)      #調用函數時,因爲只給了一個實參,則10賦值給a,b則用默認的參數值11

程序運行結果以下:

clipboard.png

注意:帶有默認值的參數必定要位於參數列表的最後面。

>>> def printinfo(name, age=35, sex):
...     print name
...
  File "<stdin>", line 1
SyntaxError: non-default argument follows default argument

(2)不定長參數


有時可能須要一個函數能處理比當初聲明時更多的參數,這些參數叫作不定長參數,聲明時不會命名。

基本語法以下:

def functionname([formal_args,] *args, **kwargs):
    "函數_文檔字符串"
    function_suite
    return [expression]
加*號的變量args會存放全部未命名的變量參數,args爲元組
加**號的變量kwargs會存放命名參數,即形如key=value的參數,kwargs爲字典

可變參數示例:

>>> def fun(a, b, *args, **kwargs):
...     """可變參數演示示例"""
...     print "a =", a
...     print "b =", b
...     print "args =", args
...     print "kwargs: "
...     for key, value in kwargs.items():
...         print key, "=", value
...
>>> fun(1, 2, 3, 4, 5, m=6, n=7, p=8)  # 注意傳遞的參數對應
a = 1
b = 2
args = (3, 4, 5)
kwargs: 
p = 8
m = 6
n = 7
>>>
>>>
>>> c = (3, 4, 5)
>>> d = {"m":6, "n":7, "p":8}
>>> fun(1, 2, *c, **d)    # 注意元組與字典的傳參方式
a = 1
b = 2
args = (3, 4, 5)
kwargs: 
p = 8
m = 6
n = 7
>>>
>>>
>>> fun(1, 2, c, d) # 注意不加星號與上面的區別
a = 1
b = 2
args = ((3, 4, 5), {'p': 8, 'm': 6, 'n': 7})
kwargs:
>>>
>>>

(3)引用傳參


  • 可變類型與不可變類型的變量分別做爲函數參數時,會有什麼不一樣?
  • Python有沒有相似C語言中的指針傳參?
>>> def selfAdd(a):
...     """自增"""
...     a += a
...
>>> a_int = 1
>>> a_int
1
>>> selfAdd(a_int)
>>> a_int
1
>>> a_list = [1, 2]
>>> a_list
[1, 2]
>>> selfAdd(a_list)
>>> a_list
[1, 2, 1, 2]

Python中函數參數是引用傳遞(注意不是值傳遞)。對於不可變類型,因變量不能修改,因此運算不會影響到變量自身;而對於可變類型來講,函數體中的運算可能會更改傳入的參數變量。

以下代碼示例:

>>> def selfAdd(a):
...     """自增"""
...     a = a + a   # 咱們更改了函數體的這句話
...
>>> a_int = 1
>>> a_int
1
>>> selfAdd(a_int)
>>> a_int
1
>>> a_list = [1, 2]
>>> a_list
[1, 2]
>>> selfAdd(a_list)
>>> a_list
[1, 2]      # 想想爲何沒有變呢?

Python中變量之間的賦值利用到引用,只要是有"="就是引用,引用就是變量中存儲的是地址,而地址指向的內存空間是存真實數據地方。a = a + a會建立一個新的內存空間,而後讓變量a指向這段空間;而a += a是將a所指向的那段空間的值變爲a + a。以下demo:

>>> a = [1,2]
>>> id(a)
31329224
>>> a = a + a
>>> a
[1, 2, 1, 2]
>>> id(a)
31991944
>>> b = 2
>>> id(b)
1587990368
>>> b = b + b
>>> b
4
>>> id(b)
1587990432
>>> c = [1,2]
>>> id(c)
31992072
>>> c += c
>>> c
[1, 2, 1, 2]
>>> id(c)
31992072
>>>

3、局部變量和全局變量

一、局部變量

  • 局部變量,就是定義在函數內部的變量,其做用單位只是在函數體內;
  • 不一樣的函數,能夠定義相同名字的局部變量,其不會產生影響;
  • 局部變量的做用:爲了臨時保存數據須要在函數中定義變量來進行存儲。

示例:

def test1():
    a = 100     #此時的a爲局部變量,做用範圍只在test1函數內
def test2():
    print("a=%d"%a)
    
test1()
test2()

此時因爲a是局部變量,其作做用範圍只在test1函數中,至關於test2函數中沒有定義變量a,因此上述程序在運行時會報以下錯誤:

clipboard.png

二、全局變量

(1)什麼是全局變量


若是一個變量既能在函數體中使用,也能在其餘函數中使用,這樣的變量稱爲全局變量

示例:

#定義全局變量
a = 100

def test1():
    print("a=%d"%a)

def test2():
    print("a=%d"%a)

#調用函數
test1()
test2()

因爲變量a是全局變量,因此在test1和test2兩個函數中均可以使用變量a,運行結果以下:

clipboard.png

(2)全局變量與局部變量同名的問題


當全局變量與局部變量同名時,在定義該局部變量的函數體內以局部變量爲主,以下示例:

#定義全局變量
a = 100 

def test1():
    a = 300 
    print("---test1--修改前--a=%d"%a)
    a = 200 
    print("---test1--修改後--a=%d"%a)

def test2():
    print("---test2---a=%d"%a)

test1()
test2()

此時,對於test1函數,函數體內定義了和所有變量同名的局部變量a,此時會以函數中的變量a爲根據;對於test2函數,函數體內沒有定義和全局變量同名的局部變量,因此若是test2函數使用變量a,則以所有變量a爲根據。運行結果以下:

clipboard.png

(3)修改全局變量


既然是全局變量,就能夠在全部的函數中是,那麼是否能夠修改呢?看以下代碼:

#定義全局變量
a = 100 

def test1():
    global a
    print("---test1--修改前--a=%d"%a)
    a = 200 
    print("---test1--修改後--a=%d"%a)

def test2():
    print("---test2---a=%d"%a)

test1()
test2()

代碼運行結果以下:

clipboard.png

在函數體內利用global這個關鍵字來聲明變量爲全局變量,此時在函數體內對該變量的操做就是至關於對全局變量的操做。

(4)可變類型的全局變量


看下面兩個代碼示例的區別:

#定義全局變量
a = 100 

def test1():
    print("---test1--修改前--a=%d"%a)
    a = 200 
    print("---test1--修改後--a=%d"%a)

def test2():
    print("---test2---a=%d"%a)

test1()
test2()

上述代碼運行結果爲:

clipboard.png

#定義全局變量
a = [11,22,33]

def test1():
    print("---test1--修改前--",a)
    a.append(44)
    print("---test1--修改前--",a)

def test2():
    print("---test2--修改前--",a)

test1()
test2()

上述代碼運行結果爲:

clipboard.png

對於上述兩種狀況,列表(list)、字典(dict)這種可變的類型的全局變量不用再函數體內聲明全局變量,在函數體中對該變量的操做就是在對全局變量進行操做;而像數值類型(int,flaot,bool,long)、字符串(str)、元組(tuple)這種不可變類型的操做,要想在函數體內對這種全局變量進行操做,必須在函數體內聲明其爲全局變量。

(5)總結


  • 在函數外邊定義的變量叫全局變量
  • 全局變量可以在全部的函數中進行訪問
  • 若是在函數中修改全局變量,那麼就須要使用global進行聲明
  • 若是全局變量的名字和局部變量的名字相同,那麼使用的是局部變量的,小技巧強龍不壓地頭蛇
  • 在函數中不使用global聲明全局變量時不能修改全局變量的本質是不能修改全局變量的指向,即不能將全局變量指向新的數據
  • 對於不可變類型的全局變量來講,因其指向的數據不能修改,因此不能使用global時沒法修改全局變量
  • 對於可變類型的全局變量來講,因其指向的數據能夠修改,因此不使用global時也可修改全局變量

4、函數的返回值

「返回值」,就是程序中函數完成一件事情後,最後給調用者返回的結果。

一、帶有返回值的函數

想要在函數中把結果返回給調用者,須要在函數中使用return
以下示例:

def add2num(a, b):
    c = a+b
    return c
或者
def add2num(a, b):
    return a + b

二、保存函數的返回值

在程序中,若是一個函數返回了一個數據,那麼想要用這個數據,就須要用一個變量來保存函數返回的數據。示例以下:

#定義函數
def add2num(a, b):
    return a+b

#調用函數,順便保存函數的返回值
result = add2num(100,98)

#由於result已經保存了add2num的返回值,因此接下來就可使用了
print result

三、Python返回多值
看以下代碼:

def test(a,b):
    sum2 = a + b 
    mulit = a * b 
    return [sum2,mulit]

result = test(2,3)
print(result)

運行結果爲:

[5,6]
def test(a,b):
    sum2 = a + b 
    mulit = a * b 
    return sum2,mulit

result = test(2,3)
print(result)

運行結果爲:

(5,6)

由上述示例咱們能夠得出,當有多個返回值時,利用列表將結果返回,那麼函數就會返回一個列表;當將幾個返回值用逗號隔開返回時,默認返回的是元組。

相關文章
相關標籤/搜索