真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

func函數(shù)python func函數(shù)用法詳解

Python 里為什么函數(shù)可以返回一個函數(shù)內(nèi)部定義的函數(shù)

“在Python中,函數(shù)本身也是對象”

10年積累的成都網(wǎng)站建設(shè)、做網(wǎng)站經(jīng)驗,可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識你,你也不認(rèn)識我。但先網(wǎng)站設(shè)計后付款的網(wǎng)站建設(shè)流程,更有和田縣免費網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。

這一本質(zhì)。那不妨慢慢來,從最基本的概念開始,討論一下這個問題:

1. Python中一切皆對象

這恐怕是學(xué)習(xí)Python最有用的一句話。想必你已經(jīng)知道Python中的list, tuple, dict等內(nèi)置數(shù)據(jù)結(jié)構(gòu),當(dāng)你執(zhí)行:

alist = [1, 2, 3]

時,你就創(chuàng)建了一個列表對象,并且用alist這個變量引用它:

當(dāng)然你也可以自己定義一個類:

class House(object):

def __init__(self, area, city):

self.area = area

self.city = city

def sell(self, price):

[...] #other code

return price

然后創(chuàng)建一個類的對象:

house = House(200, 'Shanghai')

OK,你立馬就在上海有了一套200平米的房子,它有一些屬性(area, city),和一些方法(__init__, self):

2. 函數(shù)是第一類對象

和list, tuple, dict以及用House創(chuàng)建的對象一樣,當(dāng)你定義一個函數(shù)時,函數(shù)也是對象:

def func(a, b):

return a+b

在全局域,函數(shù)對象被函數(shù)名引用著,它接收兩個參數(shù)a和b,計算這兩個參數(shù)的和作為返回值。

所謂第一類對象,意思是可以用標(biāo)識符給對象命名,并且對象可以被當(dāng)作數(shù)據(jù)處理,例如賦值、作為參數(shù)傳遞給函數(shù),或者作為返回值return 等

因此,你完全可以用其他變量名引用這個函數(shù)對象:

add = func

這樣,你就可以像調(diào)用func(1, 2)一樣,通過新的引用調(diào)用函數(shù)了:

print func(1, 2)

print add(1, 2) #the same as func(1, 2)

或者將函數(shù)對象作為參數(shù),傳遞給另一個函數(shù):

def caller_func(f):

return f(1, 2)

if __name__ == "__main__":

print caller_func(func)

可以看到,

函數(shù)對象func作為參數(shù)傳遞給caller_func函數(shù),傳參過程類似于一個賦值操作f=func;

于是func函數(shù)對象,被caller_func函數(shù)作用域中的局部變量f引用,f實際指向了函數(shù)func;cc

當(dāng)執(zhí)行return f(1, 2)的時候,相當(dāng)于執(zhí)行了return func(1, 2);

因此輸出結(jié)果為3。

3. 函數(shù)對象 vs 函數(shù)調(diào)用

無論是把函數(shù)賦值給新的標(biāo)識符,還是作為參數(shù)傳遞給新的函數(shù),針對的都是函數(shù)對象本身,而不是函數(shù)的調(diào)用。

用一個更加簡單,但從外觀上看,更容易產(chǎn)生混淆的例子來說明這個問題。例如定義了下面這個函數(shù):

def func():

return "hello,world"

然后分別執(zhí)行兩次賦值:

ref1 = func #將函數(shù)對象賦值給ref1

ref2 = func() #調(diào)用函數(shù),將函數(shù)的返回值("hello,world"字符串)賦值給ref2

很多初學(xué)者會混淆這兩種賦值,通過Python內(nèi)建的type函數(shù),可以查看一下這兩次賦值的結(jié)果:

In [4]: type(ref1)

Out[4]: function

In [5]: type(ref2)

Out[5]: str

可以看到,ref1引用了函數(shù)對象本身,而ref2則引用了函數(shù)的返回值。通過內(nèi)建的callable函數(shù),可以進(jìn)一步驗證ref1是可調(diào)用的,而ref2是不可調(diào)用的:

In [9]: callable(ref1)

Out[9]: True

In [10]: callable(ref2)

Out[10]: False

傳參的效果與之類似。

4. 閉包LEGB法則

所謂閉包,就是將組成函數(shù)的語句和這些語句的執(zhí)行環(huán)境打包在一起時,得到的對象

聽上去的確有些復(fù)雜,還是用一個栗子來幫助理解一下。假設(shè)我們在foo.py模塊中做了如下定義:

#foo.py

filename = "foo.py"

def call_func(f):

return f() #如前面介紹的,f引用一個函數(shù)對象,然后調(diào)用它

在另一個func.py模塊中,寫下了這樣的代碼:

#func.py

import foo #導(dǎo)入foo.py

filename = "func.py"

def show_filename():

return "filename: %s" % filename

if __name__ == "__main__":

print foo.call_func(show_filename) #注意:實際發(fā)生調(diào)用的位置,是在foo.call_func函數(shù)中

當(dāng)我們用python func.py命令執(zhí)行func.py時輸出結(jié)果為:

chiyu@chiyu-PC:~$ python func.py

filename:func.py

很顯然show_filename()函數(shù)使用的filename變量的值,是在與它相同環(huán)境(func.py模塊)中定義的那個。盡管foo.py模塊中也定義了同名的filename變量,而且實際調(diào)用show_filename的位置也是在foo.py的call_func內(nèi)部。

而對于嵌套函數(shù),這一機(jī)制則會表現(xiàn)的更加明顯:閉包將會捕捉內(nèi)層函數(shù)執(zhí)行所需的整個環(huán)境:

#enclosed.py

import foo

def wrapper():

filename = "enclosed.py"

def show_filename():

return "filename: %s" % filename

print foo.call_func(show_filename) #輸出:filename: enclosed.py

實際上,每一個函數(shù)對象,都有一個指向了該函數(shù)定義時所在全局名稱空間的__globals__屬性:

#show_filename inside wrapper

#show_filename.__globals__

{

'__builtins__': module '__builtin__' (built-in), #內(nèi)建作用域環(huán)境

'__file__': 'enclosed.py',

'wrapper': function wrapper at 0x7f84768b6578, #直接外圍環(huán)境

'__package__': None,

'__name__': '__main__',

'foo': module 'foo' from '/home/chiyu/foo.pyc', #全局環(huán)境

'__doc__': None

}

當(dāng)代碼執(zhí)行到show_filename中的return "filename: %s" % filename語句時,解析器按照下面的順序查找filename變量:

Local - 本地函數(shù)(show_filename)內(nèi)部,通過任何方式賦值的,而且沒有被global關(guān)鍵字聲明為全局變量的filename變量;

Enclosing - 直接外圍空間(上層函數(shù)wrapper)的本地作用域,查找filename變量(如果有多層嵌套,則由內(nèi)而外逐層查找,直至最外層的函數(shù));

Global - 全局空間(模塊enclosed.py),在模塊頂層賦值的filename變量;

Builtin - 內(nèi)置模塊(__builtin__)中預(yù)定義的變量名中查找filename變量;

在任何一層先找到了符合要求的filename變量,則不再向更外層查找。如果直到Builtin層仍然沒有找到符合要求的變量,則拋出NameError異常。這就是變量名解析的:LEGB法則。

總結(jié):

閉包最重要的使用價值在于:封存函數(shù)執(zhí)行的上下文環(huán)境;

閉包在其捕捉的執(zhí)行環(huán)境(def語句塊所在上下文)中,也遵循LEGB規(guī)則逐層查找,直至找到符合要求的變量,或者拋出異常。

5. 裝飾器語法糖(syntax sugar)

那么閉包和裝飾器又有什么關(guān)系呢?

上文提到閉包的重要特性:封存上下文,這一特性可以巧妙的被用于現(xiàn)有函數(shù)的包裝,從而為現(xiàn)有函數(shù)更加功能。而這就是裝飾器。

還是舉個例子,代碼如下:

#alist = [1, 2, 3, ..., 100] -- 1+2+3+...+100 = 5050

def lazy_sum():

return reduce(lambda x, y: x+y, alist)

我們定義了一個函數(shù)lazy_sum,作用是對alist中的所有元素求和后返回。alist假設(shè)為1到100的整數(shù)列表:

alist = range(1, 101)

但是出于某種原因,我并不想馬上返回計算結(jié)果,而是在之后的某個地方,通過顯示的調(diào)用輸出結(jié)果。于是我用一個wrapper函數(shù)對其進(jìn)行包裝:

def wrapper():

alist = range(1, 101)

def lazy_sum():

return reduce(lambda x, y: x+y, alist)

return lazy_sum

lazy_sum = wrapper() #wrapper() 返回的是lazy_sum函數(shù)對象

if __name__ == "__main__":

lazy_sum() #5050

這是一個典型的Lazy Evaluation的例子。我們知道,一般情況下,局部變量在函數(shù)返回時,就會被垃圾回收器回收,而不能再被使用。但是這里的alist卻沒有,它隨著lazy_sum函數(shù)對象的返回被一并返回了(這個說法不準(zhǔn)確,實際是包含在了lazy_sum的執(zhí)行環(huán)境中,通過__globals__),從而延長了生命周期。

當(dāng)在if語句塊中調(diào)用lazy_sum()的時候,解析器會從上下文中(這里是Enclosing層的wrapper函數(shù)的局部作用域中)找到alist列表,計算結(jié)果,返回5050。

當(dāng)你需要動態(tài)的給已定義的函數(shù)增加功能時,比如:參數(shù)檢查,類似的原理就變得很有用:

def add(a, b):

return a+b

這是很簡單的一個函數(shù):計算a+b的和返回,但我們知道Python是 動態(tài)類型+強(qiáng)類型 的語言,你并不能保證用戶傳入的參數(shù)a和b一定是兩個整型,他有可能傳入了一個整型和一個字符串類型的值:

In [2]: add(1, 2)

Out[2]: 3

In [3]: add(1.2, 3.45)

Out[3]: 4.65

In [4]: add(5, 'hello')

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

TypeError Traceback (most recent call last)

/home/chiyu/ipython-input-4-f2f9e8aa5eae in module()

---- 1 add(5, 'hello')

/home/chiyu/ipython-input-1-02b3d3d6caec in add(a, b)

1 def add(a, b):

---- 2 return a+b

TypeError: unsupported operand type(s) for +: 'int' and 'str'

于是,解析器無情的拋出了一個TypeError異常。

動態(tài)類型:在運行期間確定變量的類型,python確定一個變量的類型是在你第一次給他賦值的時候;

強(qiáng)類型:有強(qiáng)制的類型定義,你有一個整數(shù),除非顯示的類型轉(zhuǎn)換,否則絕不能將它當(dāng)作一個字符串(例如直接嘗試將一個整型和一個字符串做+運算);

因此,為了更加優(yōu)雅的使用add函數(shù),我們需要在執(zhí)行+運算前,對a和b進(jìn)行參數(shù)檢查。這時候裝飾器就顯得非常有用:

import logging

logging.basicConfig(level = logging.INFO)

def add(a, b):

return a + b

def checkParams(fn):

def wrapper(a, b):

if isinstance(a, (int, float)) and isinstance(b, (int, float)): #檢查參數(shù)a和b是否都為整型或浮點型

return fn(a, b) #是則調(diào)用fn(a, b)返回計算結(jié)果

#否則通過logging記錄錯誤信息,并友好退出

logging.warning("variable 'a' and 'b' cannot be added")

return

return wrapper #fn引用add,被封存在閉包的執(zhí)行環(huán)境中返回

if __name__ == "__main__":

#將add函數(shù)對象傳入,fn指向add

#等號左側(cè)的add,指向checkParams的返回值wrapper

add = checkParams(add)

add(3, 'hello') #經(jīng)過類型檢查,不會計算結(jié)果,而是記錄日志并退出

注意checkParams函數(shù):

首先看參數(shù)fn,當(dāng)我們調(diào)用checkParams(add)的時候,它將成為函數(shù)對象add的一個本地(Local)引用;

在checkParams內(nèi)部,我們定義了一個wrapper函數(shù),添加了參數(shù)類型檢查的功能,然后調(diào)用了fn(a, b),根據(jù)LEGB法則,解釋器將搜索幾個作用域,并最終在(Enclosing層)checkParams函數(shù)的本地作用域中找到fn;

注意最后的return wrapper,這將創(chuàng)建一個閉包,fn變量(add函數(shù)對象的一個引用)將會封存在閉包的執(zhí)行環(huán)境中,不會隨著checkParams的返回而被回收;

當(dāng)調(diào)用add = checkParams(add)時,add指向了新的wrapper對象,它添加了參數(shù)檢查和記錄日志的功能,同時又能夠通過封存的fn,繼續(xù)調(diào)用原始的add進(jìn)行+運算。

