day10-函數進階

1.函數的命名空間

  命名空間分為三種:

  內置命名空間:

    是python解釋器一啟動就可以使用的名字,存儲在內置命名空間中,啟動解釋器的時候被加載進內存里。比如list,tuple等等。

  全局命名空間:

    是在程序從上到下被執行的過程中依次加載進內存的,放置了我們設置的所有變量名和函數名。

1 a = 1
2 def func():
3     print(a)
4 fun()

  局部命名空間:

    就是函數內部定義的名字,當調用函數的時候 才會產生這個名稱空間 隨着函數執行的結束 這個命名空間就又消失了。

1 def func():
2     a = 1
3     print(a)
4 func()

  在局部:可以使用全局、內置命名空間中的名字。

  在全局:可以使用內置命名空間中的名字,但是不能用局部命名空間中的名字。

  在內置:不能使用局部和全局的名字的。

  注意以下幾點:

  (1)在正常情況下,直接使用內置的名字

  (2)當我們在全局定義了和內置名字空間中同名的名字時,會使用全局的名字

  (3)當在一個函數內,有我要使用的變量名,我就回去使用它,沒有的話,我就會向上級去尋找,找到了就用,找不到就繼續尋找,如果還找不到,就報錯

1 def input():
2     print('input')
3 def func():
4     input()
5 func()
6 # result:input

  (4)多個函數應該擁有多個獨立的局部名字空間,不互相共享,即在函數A中不能使用函數B的局部變量

  (5)函數名()—函數的調用  等價於  函數的內存地址()—函數的調用

1 def input():
2     print('input')
3 def func():
4     print(input)# 這裏輸出的是函數的內存地址---<function input at 0x000001D05CEEC2F0>
5 func()

2.函數的作用域

  全局作用域 —— 作用在全局 —— 內置和全局名字空間中的名字都屬於全局作用域  ——用globals()可以打印出來

  局部作用域 —— 作用在局部 —— 函數(局部名字空間中的名字屬於局部作用域) ——用locals()可以打印出來

 1 a = 1
 2 b = 2
 3 def func():
 4     x = 'aaa'
 5     y = 'bbb'
 6     print(locals())
 7     print(globals())
 8 func()
 9 print(globals())
10 print(locals()) #本地的
11 # result:
12 # {'x': 'aaa', 'y': 'bbb'}
13 # {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000013D05871CF8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/Python/PyChram/WorkPlace/day01/Demo.py', '__cached__': None, 'input': <function input at 0x0000013D058AC2F0>, 'func': <function func at 0x0000013D05A5A8C8>, 'a': 1, 'b': 2}
14 # {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000013D05871CF8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/Python/PyChram/WorkPlace/day01/Demo.py', '__cached__': None, 'input': <function input at 0x0000013D058AC2F0>, 'func': <function func at 0x0000013D05A5A8C8>, 'a': 1, 'b': 2}
15 # {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000013D05871CF8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/Python/PyChram/WorkPlace/day01/Demo.py', '__cached__': None, 'input': <function input at 0x0000013D058AC2F0>, 'func': <function func at 0x0000013D05A5A8C8>, 'a': 1, 'b': 2}

  可以看到,內置函數中的locals打印的就是內置函數中定義的變量,而globals不論在哪裡都打印全局變量,至於函數外的locals,他會將globals看作是一個笨的的變量,所以他打印出來的也是全局的。總結如下:

  (1)globals 永遠打印全局的名字

  (2)locals輸出什麼,根據locals所在的位置

1 a = 1
2 def func():
3     global a
4     a = 2
5 func()
6 print(a)

  在上面代碼中,在函數外,若是想要打印出函數內的變量,只要在函數內對這個變量加上一個global就行了,但是一般不建議這麼做,因為別人看你的代碼時,只會看到你定義的全局變量a = 1,誰會看到你函數內又將他變成了a = 2呢,所以建議不要使用global。

3.函數的嵌套調用

1 def max(a,b):
2     return a if a>b else b
3 def the_max(x,y,z):  #函數的嵌套調用
4     c = max(x,y)
5     return max(c,z)
6 print(the_max(1,2,3))

4.函數的嵌套定義

a = 1
def outer():
    a = 1
    def inner():
        a = 2
        def inner2():
            nonlocal a  #聲明了一個上面第一層局部變量
            a += 1   #不可變數據類型的修改
        inner2()
        print('##a## : ', a)
    inner()
    print('**a** : ',a)

outer()
print('全局 :',a)
# result:
# ##a## :  3
# **a** :  1
# 全局 : 1

  這裏展示的是函數的嵌套定義,同時也展示了nonlocal的使用方法。

  nonlocal可以使內部函數使用外部函數的變量。它的使用規則是找到距離當前函數上面最近一個函數的變量。比如說,nonlocal a,那麼我在上面一個函數上找是否有a,有的話就用它,沒有的話就繼續找,直到有為止。

  nonlocal的聲明,當修改這個變量后,會影響到被找到的那個函數的變量,也就是說,若你在內部函數修改了外部變量,則外部變量也會被修改。

  nonlocal只能作用於局部變量,不能作用於全局變量。

5.函數的返回值

def func():
    print(123)

def wahaha(f):
    f()
    return f           #函數名可以作為函數的返回值
qqxing = wahaha(func)   # 函數名可以作為函數的參數
qqxing()
# result:
# 123
# 123

 6.閉包

  所謂閉包就是內部函數調用外部函數的變量。

def outer():
    a = 1
    def inner():
        print(a)#調用的是外部函數的a,所以這是一個閉包
    print(inner.__closure__)
outer()#(<cell at 0x000001FAA0251918: int object at 0x00007FF96C376290>,)---在這裏打印出來了一個cell什麼的,就說明這個函數是閉包
print(outer.__closure__)#None---這裏輸出為空,說明它不是一個閉包

  閉包的常用形式:

  在這裏說明一下閉包的好處,當使用閉包之後,我就不用每次都去聲明這個a變量,因為使用閉包之後,a就一直存在內存中,不會消失,即大大節省了時間。

def outer():
    a = 1
    def inner():
        print(a)
    return  inner
inn = outer()
inn()

  閉包的簡單用處:

import urllib  #模塊
from urllib.request import urlopen
ret = urlopen('https://www.52pojie.cn/').read()
print(ret)

  上面代碼是獲取一個網頁的源碼。

from urllib.request import urlopen
def get_url():
    url = 'https://www.52pojie.cn/'
    def get():
        ret = urlopen(url).read()
        print(ret)
    return get
get_re = get_url()
get_re()

  使用閉包之後,我就不用每次都去聲明這個url了,因為他一直在內存中,節省了事件。

点赞

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *