1. 程式人生 > >Python函數知識點總結

Python函數知識點總結

每次 指定 定義函數 關鍵字參數 錯誤 改變 對象實例 ber ont

1.函數的定義
2.如何定義一個函數以及函數語法
3.函數的調用
4.函數的參數(形參,實參)以及參數的傳遞
5.函數的返回值
6.變量的作用域
7.匿名函數
8.嵌套函數和閉包
9.裝飾器

1.函數的定義

函數是組織好的,可重復使用的,用來實現一定功能的代碼段。
函數能提高應用的模塊性,和代碼的重復利用率。

2.如何定義一個函數以及函數語法

函數代碼塊以def關鍵詞開頭,後接函數名稱和圓括號()
傳入的任何參數和自變量放在圓括號()中間
函數的內容以冒號起始,並且縮進
函數的第一行語句可以選擇性的使用文檔字符串————用於存放函數說明
return 【表達式】結束函數,選擇性的返回一個值給調用方。不帶表達式的return相當於返回None
語法:

def function_name(parameters):
    ‘‘‘函數說明‘‘‘
    function_suite
    return [expression]

實例:

def print_test(str_par):
    ‘‘‘打印輸入的字符串到標準顯示設備上‘‘‘
    print(str_par)
    return
print_test(test_success)

3.函數的調用

定義一個函數只給了函數一個名稱,指定了函數裏包含的參數和代碼塊結構。
這個函數的基本結構完成以後,你可以通過另一個函數調用執行,也可以直接從Python提示符執行。
實例:

#
!/usr/bin/python #-*- coding:UTF-8 -*- #定義函數 def print_test(str_par): ‘‘‘打印輸入的字符串到標準顯示設備上‘‘‘ print(str_par) return #調用函數 print_test(test_success)

4.函數的參數(形參,實參)以及參數的傳遞

在python中,類型屬於對象,變量是沒有類型的。
a = [1,2,3]
a = "hello,world"
以上代碼中,[1,2,3]是list類型,"hello world"是string類型,而變量a是沒有類型,她僅僅是一個對象的引用(一個指針),可以是list類型對象,也可以指定string類型對象

可更改(mutable)和不可更改(immutable)對象
在python中,string,tuple,number是不可更改的對象,而list,dict等則是可以修改的對象。
1.不可變類型:變量賦值a = 5後在賦值a = 10,這裏實際是新生成一個int值對象10,在讓a指向它,而5被丟棄,不是改變a的值,相當於新生成了a。
2.可變類型:變量賦值list_a = [1,2,3,4]後在賦值list_a[2] = 5則是將list list_a的第三個元素值更改,本身list_a沒有動,只是其內部的一部分值被修改了。

python函數的參數傳遞:
1.不可變類型:如整數、字符串、元祖。如fun(a),傳遞的只是a的值,沒有影響a對象本身。比如在fun(a)內部修改a的值,只是修改另一個復制的對象,不會影響a本身。
2.可變類型:如列表,字典。如fun(list_a),則是將list_a真正的傳過去,修改後fun外部的list_a也會受影響。

python中一切都是對象,嚴格意義我們不能說值傳遞還是引用傳遞,我們應該說傳不可變對象和傳可變對象。

python傳不可變對象實例:

#!/usr/bin/python
#-*- coding:UTF-8 -*-
def ChangeInt(a):
    a = 10

b = 2
ChangeInt(b)
print(b)  #結果是2

實例中有int對象2,指向它的變量是b,在傳遞給ChangeInt函數時,按傳值的方式復制了變量b,a 和b都指向了同一個int對象,在a = 10時,則新生成一個int值對象10,並讓a指向它。


傳可變對象實例

#!/usr/bin/python
#-*- encoding:UTF-8 -*-

def ChangeList(mylist):
    "修改傳入的列表“
    mylist.append([1,2,3,4]);
    print(函數內部取值:’,mylist)
    return

#調用Changelist函數
mylist = [10,20,30]
ChangeList(mylist)
print(函數外取值:‘,mylist)

實例中傳入函數的和在末尾添加新內容的對象用的是同一個引用,故輸出結果如下:

函數內取值:[10,20,30,[1,2,3,4]]
函數外取值:[10,20,30,[1,2,3,4]]

實參和形參
形參:定義函數時接收的參數
形參類型:位置參數,動態*args參數,默認參數,動態**kwargs參數

位置參數:位置參數必須以正確的順序傳入函數。調用時的數量必須和聲明時的一樣。

調用test()函數時,你必選傳入一個參數,不然會出現語法錯誤:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
 

def test( a ):
   "打印任何傳入的字符串"
   print(a);
   return;
 
#調用test函數
test();
以上實例輸出結果:
Traceback (most recent call last):
  File "test.py", line 11, in <module>
    printme();
TypeError: printme() takes exactly 1 argument (0 given)

