函數對象、名稱空間和作用域、閉包函數、裝飾器

一、函數對象:
  函數名就相當於變量名,把函數的內存地址當作一種變量值(一種數據類型)去使用
  在面向對象編程中,一切皆對象
  具體的體現:
    1.函數可以被引用
    2.函數可以作爲函數的參數
    3.函數可以作爲函數的返回值
    4.函數可以存儲到容器類型中

二、函數嵌套:
  1.嵌套定義
  def outer():
    def inner():
    pass
  2. 嵌套調用
  def max2(x, y):
    if x > y:
      return x
    else:
      return y

  def max4(a, b, c, d):
    res1 = max2(a.b)
    res2 = max2(res1, c)
    res3 = max2(res2, d)
    return res3

三、名稱空間和作用域
名稱空間:
  1.什麼是名稱空間:
    存放名字與值內存地址綁定關係的地方
    x=10
    x:10的內存地址

  2.爲什麼要有名稱空間:

  3.如何用內存空間:
    內置名稱空間:存放py解釋器自帶的函數名稱
      parcharm解釋器啓動時創建,關閉解釋器時銷燬

    全局名稱空間:文件級別的名稱:除了內置名稱和函數內名稱,其餘都是全局名稱
      運行文件時創建,所有文件運行結束或者中途刪除時銷燬

    局部名稱空間:函數內定義的名稱
      調用函數時創建,函數執行完畢銷燬

    查找名稱順序:
      1.查找名字的順序是從當前位置往外查找
      2.名稱空間的嵌套關係是在函數定義階段就固定死的,與調用的位置沒關係
      函數的作用域在定義時就固定了,與調用的位置沒關係

    名稱空間的加載順序:
      內置>全局>局部
    名稱空間的查找順序:
      局部>全局>內置 (不能反着找)

作用域:
  域指的是區域、範圍
    即全局範圍:全局存活 全局有效
    無論在任何位置都能看的到

  全局的名稱空間和內置的名稱空間 在使用上沒什麼區別
  局部的和全局的內置的 就有區別了 局部定義的只能在局部使用

  全局的 和 內置的可以劃分爲同一個範圍
  global 表示的是全局範圍 就是所謂的全局作用域

  局部的單獨一個範圍
  local 局部作用域

  globals() 查看全局作用域中的內容
  locals()查看局部作用域中的內容 (相對局部,站在什麼位置看就是哪個局部,
    比如你在全局作用域中使用locals,看到的就是全局作用域的內容)

 


四、閉包函數:

  1.什麼是閉包函數
    閉函數:該函數一定是定義在函數內的函數
    包函數:該內部函數包含對外層函數作用域名字的引用

  2.爲何要用閉包函數
    傳值

  3.如何用
  爲函數體傳值的方案一:直接參數傳
  def f():
    print(x)

  爲函數體傳值的方案二:閉包傳值
  def outer(x):
    def f():
      print(x)
    return f

  f1 = outer(10)
  f2 = outer(11)

  f1()

  f2()

五、裝飾器
  1.什麼是裝飾器
    裝飾器指的是爲被裝飾對象添加新功能的工具
    裝飾器本身可以是任意可調用的對象
    被裝飾對象本身也可以是任意可調用對象

  2.爲何要用裝飾器
    開放封閉原則:對修改封閉,對擴展開放

    裝飾器的原則:
      1.不能修改被裝飾對象的源代碼
      2.不能修改被裝飾對象的調用方式

    裝飾器的目的:
      就是在遵循原則1和2的前提下,爲被裝飾對象添加新功能

  3.如何用

    1.源函數
    def index():
      time.sleep(1)
      print('welcome to index page')

    2.添加功能
    import time
    def index():
      time.sleep(1)
      print('welcome to index page')

    def outer(func):
      # func=最原始那個index的內存地址
      def wrapper(*args,**kwargs):
        start_time = time.time()
        res=func(*args,**kwargs):#最原始那個index的內存地址
        end_time = time.time()
        print('time is %s' %(end_time - start_time))
        return res
      return wrapper

    index=outer(index) #index=outer(最原始那個index的內存地址) index=wrapper的內存地址
    index() #wrapper的內存地址()
        # 偷樑換柱 用戶並不知道

    3.語法糖
    import time
    def outer(func):
      # func=最原始那個index的內存地址
      def wrapper(*args,**kwargs):
        start_time = time.time()
        res=func(*args,**kwargs):#最原始那個index的內存地址
        end_time = time.time()
        print('time is %s' %(end_time - start_time))
        return res
        return wrapper

      @outer #index=outter(index)
      def index():
        time.sleep(1)
        print('welcome to index page')
      index()

    總結:

      要寫一個裝飾器,先定義一個新函數例如def inner():,寫要添加的功能,寫好之後打包。

      所謂打包其實有固定的套路,在新函數同級頭下寫return inner,在新函數同級頭上寫參數func=index(index爲源函數名)

      定義一個外函數def outer():,將寫好的新函數上下三行,統一縮進,打包進外函數內。就可以了

      使用語法糖,調用裝飾器運行源函數即可。

 

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