国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

帶你了解python裝飾器

2020-01-04 17:20:45
字體:
來源:轉載
供稿:網友

1.作用域

 在python中,作用域分為兩種:全局作用域和局部作用域。

 全局作用域是定義在文件級別的變量,函數名。而局部作用域,則是定義函數內部。

 關于作用域,我要理解兩點:a.在全局不能訪問到局部定義的變量 b.在局部能夠訪問到全局定義的變量,但是不能修改全局定義的變量(當然有方法可以修改)

 下面我們來看看下面實例:

x = 1def funx():  x = 10  print(x) # 打印出10funx()print(x) # 打印出1

  如果局部沒有定義變量x,那么函數內部會從內往外開始查找x,如果沒有找到,就會報錯

x = 1def funx():  print(x) # 打印出1funx()print(x) # 打印出1x = 1def funx():  def func1():    print(x) # 打印出1  func1()funx()print(x) # 打印出1

  因此,關于作用域的問題,只需要記住兩點就行:全局變量能夠被文件任何地方引用,但修改只能在全局進行操作;如果局部沒有找到所需的變量,就會往外進行查找,沒有找到就會報錯。

2.高級函數

 我們知道,函數名其實就是指向一段內存空間的地址,既然是地址,那么我們可以利用這種特性來。

 a函數名可以作為一個值

def delete(ps):  import os  filename = ps[-1]  delelemetns = ps[1]  with open(filename, encoding='utf-8') as f_read,/    open('tmp.txt', 'w', encoding='utf-8') as f_write:    for line in iter(f_read.readline, ''):      if line != '/n': # 處理非空行        if delelemetns in line:          line = line.replace(delelemetns,'')        f_write.write(line)  os.remove(filename)  os.rename('tmp.txt',filename)def add(ps):  filename = ps[-1]  addelemetns = ps[1]  with open(filename, 'a', encoding='utf-8') as fp:    fp.write("/n", addelemetns)def modify(ps):  import os  filename = ps[-1]  modify_elemetns = ps[1]  with open(filename, encoding='utf-8') as f_read, /      open('tmp.txt', 'w', encoding='utf-8') as f_write:    for line in iter(f_read.readline, ''):      if line != '/n': # 處理非空行        if modify_elemetns in line:          line = line.replace(modify_elemetns, '')        f_write.write(line)  os.remove(filename)  os.rename('tmp.txt', filename)def search(cmd):  filename = cmd[-1]  pattern = cmd[1]  with open(filename, 'r', encoding="utf-8") as f:    for line in f:      if pattern in line:        print(line, end="")    else:      print("沒有找到")dic_func ={'delete': delete, 'add': add, 'modify': modify, 'search': search}while True:  inp = input("請輸入您要進行的操作:").strip()  if not inp:    continue  cmd_1 = inp.split()  cmd = cmd_1[0]  if cmd in dic_func:    dic_func[cmd](cmd_1)  else:    print("Error")

 b.函數名可以作為返回值

def outer():  def inner():    pass  return inners = outer()print(s)######輸出結果為#######<function outer.<locals>.inner at 0x000000D22D8AB8C8>

 c..函數名可以作為一個參數

def index():  print("index func")def outer(index):  s = index  s()  outer(index)######輸出結果#########index func

 所以滿足上面兩個條件中的一個,都可以稱為高級函數.

3.閉包函數

  閉包函數必須滿足兩個條件:1.函數內部定義的函數 2.包含對外部作用域而非全局作用域的引用

  下面通過一些實例來說明閉包函數:

  實例一:以下僅僅在函數內部定義了一個函數,但并非閉包函數.

def outer():  def inner():    print("inner func excuted")  inner() # 調用執行inner()函數  print("outer func excuted")outer() # 調用執行outer函數####輸出結果為##########inner func excutedouter func excuted

  實例二:以下在函數內部定義了一個函數,而且還引用了一個外部變量x,那么這個是閉包函數么?答案:不是

x = 1def outer():  def inner():    print("x=%s" %x) # 引用了一個非inner函數內部的變量    print("inner func excuted")  inner() # 執行inner函數  print("outer func excuted")outer()#####輸出結果########x=1inner func excutedouter func excuted

  在回頭來看看對閉包函數的定義,是不是兩條都滿足?聰明的你,一定發現不滿足第二條.對,這里的變量x,是屬于全局變量,而非外部作用于域的變量。再來看看下面例子:

def outer():  x = 1  def inner():    print("x=%s" %x)    print("inner func excuted")  inner()  print("outer func excuted")outer()#####輸出結果#########x=1inner func excutedouter func excuted

  顯然,上面實例滿足閉包函數的條件。現在,你應該清楚,作為一個閉包函數,必須得滿足上述的兩個條件,缺一不可。但是,一般情況下,我們都會給閉包函數返回一個值.這里先不說為什么.在接下來的內容中,你會看到這個返回值的用途.

def outer():  x = 1  def inner():    print("x=%s" %x)    print("inner func excuted")  print("outer func excuted")  return inner # 返回內部函數名  outer()

  現在我們來抽象的定義一下閉包函數。它是函數和與其相關的引用環境組合而成的實體。在實現深約束時,需要創建一個能顯式表示引用環境的東西,并將它與相關的子程序捆綁在一起,這樣捆綁起成為閉包。在上面實例中,我們可以發現,閉包函數,它必須包含自己的函數以及一個外部變量才能真正稱得上是一個閉包函數。如果沒有一個外部變量與其綁定,那么這個函數不能算得上是閉包函數。

  那么怎么知道一個閉包函數有多少個外部引用變量呢?看看下面代碼.