關鍵字參數:
關鍵字參數和函數調用關系緊密,函數調用使用關鍵字參數來確認傳入的參數值。
使用關鍵字參數允許函數調用時參數的順序與聲明時不一致,因為python解釋器能夠用參數名匹配參數值。
以下實例在函數test()調用時使用參數名:

#!/usr/bin/python
#-*- coding:UTF-8 -*-

def test(a ,b ):
    print(a)
    rerurn
print(test(a = 2,b = 2)

默認參數:
調用函數時,默認參數的值如果沒有傳入,則被認為是默認值。下列會打印默認的age,即是沒有傳入age的參數:

#!/usr/bin/python
#-*- coding:UTF-8 -*-
def test(name,age = 20):
    print(name,age)
    return
test(age = 22,name = jack)
test(name = jack)

動態參數:
你可能需要一個函數能夠處理比當初生命是更多的參數。這些參數叫做不定長參數
語法如下:

def function_name(*args,**kwargs):
    function_suite
    return[expression]

加了星號(*)的變量名會存放所有未命名的變量參數。返回為元祖數據類型
加了兩個星號(**)的變量名會存放所有關鍵字參數。返回為字典數據類型


參數定義順序:位置參數->*args->默認參數->**kwargs

實參:函數調用時傳遞的參數
實參類型:位置參數,關鍵字參數
位置參數:必須和函數定義時的參數一對一對應
關鍵字參數:可以通過*[],*()一次性傳遞多個參數給*args;通過**{}一次性傳遞多個參數給**kwargs參數

5.函數的返回值

return語句【表達式】退出函數(結束一個函數的執行),選擇性地向調用方返回一個表達式。
返回值可以是任意數據類型
返回值情況:
1,返回值為None的情況
當不寫return時,默認返回值為None
return不加參數時,返回None
2,返回值不為None的情況
返回一個值: return xxx 返回一個值(一個變量) 任意數據類型
返回多個值: return a,b,[1,2,3] ; 用一個變量接收時返回的是一個元祖,也可以用相應數量的變量去接收

6.變量的作用域

一個程序的所有變量並不是在哪個位置都可以訪問的。訪問權限決定於這個變量實在哪裏賦值的。
命名空間:
局部命名空間
全局命名空間
內置命名空間

定義在函數內部的變量擁有一個局部作用域,定義在函數外的擁有全局作用域。
局部變量只能在其被聲明的函數內部訪問,而全局變量可以在整個程序範圍內訪問。調用函數時,所有在函數內聲明的變量名稱都將被加入到作用域中。如下實例:

#!/usr/bin/python
#-*- coding:UTF-8 -*-
total = 0 # 這是一個全局變量
def sum(arg1,arg2):
    ‘‘‘返回2個參數的和‘‘‘
    total1 = arg1 + arg2   #total在這裏局部變量
    print(函數內是局部變量:,total)
    return(total)
#調用sum函數
sum(10,20);
print(函數外是全局變量:’,total)

#輸入結果
函數內是局部變量:30
函數外是全局變量:0

變量查找順序:先查找全局作用域,然後內置作用域
global關鍵字:可以是在函數內部聲明的變量變成全局變量
nonlocal關鍵字:可以讓內部函數中的變量在上一層函數中生效,外部必須要有這個變量

#!/usr/bin/python
# -*- coding: UTF-8 -*-

globvar = 0

def set_globvar_to_one():
    global globvar    # 使用 global 聲明全局變量
    globvar = 1

def print_globvar():
    print(globvar)     # 沒有使用 global

set_globvar_to_one()
print  globvar        # 輸出 1
print_globvar()       # 輸出 1,函數內的 globvar 已經是全局變量

7.匿名函數

python使用lambda來創建匿名函數。
1.lambda只是一個表達式,函數體比def簡單很多。
2.lambda的主題式一個表達式,而不是一個代碼塊。僅僅能在lambda表達式中封裝有限的邏輯進去。
3.lambda函數擁有自己的命名空間,且不能訪問只有參數列表之外或全局命名空間裏的參數
4.雖然lambda函數看起來只能寫一行,卻不等同於C或C++的內聯函數,後者的目的是調用小函數時不占用棧內存從而增加運行效率

語法:lambda函數的語法只能包含一個語句,如下:

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

如下實例:
#!/usr/bin/python
#-*- coding:UTF-8 -*-
sum = lambda arg1,arg2:arg1 + arg2;
print(相加後的值為:‘,sum(10,20)
print(相加後的值為:‘,sum(20,20)

以上實例輸出結果:
相加後的值為:30
相加後的值為:40

8.嵌套函數和閉包

在一個函數內部定義函數就創建了嵌套函數,如下所示:

def outer():
    outer_var = outer variable
    def inner():
        return outer_var
    return innter

在這種類型的函數定義中,函數inner只在函數outer內部有效,所以當內部函數需要被返回(移動到外部作用範圍)或被傳遞給另一個函數時,使用嵌套函數通常比較方便。在如在上面的嵌套函數中,每次調用外部函數時都會創建一個新的嵌套函數實例,這是因為,在每次執行外部函數時,都會執行一次內部函數定義,而其函數體則不會被執行。

嵌套函數可以訪問創建它的環境,這是python函數定義語句的直接結果。一個結果是,外部函數中定義的變量可以在內部函數用引用,即是外部函數已經執行結束。

ef outer():
    outer_var = "outer variable"
    def inner():
        return outer_var
    return inner
 
>>> x = outer()
>>> x
<function inner at 0x0273BCF0>
>>> x()
outer variable

當內部嵌套的函數引用外部函數中的變量時,我們說嵌套函數相對於引用變量時封閉的。我們可以使用函數對象的一個特殊屬性’_closure_‘來訪問這個封閉的變量,如下所示:

>>>cl = x.__closure__
>>>cl
(<cell at 0x029E4470:str object at 0x02A0FD90,)
>>>cl[0].cell_contents
outer variable

python中的閉包有一個古怪的行為。在python2.x以及更低版本中,指向不可變類型(例如字符串和數字)的變量不能再閉包內反彈。

def counter():
    count = 0
    def c():
        count += 1
        return count
    return c
 
>>> c = counter()
>>> c()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in c
UnboundLocalError: local variable count referenced before assignment

一個相當不可靠的解決方案是,使用一個可變類型來捕獲閉包,如下所示:

def counter():
    count = [0]
    def c():
        count[0] += 1
        return count[0]
    return c
 
>>> c = counter()
>>> c()
1
>>> c()
2
>>> c()
3

python3引入了nonlocal關鍵字用來解決下面所示的閉包範圍問題。

def counter():
       count = 0
       def c():
           nonlocal count
           count += 1
           return count
        return c

閉包可以用來維持狀態(與類的作用不同),在一些簡單的情況下,還可以提供一種簡潔性與可讀性比類更強的解決方案

9.裝飾器

裝飾器的本質:是一個閉包函數
裝飾器的功能:在不修改原函數及其調用方式的情況下對原函數功能進行擴展

裝飾器結構:

import time
def timer(func):
    def inner():
        start = time.time()
        func()
        print(time.time() - start)
    return inner

@timer   #==> func1 = timer(func1)
def func1():
    print(in func1)


func1()

帶參數的裝飾器:

def timer(func):
    def inner(a):
        start = time.time()
        func(a)
        print(time.time() - start)
    return inner

@timer
def func1(a):
    print(a)

func1(1)

帶多個參數的裝飾器:

import time
def timer(func):
    def inner(*args,**kwargs):
        start = time.time()
        re = func(*args,**kwargs)
        print(time.time() - start)
        return re
    return inner

@timer   #==> func1 = timer(func1)
def func1(a,b):
    print(in func1)

@timer   #==> func2 = timer(func2)
def func2(a):
    print(in func2 and get a:%s%(a))
    return fun2 over

func1(aaaaaa,bbbbbb)
print(func2(aaaaaa))

帶返回值的裝飾器:

import time
def timer(func):
    def inner(*args,**kwargs):
        start = time.time()
        re = func(*args,**kwargs)
        print(time.time() - start)
        return re
    return inner

@timer   #==> func2 = timer(func2)
def func2(a):
    print(in func2 and get a:%s%(a))
    return fun2 over

func2(aaaaaa,bbbbbb)
print(func2(aaaaaa))

多個裝飾器裝飾一個函數:

def wrapper1(func):
    def inner():
        print(wrapper1 ,before func)
        func()
        print(wrapper1 ,after func)
    return inner

def wrapper2(func):
    def inner():
        print(wrapper2 ,before func)
        func()
        print(wrapper2 ,after func)
    return inner

@wrapper1     #f = wrapper1(f) ---> wrapper1(wrapper2(f)
@wrapper2     #f = wrapper2(f)
def f():
    print(in f)
f()

執行結果:
wrapper1 ,before func
wrapper2 ,before func
in f
wrapper2 ,after func
wrapper1 ,after func

帶參數的裝飾器:

F = True          #stpe1 裝飾器的開關變量
def outer(flag):  #step 2
    def wrapper(func): #step 4
        def inner(*args,**kwargs): #stpe 6
            if flag:               #step 9
                print(before)   #step 10
                ret = func(*args,**kwargs)  #step 11  執行原函數
                print(after)             #step13
            else:
                ret = func(*args,**kwargs)
                print(123)
            return ret                     #step 14
        return inner    #step 7
    return wrapper     #step 5

@outer(F)   #先執行step 3 :outer(True)這個函數,然後step 6:@wrapper   #此處把開關參數傳遞給裝飾器函數
def hahaha():
    pass    #step 12
hahaha()    # step 8    相當於inner()

Python函數知識點總結