week04_python函數返回值、作用域

函數的返回值:

  Python函數使用return語句返回"返回值"

  所有函數都有返回值,如果沒有return語句,隱式調用return None

  return語句並不一定是函數的語句塊的最後一條語句

  一個函數可以存在多個return語句,但是隻有一條可以被執行;如果沒有一條return語句被執行到,

隱式調用return None

  如果有必要,可以顯示調用return None,可以簡寫return

  如果函數被掃行了return語句,函數就會返回,當前被執行的return語句之後的其它語句就不會被執行了

  作用:結束函數調用、返回值


舉例:

def showplus(x):
    print(x)
    return x + 1
    return x + 2

print(showplus(5))# 只執行第一條return

def guess(x):
    if x > 3:
        return "> 3"
    else:
        return "<= 3"

print(guess(2))# 條件滿足,只執行其中一條return


def fn(x):
    for i in range(x):
        if i > 3:
            return i
        else:
            print("{} is not greater than 3".format(i))

print(fn(5))# 打印什麼?
print(fn(3))# 打印什麼?


函數不能同時返回多個值:

def showlist():
    return [1, 3, 5]

print(showlist()) #[1, 3, 5] 指明返回一個列表,是一個列表對象

def showlist():
    return 1, 3, 5

print(showlist()) #(1, 3, 5) 看似返回多個值,隱式被python封裝成了一個元組


函數的嵌套:

  在一個函數中定義了另一個函數

def outer():
    def inner():
        print("inner")
    print("outer")

outer()# outer
inner()# NameError: name 'inner' is not defined

函數有可見範圍,這就是作用域的概念;

內部函數不能被外部直接使用,會拋NameError異常;



作用域###

  一個標識符的可見範圍,這就是標識符的作用域。一般常說的是變量的作用域

對比一下,下面2個函數,x到底是可見還是不可見?

(1)
x = 5

def foo():
    print(x)

foo()# 5


(2)
x = 5

def foo():
    x += 1
    print(x)


foo()# UnboundLocalError: local variable 'x' referenced before assignment

全局作用域

  在整個程序運行環境中都可見;

局部作用域

  在函數、類等內部可見;

  局部變量使用範圍不能超過其所在的的局部作用域;

def fn1():
    x = 1 # 局部作用域,在fn1內

def fn2():
    print(x)# x可見嗎?

print(x)# x可見嗎?

嵌套結構:

對比下面兩個代碼中變量o的差別:
(1).

def outer1():
    o = 65
    def inner():
        print("inner {}".format(o))
        print(chr(o))
    print("outer {}".format(o))
    inner()

outer1()

(2).

def outer2():
    o = 65
    def inner():
        o = 97
        print("inner {}".format(o))
        print(chr(o))
    print("outer {}".format(o))
    inner()

outer2()

從上面的例子中可以看出:

  外層變量作用域在內層作用域可見

  內層作用域inner中,如果定義了o = 97 ,相當於當前作用域中重新定義了一個新的變量o,但是

這個o並沒有覆蓋外層作用域outer中的o

x = 5
def foo():
    # y = x + 1
    x += 1# UnboundLocalError: local variable 'x' referenced before assignment
    print(x)
foo()

x += 1 其實是 x = x + 1
相當於在foo內部定義一個局部變量x,那麼foo內部所有x都是這個局部變量了;
但是這個x還沒有完全賦值,就被右邊拿來做加1操作了;
該如何解決???

全局變量global

x = 5
def foo():
    global x
    x += 1
    print(x)

foo()

使用global關鍵字的變量,將foo內的x聲明爲使用外部的全局作用域中定義的x; 
全局作用域中必須有x的定義
如果全局作用域中沒有x定義會怎麼樣???
x = 5

def foo():
    global x
    x = 10
    x += 1# 會報錯嗎?
    print(x)# 打印什麼?

print(x)
foo()

使用global關鍵字的變量,將foo內的x聲明爲使用外部的全局作用域中定義的x; 

但是,x = 10 賦值即定義,x在內部作用域爲一個外部作用域的變量賦值,所以x += 1不會報錯。 

注意:這裏x的作用域還是全局的;


global總結:

  x += 1這種是特殊形式產生的錯誤的原因?先引用後賦值,而python動態語言是賦值和算定義;

  才能被引用。解決方法,在這條語句前增加x = 0之類的賦值語句,或者使用global告訴內部作

  用域,去全局作用域查找變量定義;

  內部作用域使用x = 5之類的賦值語句會重新定義局部作用域使用的變量x,但是,一旦這個作用

  域中使用global聲明x爲全局的,那麼x = 5相當於在爲全局作用域的變量x賦值;


global使用原則:

  外部作用域變量會內部作用域可見,但也不要在這個內部的局部作用域中直接使用,因爲

  函數的目的就是爲了封裝,儘量與外界隔離;

  如果函數需要使用外部全局變量,請使用函數的形參傳參解決;

  一句話:不用global。學習它就是爲了深入理解變量的作用域;




閉包#

  自由變量:未在本地作用域中定義的變量。例如定義在內存函數外的外層函數的作用域中的變量;

  閉包:就是一個概念,出現在嵌套函數中,指的是內層函數引用到了外層函數的自由變量,就形成

了閉包。很多語言都有這個概念,最熟悉就是JavaScript

def counter():
    c = [0]
    def inc():
        c[0] += 1
        return c[0]
    return inc

foo = counter()
print(foo(), foo())
c = 100
print(foo())

代碼解析:

  第4行不會報錯,因爲c已經在counter函數中定義過了。而inc中的使用方式是爲c的元素修改值,而不是重新定義。

  第8行 會打印 1 2

  第10行會打印 3

  第9行的c和counter中的c不一樣,而inc引用的是自由變量正式counter的變量c; 

這就是python2中實現閉包的方式,python3還可以使用nonlocal關鍵字



nonlocal關鍵字

  使用nonlocal關鍵字,將變量標記爲不在本地作用域定義,而是上級的某一級局部作用域中定義,但不能是

全局作用域中定義

def counter():
    count = 0
    def inc():
        nonlocal count
        count += 1
        return count
    return inc
foo = counter()
print(foo())
print(foo())

代碼解析:

  count是外層函數的局部變量,被內部函數引用;

  內部函數使用nonlocal關鍵字聲明count變量在上級作用域而非本地作用域中定義;

  代碼可以正常使用,且形成閉包;




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章