def outer():  x = 1  y = 2  def inner():    print("x= %s" %x)    print("y= %s" %y)  print(inner.__closure__)  return innerouter()######輸出結果#######(<cell at 0x000000DF9EA965B8: int object at 0x000000006FC2B440>, <cell at 0x000000DF9EA965E8: int object at 0x000000006FC2B460>)

  結果表明,在inner內部,引用了兩個外部局部變量。如果引用的是非局部變量,那么這里輸出的為None.

  閉包函數的特點:

1.自帶作用域 2.延遲計算

  那么閉包函數有什么作用呢?我們清楚的知道,閉包函數在定義時,一定會綁定一個外部環境。這個整體才能算的上是一個閉包函數,那么我們可以利用這個綁定特性,來完成某些特殊的功能。

  實例三:根據傳入的URL,來下載頁面源碼

from urllib.request import urlopendef index(url)  def get()    return urlopen(url).read()  return getpython = index("http://www.python.org") # 返回的是get函數的地址print(python()) # 執行get函數《并且將返回的結果打印出來baidu = index("http://www.baidu.com")print(baidu())

  有人可以會說,這個不滿足閉包函數的條件啊!我沒有引用非全局的外部變量啊。其實并非如此,給,我們之前說過,只要在函數內部的變量都屬于函數。那么我在index(url),這個url也屬于函數內部,只不過我們省略一步而已,所以上面那個函數也是閉包函數。

4.裝飾器

  有了以上基礎,對于裝飾器就好理解了.

  裝飾器:外部函數傳入被裝飾函數名,內部函數返回裝飾函數名。

  特點:1.不修改被裝飾函數的調用方式 2.不修改被裝飾函數的源代碼

  a.無參裝飾器

  有如下實例,我們需要計算一下代碼執行的時間。

import time, randomdef index():  time.sleep(random.randrange(1, 5))  print("welcome to index page")

  根據裝飾器的特點,我們不能對index()進行任何修改,而且調用方式也不能變。這時候,我們就可以使用裝飾器來完成如上功能.

import time, randomdef outer(func): # 將index的地址傳遞給func  def inner():    start_time = time.time()    func()  # fun = index 即func保存了外部index函數的地址    end_time = time.time()    print("運行時間為%s"%(end_time - start_time))  return inner # 返回inner的地址def index():  time.sleep(random.randrange(1, 5))  print("welcome to index page")index = outer(index) # 這里返回的是inner的地址,并重新賦值給indexindex()

  但是,有些情況,被裝飾的函數需要傳遞參數進去,有些函數又不需要參數,那么如何來處理這種變參數函數呢?下面來看看有參數裝飾器的使用情況.

  b.有參裝飾器

def outer(func): # 將index的地址傳遞給func  def inner(*args, **kwargs):    start_time = time.time()    func(*args, **kwargs)  # fun = index 即func保存了外部index函數的地址    end_time = time.time()    print("運行時間為%s"%(end_time - start_time))  return inner # 返回inner的地址

  下面來說說一些其他情況的實例。

   如果被裝飾的函數有返回值

def timmer(func):  def wrapper(*args,**kwargs):    start_time = time.time()    res=func(*args,**kwargs) #res來接收home函數的返回值    stop_time=time.time()    print('run time is %s' %(stop_time-start_time))    return res   return wrapperdef home(name):  time.sleep(random.randrange(1,3))  print('welecome to %s HOME page' %name)  return 123123123123123123123123123123123123123123

  這里補充一點,加入我們要執行被裝飾后的函數,那么應該是如下調用方式:

  home = timmer(home)  # 等式右邊返回的是wrapper的內存地址,再將其賦值給home,這里的home不在是原來的的那個函數,而是被裝飾以后的函數了。像home = timmer(home)這樣的寫法,python給我們提供了一個便捷的方式------語法糖@.以后我們再要在被裝飾的函數之前寫上@timmer,它的效果就和home = timmer(home)是一樣的。

  如果一個函數被多個裝飾器裝飾,那么執行順序是怎樣的。

import timeimport randomdef timmer(func):  def wrapper():    start_time = time.time()    func()    stop_time=time.time()    print('run time is %s' %(stop_time-start_time))  return wrapperdef auth(func):  def deco():    name=input('name: ')    password=input('password: ')    if name == 'egon' and password == '123':      print('login successful')      func() #wrapper()    else:      print('login err')  return deco@auth  # index = auth(timmer(index))         @timmer # index = timmer(index)def index():   time.sleep(3)  print('welecome to index page')index()

  實驗結果表明,多個裝飾器裝飾一個函數,其執行順序是從下往上。

  關于裝飾器,還有一些高級用法,有興趣的可以自己研究研究。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 牙克石市| 蓝田县| 襄垣县| 阜南县| 宝坻区| 扎赉特旗| 五常市| 黄浦区| 榆林市| 广德县| 宁陵县| 游戏| 弋阳县| 霍城县| 清丰县| 南汇区| 武穴市| 米易县| 措美县| 呈贡县| 南澳县| 泰安市| 临泽县| 弋阳县| 庆阳市| 平远县| 西畴县| 石门县| 昆山市| 绵竹市| 宕昌县| 贡山| 秀山| 伊吾县| 巴青县| 潼关县| 濉溪县| 文山县| 霍州市| 鹤山市| 正定县|