從定義開始
衆所周知,函數是可以重用的程序段,它們允許你給一塊語句一個名稱,然後你可以在你的程序的任何地方使用這個名稱任意多次地運行這個語句塊。
python的函數是用def關鍵字來定義,主要包括:函數名、函數參數、函數體、函數返回值。
#!/usr/bin/env python
def foo():
return 1
print foo()
以上例子的運行結果爲:
該例子中,函數名爲foo, 我們通過foo()來調用該函數,打印返回值1
函數Scope
python函數運行的時候,會創建自己的scope,即作用域(或者說函數有自己的namespace,即命名空間)。執行函數時,如果在函數體中遇到了變量名,python首先會在該函數的namespace內尋找該變量。
python有一些內置函數,可以讓我們來查看函數的namespaces,下面看一個例子,可以查看函數的local 和global 作用域。
#!/usr/bin/env python
a_string = "This is a global variable"
def foo():
print "locals:"
print locals()
print "globals:"
print globals() # doctest: +ELLIPSIS
foo() # 2
執行結果:
{'foo': <function foo at 0x19c100c8>, '__builtins__': <module '__builtin__' (built-in)>, '__file__': './2.py', 'a_string': 'This is a global variable', '__name__': '__main__', '__package__': None, '__doc__': None}
locals:
{}
可以看到,內建函數globals返回的是一個dict,裏面是全局性的一些變量(注意:我們定義的a_string也在裏面,a_string是在函數外定義的)。代碼裏的#2處,調用了foo函數,裏面的locals函數返回的是函數自己的namespace(foo中沒有定義任何變量,所以是空的)
變量分辨規則
在函數內部也可以訪問global變量。python的作用域規則是:
1. 變量在創建時,local作用域中默認創建的是local變量
2. 在local作用域(scope)中訪問變量時,首先在local作用域中尋找變量,然後在所有外圍作用域中尋找變量。
3. 在local作用域中修改變量時,默認是在local作用域尋找該變量,如果找不到,則新建一個變量。除非聲明要修改的是global變量。
下面的例子是在foo函數裏打印global變量。
#!/usr/bin/env python
a_string = "This is a global variable"
def foo():
print locals()
print a_string #1
foo()
執行結果:
This is a global variable
在foo函數裏,先打印了locals,是空的。然後在#1處,打印a_string這個變量。這時候發生以下事情:
1. python先在locals裏面尋找,locals是空的,所以找不到。
2.python在globals裏面尋找,可以找到a_string,然後獲得值,打印。
再看一個例子:
#!/usr/bin/env python
a_string = "This is a global variable"
def foo():
a_string = "test" #1
print locals()
print a_string #2
def foo1():
global a_string #4
a_string = "Oh. global variable has been changed in foo1." #5
foo()
print a_string #3
print "---------------------"
foo1()
print a_string#6
執行結果爲:
test
This is a global variable
---------------------
Oh. global variable has been changed in foo1.
上面的代碼中,有以下幾個要點:
1. #1是要給a_string賦值(即修改變量值),先在locals中尋找a_tring, 沒有找到,則新創建local變量。所以打印locals時,結果爲:{'a_string': 'test'} 。
2. #2處打印時,按照我們之前說的變量分辨規則, 先從locals中尋找a_tring變量,在#1處有定義,所以直接打印
3.#3處不在任何函數中,位於全局作用域,所以直接查找globals,找到了a_string,打印。
4.#4處聲明瞭一個全局變量(a_string之前已經聲明,這裏表示在local作用域中使用全局a_string)
#5處修改a_string, 因爲#4中聲明瞭a_string是全局的,所以修改a_string之後,#6處打印的是修改後的值
變量生存週期
#!/usr/bin/env python
def foo():
x = 1
foo()
print x # 1
執行結果:
File "./5.py", line 6, in <module>
print x # 1
NameError: name 'x' is not defined
變量都是有生存週期(lifetime)的,變量的生存週期與變量聲明時的作用域息息相關。其作用域銷燬時,變量也就銷燬了。
上面的例子主要有以下要點:
1. x是在foo函數內定義的,在foo的locals中存在,因此,其作用域是foo函數的作用域。
也就是說:foo運行時,locals創建,x位於locals中,結束後,foo的locals被銷燬,x不在了。
2. #1處打印x,#1位於全局作用域,因此,其在globals中尋找x,沒有找到,所以會報錯。
函數參數與參量
函數的參數與參量也可稱爲函數的形參和實參(形參和實參的概念可以諮詢查找學習)
Python中,函數運行時,其參數和參量實際上會成爲local變量,存在於locals中。如下例子:
#!/usr/bin/env python
def foo(x):
print locals()
foo(1)
結果爲:
可以看到,形參x和運行時foo(1)的實參1都成了foo運行時的local變量
python有許多種定義函數形參和實參的方法,這裏我就不具體說了,請參照:
https://docs.python.org/2/tutorial/controlflow.html#more-on-defining-functions
下面我再貼一個例子:
#!/usr/bin/env python
def foo(x, y=0): # 1
return x - y
print foo(3, 1) # 2
print foo(3) # 3
print foo(y=1, x=3) # 4
print foo() # 5
運行結果:
3
2
Traceback (most recent call last):
File "./7.py", line 12, in <module>
print foo() # 5
TypeError: foo() takes at least 1 argument (0 given)
可以看到#1處定義了x和y兩個參數,y給了默認值0.
在函數調用中,#2,#3,#4都是沒有問題的,只有#5報錯了。也就是說:
1. 定義函數參數時,如果沒有給某參數設定默認值,則在調用函數時,必須給該參數設定值。
2. 如果給某參數設定了默認值,則調用函數時,可以給該參數賦值,也可以忽略。
函數基礎大概介紹到這裏,關於嵌套函數、閉包等知識,我在另一個博文中介紹: