欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

帶你了解python裝飾器

 更新時(shí)間:2017年06月15日 08:47:44   作者:Davve_chen  
Python中的裝飾器是你進(jìn)入Python大門的一道坎,不管你跨不跨過去它都在那里。Python中的裝飾器的概念經(jīng)常會(huì)讓人搞得一頭霧水,所以今天就好好來分析一下python中的裝飾器

1.作用域

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

 全局作用域是定義在文件級(jí)別的變量,函數(shù)名。而局部作用域,則是定義函數(shù)內(nèi)部。

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

 下面我們來看看下面實(shí)例:

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

funx()
print(x) # 打印出1

  如果局部沒有定義變量x,那么函數(shù)內(nèi)部會(huì)從內(nèi)往外開始查找x,如果沒有找到,就會(huì)報(bào)錯(cuò)

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

funx()
print(x) # 打印出1

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

funx()
print(x) # 打印出1

  因此,關(guān)于作用域的問題,只需要記住兩點(diǎn)就行:全局變量能夠被文件任何地方引用,但修改只能在全局進(jìn)行操作;如果局部沒有找到所需的變量,就會(huì)往外進(jìn)行查找,沒有找到就會(huì)報(bào)錯(cuò)。

2.高級(jí)函數(shù)

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

 a函數(shù)名可以作為一個(gè)值

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("請(qǐng)輸入您要進(jìn)行的操作:").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.函數(shù)名可以作為返回值

def outer():
  def inner():
    pass
  return inner

s = outer()
print(s)

######輸出結(jié)果為#######
<function outer.<locals>.inner at 0x000000D22D8AB8C8>

 c..函數(shù)名可以作為一個(gè)參數(shù)

def index():
  print("index func")

def outer(index):
  s = index
  s()
  
outer(index)

######輸出結(jié)果#########

index func

 所以滿足上面兩個(gè)條件中的一個(gè),都可以稱為高級(jí)函數(shù).

3.閉包函數(shù)

  閉包函數(shù)必須滿足兩個(gè)條件:1.函數(shù)內(nèi)部定義的函數(shù) 2.包含對(duì)外部作用域而非全局作用域的引用

  下面通過一些實(shí)例來說明閉包函數(shù):

  實(shí)例一:以下僅僅在函數(shù)內(nèi)部定義了一個(gè)函數(shù),但并非閉包函數(shù).

def outer():
  def inner():
    print("inner func excuted")
  inner() # 調(diào)用執(zhí)行inner()函數(shù)
  print("outer func excuted")
outer() # 調(diào)用執(zhí)行outer函數(shù)

####輸出結(jié)果為##########
inner func excuted
outer func excuted

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

x = 1
def outer():
  def inner():
    print("x=%s" %x) # 引用了一個(gè)非inner函數(shù)內(nèi)部的變量
    print("inner func excuted")
  inner() # 執(zhí)行inner函數(shù)
  print("outer func excuted")

outer()
#####輸出結(jié)果########
x=1
inner func excuted
outer func excuted

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

def outer():
  x = 1
  def inner():
    print("x=%s" %x)
    print("inner func excuted")
  inner()
  print("outer func excuted")

outer()

#####輸出結(jié)果#########
x=1
inner func excuted
outer func excuted

  顯然,上面實(shí)例滿足閉包函數(shù)的條件?,F(xiàn)在,你應(yīng)該清楚,作為一個(gè)閉包函數(shù),必須得滿足上述的兩個(gè)條件,缺一不可。但是,一般情況下,我們都會(huì)給閉包函數(shù)返回一個(gè)值.這里先不說為什么.在接下來的內(nèi)容中,你會(huì)看到這個(gè)返回值的用途.

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

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

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

def outer():
  x = 1
  y = 2

  def inner():
    print("x= %s" %x)
    print("y= %s" %y)

  print(inner.__closure__)
  return inner

outer()

######輸出結(jié)果#######
(<cell at 0x000000DF9EA965B8: int object at 0x000000006FC2B440>, <cell at 0x000000DF9EA965E8: int object at 0x000000006FC2B460>)

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

  閉包函數(shù)的特點(diǎn):

1.自帶作用域 2.延遲計(jì)算

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

  實(shí)例三:根據(jù)傳入的URL,來下載頁面源碼

from urllib.request import urlopen

def index(url)
  def get()
    return urlopen(url).read()
  return get

python = index("http://www.python.org") # 返回的是get函數(shù)的地址
print(python()) # 執(zhí)行g(shù)et函數(shù)《并且將返回的結(jié)果打印出來
baidu = index("http://www.baidu.com")
print(baidu())

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

4.裝飾器

  有了以上基礎(chǔ),對(duì)于裝飾器就好理解了.

  裝飾器:外部函數(shù)傳入被裝飾函數(shù)名,內(nèi)部函數(shù)返回裝飾函數(shù)名。

  特點(diǎn):1.不修改被裝飾函數(shù)的調(diào)用方式 2.不修改被裝飾函數(shù)的源代碼

  a.無參裝飾器

  有如下實(shí)例,我們需要計(jì)算一下代碼執(zhí)行的時(shí)間。

import time, random

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

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

import time, random

def outer(func): # 將index的地址傳遞給func
  def inner():
    start_time = time.time()
    func()  # fun = index 即func保存了外部index函數(shù)的地址
    end_time = time.time()
    print("運(yùn)行時(shí)間為%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的地址,并重新賦值給index

index()

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

  b.有參裝飾器

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

  下面來說說一些其他情況的實(shí)例。

   如果被裝飾的函數(shù)有返回值

def timmer(func):
  def wrapper(*args,**kwargs):
    start_time = time.time()
    res=func(*args,**kwargs) #res來接收home函數(shù)的返回值
    stop_time=time.time()
    print('run time is %s' %(stop_time-start_time))
    return res 
  return wrapper

def home(name):
  time.sleep(random.randrange(1,3))
  print('welecome to %s HOME page' %name)
  return 123123123123123123123123123123123123123123

  這里補(bǔ)充一點(diǎn),加入我們要執(zhí)行被裝飾后的函數(shù),那么應(yīng)該是如下調(diào)用方式:

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

  如果一個(gè)函數(shù)被多個(gè)裝飾器裝飾,那么執(zhí)行順序是怎樣的。

import time
import random

def timmer(func):
  def wrapper():
    start_time = time.time()
    func()
    stop_time=time.time()
    print('run time is %s' %(stop_time-start_time))
  return wrapper
def 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()

  實(shí)驗(yàn)結(jié)果表明,多個(gè)裝飾器裝飾一個(gè)函數(shù),其執(zhí)行順序是從下往上。

  關(guān)于裝飾器,還有一些高級(jí)用法,有興趣的可以自己研究研究。

相關(guān)文章

  • 使用Python實(shí)現(xiàn)插入100萬條數(shù)據(jù)到MySQL數(shù)據(jù)庫

    使用Python實(shí)現(xiàn)插入100萬條數(shù)據(jù)到MySQL數(shù)據(jù)庫

    這篇文章主要為大家詳細(xì)介紹了如何使用Python實(shí)現(xiàn)插入100萬條數(shù)據(jù)到MySQL數(shù)據(jù)庫,文中的示例代碼講解詳細(xì),有需要的小伙伴可以參考一下
    2024-04-04
  • python celery beat實(shí)現(xiàn)定時(shí)任務(wù)的示例代碼

    python celery beat實(shí)現(xiàn)定時(shí)任務(wù)的示例代碼

    在日常工作中,我們常常會(huì)用到需要周期性執(zhí)行的任務(wù),本文主要介紹了python celery beat實(shí)現(xiàn)定時(shí)任務(wù)的示例代碼,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • python實(shí)現(xiàn)線性插值的示例

    python實(shí)現(xiàn)線性插值的示例

    線性插值是針對(duì)一維數(shù)據(jù)的插值方法,它根據(jù)一維數(shù)據(jù)序列中需要插值的點(diǎn)的左右臨近兩個(gè)數(shù)據(jù)來進(jìn)行數(shù)值估計(jì),這篇文章主要介紹了python實(shí)現(xiàn)線性插值,需要的朋友可以參考下
    2022-12-12
  • Python提取特定時(shí)間段內(nèi)數(shù)據(jù)的方法實(shí)例

    Python提取特定時(shí)間段內(nèi)數(shù)據(jù)的方法實(shí)例

    今天小編就為大家分享一篇關(guān)于Python提取特定時(shí)間段內(nèi)數(shù)據(jù)的方法實(shí)例,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-04-04
  • 基于Python編寫一個(gè)文檔密碼移除工具

    基于Python編寫一個(gè)文檔密碼移除工具

    保護(hù)文檔內(nèi)容是常見的需求,但有時(shí)我們可能會(huì)忘記或丟失文檔的密碼,導(dǎo)致無法訪問重要信息,本文將介紹如何使用Python創(chuàng)建一個(gè)簡單而實(shí)用的文檔密碼移除工具,需要的可以參考下
    2023-12-12
  • Python中全局變量和局部變量的理解與區(qū)別

    Python中全局變量和局部變量的理解與區(qū)別

    這篇文章主要給大家介紹了關(guān)于Python中全局變量和局部變量的理解與區(qū)別的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • 詳解Python中映射類型的內(nèi)建函數(shù)和工廠函數(shù)

    詳解Python中映射類型的內(nèi)建函數(shù)和工廠函數(shù)

    這篇文章主要介紹了詳解Python中映射類型的內(nèi)建函數(shù)和工廠函數(shù),目前Python的內(nèi)建映射類型只有字典一種,需要的朋友可以參考下
    2015-08-08
  • 教你如何用一行Python代碼實(shí)現(xiàn)GUI圖形界面

    教你如何用一行Python代碼實(shí)現(xiàn)GUI圖形界面

    GUI(圖形用戶界面),顧名思義就是用圖形的方式,來顯示計(jì)算機(jī)操作的界面,更加方便且直觀。本文將用一行代碼實(shí)現(xiàn)GUI界面的制作,需要的可以參考一下
    2022-05-05
  • 深入分析python 排序

    深入分析python 排序

    這篇文章主要介紹了python 排序的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)python排序的知識(shí),感興趣的朋友可以了解下
    2020-08-08
  • 詳解?PyTorch?Lightning模型部署到生產(chǎn)服務(wù)中

    詳解?PyTorch?Lightning模型部署到生產(chǎn)服務(wù)中

    這篇文章主要為大家介紹了如何將PyTorch?Lightning模型部署到生產(chǎn)服務(wù)中的詳細(xì)教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09

最新評(píng)論