1. 程式人生 > >what's the python之函數及裝飾器

what's the python之函數及裝飾器

聲明 做的 運用 本質 修改 忽略 局部變量 即使 實現

what‘s the 函數?

  函數的定義:(return是返回值,可以沒有,不過沒有的話就返回了None)

def wrapper(參數1,參數2,*args,默認參數,**kwargs):
    ‘‘‘註釋:函數功能和參數說明‘‘‘
        函數體
        
        return 返回值

  函數就是將要調用的內容打包裝進def()裏面,在不調用的情況下只讀入內存不執行任何操作,若要調用時再一步一步進行。

  函數的參數:有形參和實參兩種,形參指的是定義時寫在def後面的括號裏,實參指調用時才會用到的代碼的實際的參數,形參就是在定義階段幫實參占位置用的。

形參:

位置形參、默認參數、動態參數、命名關鍵字參數

  位置形參:按照從左到右的順序定義,必須被傳值,多一個不行,少一個不行。(值經常變化時可以將其定義為位置形參)

  默認參數:在定義函數時就已經為形參賦值,調用階段可以不用傳值(值基本不變時可以用默認參數,調用階段就可以忽略不傳值。比如礦工的性別、一個農村小學的學生的籍貫等等)。需要註意的因素:一:必須放在位置形參後面;二:默認參數通常要定義成不可變類型;三:默認參數只在定義階段被賦值一次。

  動態參數:實參的長度不固定是就用動態參數*args*和*kwargs,可以接受任意類型

  命名關鍵字參數:定義在*後的形參,這類形參,必須被傳值,而且要求實參必須是以關鍵字的形式來傳值,如:

def register(*args,name=egon,age):
    print(args)
    print(name)
    print(age)
#
# register(name=‘egon‘,age=18)
register(1,2,2,3,age=10)

形參的定義順序為位置形參,默認參數,*args,命名關鍵字參數,**kwargs


實參:位置實參、關鍵字參數(位置實參必須在關鍵字實參前面)

  位置實參:與位置形參相對應,統稱為位置參數

  關鍵字參數:以key=value的形式指名道姓的傳值,可以不用像位置實參一樣與形參一一對應


what‘s the 命名空間?

命名空間內置命名空間、全局命名空間、局部命名空間

加載順序:內置命名空間(程序運行前加載)->全局命名空間(程序運行中:從上到下加載)->局部命名空間(程序運行中:調用時才加載)

相對應的變量即全局變量和局部變量,局部變量的取值順序為:

          在局部調用:局部命名空間->全局命名空間->內置命名空間;

          在全局調用:全局命名空間->內置命名空間

函數的嵌套:定義的函數中可再定義函數,內部的函數就是嵌套進去的函數,要記住凡是函數都有返回值return

作用域就是作用範圍,按照生效範圍可以分為全局作用域和局部作用域。函數的作用域關系在函數定義階段就已經固定,與調用位置無關,無論函數在何處調用,都需要回到定義階段去找對應的作用域關系

nonlocal關鍵字的運用:

# 1.外部必須有這個變量
# 2.在內部函數聲明nonlocal變量之前不能再出現同名變量
# 3.內部修改這個變量如果想在外部有這個變量的第一層函數中生效
def f1():
    a = 1
    def f2():
        nonlocal a
        a = 2
    f2()
    print(a in f1 : ,a)

f1()

  函數名的本質是函數的內存地址,可以被引用,可以被當作容器類型的元素,可以當作函數的參數和返回值。函數名可以當普通變量使用。

註:

第一類對象(first-class object)指
1.可在運行期創建
2.可用作函數參數或返回值
3.可存入變量的實體。


閉包函數:在函數內部再定義一個函數,該內部函數包含對外部作用域,而不是對全局作用域名字的引用那麽該內部函數就叫閉包函數。(該函數即使不return也算閉包函數)

  閉包函數的特點就是自帶作用於,即始終攜帶其外部作用域的變量,及時在調用時在其外部再設置一個不同值的相同變量也不能改變其攜帶的變量的值。

定義閉包函數的基本形式:

def 外部函數名():
    內部函數需要的變量
    def 內部函數():
        引用外部變量
    return 內部函數

舉個小栗子:

def func():#以下縮進內容就是一個閉包函數
    name=alex
    def bar():
        print(name)
    return bar
b=func()#因為func()return出了bar,所以b就等於bar
b()#這個b()就是bar(),就是一個閉包函數

查看閉包函數的一個方法:print(b.__closure__[0].cell_contents) #如果結果是None,就說明不是閉包函數。

  b就是指閉包,__closure__指查看攜帶的變量的id,[0]指的是攜帶的第一個變量,cell_contents值的是查看攜帶的變量的值。

閉包函數的一個應用就是裝飾器,裝飾器的誕生是因為代碼的修改遵循開放封閉原則——已經實現功能的代碼不能被修改,但是可以被擴展。就是因為不能被修改,所以才有了裝飾器,以起到不修改源代碼的前提下對其效果進行修改的作用。

裝飾器的基本形式:

#裝飾器
def wrapper(func):
    def inner(*args,**kwargs):#定義函數的時候——*參數的聚合
        ret = func(*args,**kwargs)  #調用函數的時候——*參數的打散
        #func是被裝飾的函數,ret是被裝飾函數的返回值
        return ret #把被裝飾的函數的返回值返回給調用者
    return inner

調用裝飾器的方法是在要調用的函數的正上方@裝飾器,該方式名為語法糖。

帶開關的裝飾器:

def outer(flag):
    def timer(func):
        def inner(*args,**kwargs):
            if flag:
                print(‘‘‘執行函數之前要做的‘‘‘)
            re = func(*args,**kwargs)
            if flag:
                print(‘‘‘執行函數之後要做的‘‘‘)
            return re
        return inner
    return timer

@outer(False)#參數是False表示關掉裝飾器,True表示開啟
# 開啟裝飾器就會執行代碼中的中文,也就是執行想要用裝飾器修改原來代碼的功能的部分
def func():
    print(111)

func()

一個函數可以被多個裝飾器裝飾,一個裝飾器可以裝飾多個不同的函數。

當一個函數被多個裝飾器裝飾時,首先要運行最上面的裝飾器,下面舉個小栗子:

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

@wrapper2#裝飾器裝飾了被裝飾過後的函數,所以對這個裝飾器而言下面的都是一個函數,即打印時的順序為最上面的裝飾器先運行
@wrapper1#裝飾器裝飾了f()
def f():
    print(in f)

f()
‘‘‘
打印結果為
wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func
‘‘‘

what's the python之函數及裝飾器