因此調(diào)用add(3, 'hello')將不會返回計算結(jié)果,而是打印出日志:

chiyu@chiyu-PC:~$ python func.py

WARNING:root:variable 'a' and 'b' cannot be added

有人覺得add = checkParams(add)這樣的寫法未免太過麻煩,于是python提供了一種更優(yōu)雅的寫法,被稱為語法糖:

@checkParams

def add(a, b):

return a + b

這只是一種寫法上的優(yōu)化,解釋器仍然會將它轉(zhuǎn)化為add = checkParams(add)來執(zhí)行。

6. 回歸問題

def addspam(fn):

def new(*args):

print "spam,spam,spam"

return fn(*args)

return new

@addspam

def useful(a,b):

print a**2+b**2

首先看第二段代碼:

@addspam裝飾器,相當(dāng)于執(zhí)行了useful = addspam(useful)。在這里題主有一個理解誤區(qū):傳遞給addspam的參數(shù),是useful這個函數(shù)對象本身,而不是它的一個調(diào)用結(jié)果;

再回到addspam函數(shù)體:

return new 返回一個閉包,fn被封存在閉包的執(zhí)行環(huán)境中,不會隨著addspam函數(shù)的返回被回收;

而fn此時是useful的一個引用,當(dāng)執(zhí)行return fn(*args)時,實際相當(dāng)于執(zhí)行了return useful(*args);

最后附上一張代碼執(zhí)行過程中的引用關(guān)系圖,希望能幫助你理解:

python內(nèi)嵌函數(shù)與閉包里func是不是有位置參數(shù)return func(),沒有位置參數(shù)return func

定義個函數(shù),查看帶括號和不帶括號的type.

def func1():

pass

print(type(func1))

#執(zhí)行結(jié)果:class 'function'

print(type(func1()))

#執(zhí)行結(jié)果:class 'NoneType'

由此可見:

使用return func 時返回的是func 這個函數(shù);

使用return func() 時返回的是func() 執(zhí)行后的返回值,如果func()函數(shù)沒有返回值則返回值為None,

func函數(shù)如果有其他打印語句也會一起執(zhí)行。

Python其實很簡單 第十二章 函數(shù)與變量的作用域

在前面已經(jīng)多次提到函數(shù)這個概念,之所以沒有解釋什么是函數(shù),是因為程序中的函數(shù)和數(shù)學(xué)中的函數(shù)差不多,如input()、range()等都是函數(shù),這些都是Python的標(biāo)準(zhǔn)函數(shù),直接使用就可以了。根據(jù)需要,用戶也可以自定義函數(shù)。

12.1 函數(shù)

函數(shù)的結(jié)構(gòu):

def 函數(shù)名(參數(shù)):

函數(shù)體

return 返回值

例如:數(shù)學(xué)中的函數(shù)f(x)=2x+5在Python中可以定義如下:

def f(x):

y=2*x+5

return(y)

如果x取值為3,可以使用如下語句調(diào)用函數(shù):

f(3)

下面給出完整的程序代碼:

def f(x):

y=2*x+5

return(y)

res=f(3)

print(res)

運行結(jié)果:11

如上例中的x是函數(shù)f(x)的參數(shù),有時也被稱為形式參數(shù)(簡稱形參),在函數(shù)被調(diào)用時,x被具體的值3替換y就是函數(shù)的返回值,這個值3也被稱為實際參數(shù)(簡稱實參)。

上例中的y是函數(shù)f(x)的返回值。并不是所有的函數(shù)都有參數(shù)和返回值。如下面的函數(shù):

def func():

print('此為無參數(shù)傳遞、無返回值的函數(shù)')

func()

輸出結(jié)果:此為無參數(shù)傳遞、無返回值的函數(shù)

可以看出,該函數(shù)func()無參數(shù),故調(diào)用時不用賦給參數(shù)值。

函數(shù)也可以有多個參數(shù),如f(x,y)=x2+y2,可用Python語言定義如下:

def f(x,y):

z=x**2+y**2

return z

print(f(2,3)) #調(diào)用函數(shù)f(x,y)

輸出結(jié)果:13

也可以通過直接給參數(shù)列表中的參數(shù)賦值的方法,為參數(shù)添加默認(rèn)值,如果用戶賦予參數(shù)值,則按照用戶賦值執(zhí)行,否則使用默認(rèn)值。例如:

def f(x,y=3):

z=x**2+y**2

return z

若調(diào)用時參數(shù)列表為(2,1),即x賦值為2,y賦值為1:

print(f(2,1))

輸出結(jié)果為:5

若調(diào)用時參數(shù)列表為(2),即x賦值為2,y賦值省缺,則y使用默認(rèn)值:

print(f(2))

輸出結(jié)果為:13

回調(diào)函數(shù),又稱函數(shù)回調(diào),是將函數(shù)作為另一函數(shù)的參數(shù)。

例如:

def func(fun,m,n):

fun(m,n)

def f_add(m,n):

print('m+n=',m+n)

def f_mult(m,n):

print('m*n=',m*n)

func(f_add,2,3)

func(f_mult,2,3)

輸出結(jié)果:

m+n= 5

m*n= 6

在f_add(m,n)和f_mult(m,n)被定義前,func(fun,m,n)中的fun(m,n)就已經(jīng)調(diào)用了這兩個函數(shù),即“先調(diào)用后定義”,這也是回調(diào)函數(shù)的特點。

如果無法預(yù)知參數(shù)的個數(shù),可以在參數(shù)前面加上*號,這種參數(shù)實際上對應(yīng)元組類型。譬如,參會的人數(shù)事先不能確定,只能根據(jù)與會人員名單輸入:

def func(*names):

print('今天與會人員有:')

for name in names:

print(name)

func('張小兵','陳曉梅','李大海','王長江')

運行后,輸出結(jié)果為:

今天與會人員有:

張小兵

陳曉梅

李大海

王長江

參數(shù)為字典類型,需要在參數(shù)前面加上**號。

def func(**kwargs):

for i in kwargs:

print(i,kwargs[i])

func(a='a1',b='b1',c='c1')

輸出結(jié)果為:

a a1

b b1

c c1

一個有趣的實例:

def func(x,y,z,*args,**kwargs):

print(x,y,z)

print(args)

print(kwargs)

func('a','b','c','Python','is easy',py='python',j='java',ph='php')

輸出結(jié)果:

a b c # 前三個實參賦給前三個形參

('Python', 'is easy') # *args接收元組數(shù)據(jù)

{'py': 'python', 'j': 'java', 'ph': 'php'} # **kwargs接收字典數(shù)據(jù)

12.2 變量的作用域

變量的作用域即變量的有效范圍,可分為全局變量和局部變量。

局部變量

在函數(shù)中定義的變量就是局部變量,局部變量的作用域僅限于函數(shù)內(nèi)部使用。

全局變量

在主程序中定義的變量就是全局變量,但在函數(shù)中用關(guān)鍵字global修飾的變量也可以當(dāng)做全局變量來使用。

全局變量的作用域是整個程序,也就是說,全局變量可以在整個程序中可以訪問。

下面通過實例去討論:

程序1:

a=1 # a為全局變量

def a_add():

print('a的初值:',a) # 在函數(shù)中讀取a的值

a_add() # 調(diào)用函數(shù)a_add()

a+=1 # 主程序語句,a增加1

print('a現(xiàn)在的值是:',a) # 主程序語句,讀取a的值

運行結(jié)果:

a的初值: 1

a現(xiàn)在的值是: 2

這個結(jié)果和我們想象的一樣,全局變量a既可以在主程序中讀取,也可以在子程序(函數(shù))中讀取。

程序2:

a=1

def a_add():

a+=1

print('a的初值:',a)

a_add()

print('a現(xiàn)在的值是:',a)

運行程序1時出現(xiàn)如下錯誤提示:

UnboundLocalError: local variable 'a' referenced before assignment

意思是:局部變量'a'在賦值之前被引用。

從語法上來講,該程序沒有錯誤。首先定義了一個全局變量a并賦值為1,又定義了一個函數(shù)a_add(),函數(shù)內(nèi)的語句a+=1就是出錯的根源,雖然我們的初衷是想讓全局變量a的值增加1,但從錯誤提示看,這個語句中的a并不是全局變量,而是局部變量。看來,在函數(shù)中讀取全局變量的值是沒有問題的(在程序1中已經(jīng)得到了驗證),但要在函數(shù)中改變?nèi)肿兞康闹凳遣恍械模ㄔ诔绦?的錯誤提示a+=1中的a 是局部變量,而非全局變量)。

怎樣解決這個問題?

程序3:

a=1

def a_add(x):

x+=1

return x

print('a的初值:',a)

a=a_add(a)

print('a現(xiàn)在的值是:',a)

運行結(jié)果:

a的初值: 1

a現(xiàn)在的值是: 2

結(jié)果的確是正確的,但在函數(shù)a_add(x)中沒有調(diào)用變量a(沒有出現(xiàn)變量a)。

程序4:

a=1

def a_add(a):

a+=1

return a

print('a的初值:',a)

a=a_add(a)

print('a現(xiàn)在的值是:',a)

運行結(jié)果:

a的初值: 1

a現(xiàn)在的值是: 2

對比程序4和程序3不難發(fā)現(xiàn),其實程序4只是簡單的把函數(shù)的參數(shù)x變成了a,這個a的實質(zhì)和程序3中的x還是一樣的。這進(jìn)一步證實,函數(shù)中的a是局部變量,與主程序的全局變量a有著本質(zhì)的區(qū)別。

程序5:

a=1

def a_add():

global a

a+=1

print('a的初值:',a)

a_add()

print('a現(xiàn)在的值是:',a)

運行結(jié)果:

a的初值: 1

a現(xiàn)在的值是: 2

程序5和程序2相比較,僅僅是在函數(shù)中添加了一個定義“global a”,此時的局部變量a就可以當(dāng)做全局變量使用,由于它和全局變量a同名,自然也就不用區(qū)分a究竟是全局變量還是局部變量了,在主程序和該函數(shù)內(nèi)都可以訪問、修改變量a的值了。

雖然使用global可使變量使用起來非常方便,但也容易引起混淆,故在使用過程中還是謹(jǐn)慎為好。

12.3 函數(shù)的遞歸與嵌套

遞歸,就是函數(shù)調(diào)用它自身。遞歸必須設(shè)置停止條件,否則函數(shù)將無法終止,形成死循環(huán)。

以計算階乘為例:

def func(n):

if n==1:

return 1

else:

return n*func(n-1) #func( )調(diào)用func( )

print(func(5))

運行結(jié)果為:120

嵌套,指在函數(shù)中調(diào)用另外的函數(shù)。這是程序中常見的一種結(jié)構(gòu),在此不再贅述。

匿名函數(shù)

Python中可以在參數(shù)前加上關(guān)鍵字lambda定義一個匿名函數(shù),這樣的函數(shù)一般都屬于“一次性”的。

例如:

程序1:這是一個常規(guī)的函數(shù)定義和調(diào)用。

def f_add(x,y):

return x+y

print(f_add(2,3))

輸出結(jié)果:5

程序2:使用lambda定義匿名函數(shù)。

f_add=lambda x,y:x+y

print(f_add(2,3))

輸出結(jié)果:5

從上面的代碼可以看出,使用lambda僅僅減少了一行代碼。f_add=lambda x,y:x+y中的f_add不是變量名,而是函數(shù)名。程序1和程序2的print( )語句中的參數(shù)都是一樣的——調(diào)用函數(shù)f_add( )。所以,匿名函數(shù)并沒有太多的優(yōu)點。

Python代碼中func(*args, **kwargs)是什么意思

文檔里tutorial里有【貌似在function那節(jié)】

*popenargs意為一般的【表達(dá)無力

:)】參數(shù)

**kwargs意為key=value形式的參數(shù)

比方說:

def

func(*args,

**kwargs):

print

'args:

',

args

print

'kwargs:

',

kwargs

func('a',

'b',

'c',

x='d',

y='e',

z='f')

輸出為:

args:

('a',

'b',

'c')

kwargs:

{'y':

'e',

'x':

'd',

'z':

'f'}

以上

解析Python函數(shù)變量如何使用

剛學(xué)用Python的時候,特別是看一些庫的源碼時,經(jīng)常會看到func(*args, **kwargs)這樣的函數(shù)定義,這個*和**讓人有點費解。其實只要把函數(shù)參數(shù)定義搞清楚了,就不難理解了。

先說說函數(shù)定義,我們都知道,下面的代碼定義了一個函數(shù)funcA

def funcA():

pass

顯然,函數(shù)funcA沒有參數(shù)(同時啥也不干:D)。

下面這個函數(shù)funcB就有兩個參數(shù)了,

def funcB(a, b):

print a

print b

調(diào)用的時候,我們需要使用函數(shù)名,加上圓括號擴(kuò)起來的參數(shù)列表,比如 funcB(100, 99),執(zhí)行結(jié)果是:

100

99

很明顯,參數(shù)的順序和個數(shù)要和函數(shù)定義中一致,如果執(zhí)行funcB(100),Python會報錯的:

TypeError: funcB() takes exactly 2 arguments (1 given)

我們可以在函數(shù)定義中使用參數(shù)默認(rèn)值,比如

def funcC(a, b=0):

print a

print b

在函數(shù)funcC的定義中,參數(shù)b有默認(rèn)值,是一個可選參數(shù),如果我們調(diào)用funcC(100),b會自動賦值為0。

OK,目前為止,我們要定義一個函數(shù)的時候,必須要預(yù)先定義這個函數(shù)需要多少個參數(shù)(或者說可以接受多少個參數(shù))。一般情況下這是沒問題的,但是也有在定義函數(shù)的時候,不能知道參數(shù)個數(shù)的情況(想一想C語言里的printf函數(shù)),在Python里,帶*的參數(shù)就是用來接受可變數(shù)量參數(shù)的。看一個例子

def funcD(a, b, *c):

print a

print b

print "length of c is: %d " % len(c)

print c

調(diào)用funcD(1, 2, 3, 4, 5, 6)結(jié)果是

1

2

length of c is: 4

(3, 4, 5, 6)

我們看到,前面兩個參數(shù)被a、b接受了,剩下的4個參數(shù),全部被c接受了,c在這里是一個tuple。我們在調(diào)用funcD的時候,至少要傳遞2個參數(shù),2個以上的參數(shù),都放到c里了,如果只有兩個參數(shù),那么c就是一個empty tuple。

好了,一顆星我們弄清楚了,下面輪到兩顆星。

上面的例子里,調(diào)用函數(shù)的時候,傳遞的參數(shù)都是根據(jù)位置來跟函數(shù)定義里的參數(shù)表匹配的,比如funcB(100, 99)和funcB(99, 100)的執(zhí)行結(jié)果是不一樣的。在Python里,還支持一種用關(guān)鍵字參數(shù)(keyword argument)調(diào)用函數(shù)的辦法,也就是在調(diào)用函數(shù)的時候,明確指定參數(shù)值付給那個形參。比如還是上面的funcB(a, b),我們通過這兩種方式調(diào)用

funcB(a=100, b=99)

funcB(b=99, a=100)

結(jié)果跟funcB(100, 99)都是一樣的,因為我們在使用關(guān)鍵字參數(shù)調(diào)用的時候,指定了把100賦值給a,99賦值給b。也就是說,關(guān)鍵字參數(shù)可以讓我們在調(diào)用函數(shù)的時候打亂參數(shù)傳遞的順序!

另外,在函數(shù)調(diào)用中,可以混合使用基于位置匹配的參數(shù)和關(guān)鍵字參數(shù),前題是先給出固定位置的參數(shù),比如

def funcE(a, b, c):

print a

print b

print c

調(diào)用funcE(100, 99, 98)和調(diào)用funcE(100, c=98, b=99)的結(jié)果是一樣的。

好了,經(jīng)過以上鋪墊,兩顆星總算可以出場了:

如果一個函數(shù)定義中的最后一個形參有 ** (雙星號)前綴,所有正常形參之外的其他的關(guān)鍵字參數(shù)都將被放置在一個字典中傳遞給函數(shù),比如:

def funcF(a, **b):

print a

for x in b:

print x + ": " + str(b[x])

調(diào)用funcF(100, c='你好', b=200),執(zhí)行結(jié)果

100

c: 你好

b: 200

大家可以看到,b是一個dict對象實例,它接受了關(guān)鍵字參數(shù)b和c。

Python編寫函數(shù)func(x),其功能為判斷x是否為字母,如果x是字母則返回true,否則?

def func(x):

空格try :

空格空格if ord(x)=122 and ord(x)=97 or ord(x)=99 and ord(x)=65:

空格空格空格return True

空格空格else:

空格空格空格return False

空格except :

空格空格print("參數(shù)有誤")


分享題目:func函數(shù)python func函數(shù)用法詳解
文章源于:http://weahome.cn/article/hpjhsh.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部