1. 程式人生 > >裝飾器,global與nonlocal

裝飾器,global與nonlocal

裝飾器

靈魂三問

  • 1.什麼事裝飾器
    器 => 工具
    裝飾 => 指的是為被裝飾的物件新增新功能

    裝飾器本身可以是任意可呼叫的物件 => 函式
    被裝飾的物件也可以是任意可呼叫的物件 => 函式
    目標:寫一個函式來為另一個函式新增新功能

  • 2.為何要用裝飾器
    開放封閉原則:軟體一旦上線就應該對修改封閉,對擴充套件開發
    對修改封閉:
    - 1.不能修改功能的原始碼
    - 2.也不能修改功能的呼叫方式
    對擴充套件開發:
    - 可以為原有的功能新增新的功能
    裝飾器就是要在不修改功能原始碼以及呼叫方式的前提下為員功能新增額外新的功能

  • 3.如何用裝飾器

  • 如何用裝飾器:
import time

def index():
    print('welcome to index page')
    time.sleep(2)

def outter(func):       #給index功能裝飾一個檢測執行時間的新功能
    #func = 最原始那個index的記憶體地址
    def wrapper():
        start = time.time()
        func()   #最原始那個index的記憶體地址()
        stop = time.time()
        print ('run time is %s'
%(stop-start)) return wrapper index = outter(index) #index = outter(原始那個index的記憶體地址) #index = wrapper函式的記憶體地址 index() #wrapper 偷樑換柱,現在的index是wrapper的記憶體地址
  • 裝飾器修正1

如果需要index的返回值,上面如果res = index() 實際上是 res = wrapper()

import time

def index():
    print('welcome to index page')
    time.
sleep(2) return 123 # =================================================== def outter (func): #func = 最原始那個index的記憶體dizh def wrapper(): start = time.time() res = func() #最原始那個index的記憶體地址 把func的返回值指向res stop = time.time() print('run time is %s' %(stop-start)) return res #wrapper的返回值和最原始index的返回值相同 return wrapper index = outter(index) #index = outter(最原始那個index的記憶體地址) #index = wrapper函式的記憶體地址 # =================================================== res = index() #res = wrapper() print(res)
  • 裝飾器修正2

之前被裝飾的函式是無引數的函式,如果被裝飾的函式是有引數的函式


import time

def index():
    print('welcome to index page')
    time.sleep(3)
    return 123

def home(name):
    print('welcome %s to home page' %name)
    time.sleep(1)

# ===================================================

def outter(func):
    #func = 最原始那個home的記憶體地址
    def wrapper (*args,**kwargs):     #用了之前學的*和**的用法
        start = time.time()
        res = func(*args,**kwargs)       #如果被裝飾的函式需要引數,可以把wrapper的引數傳給被裝飾的函式做引數
        stop = time.time()
        print('run time is %s' %(stop-start))
        return res
    return wrapper

index = outter(index)    #index = outter(最原始那個index的記憶體地址) #index = wrapper函式的記憶體地址
home = outter(home)   #home = outter(最原始那個home的記憶體地址) #home = wrapper函式的記憶體地址

# ===================================================

home('wood')   #wrapper('wood')
index()  #wrapper
  • 裝飾器的語法糖

之前寫的裝飾器最後都要把被修飾的函式名偷樑換柱給outter
index = outter(index)
home = outter(home)
如果多個函式需要用到這個裝飾器,我們就要寫很多的像上面那樣的程式碼
這要寫重複的東西不是很low,python怎麼能low呢
這裡有一個裝飾器的語法糖的概念

# @裝飾器的名字:要在被裝飾物件正上方單獨一行寫上

import time

def timmer(func):           #寫一個裝飾器
    def wrapper(*args,**kwargs):
        start = time.time()
        res = func(*args,**kwargs):
        stop = time.time()
        print('run time is %s' %(stop-start))
        return res
    return wrapper

@timmer         #@後+裝飾圈的函式名,直接使用省了index = outter(index) 
def index():
    '''這是index功能 '''
    print('welcome to index page')
    time.sleep(2)
    return 123

@timmer       #@後+裝飾圈的函式名,直接使用省了index = home(index) 
def home(name):
    '''這是home功能 '''
    print('welcome %s to home page' %name)
    time.sleep(1)

print(help(index))     #wrapper的註釋
print(index.__name__)     #wrapper的名字

上面程式碼有一個新問題,函式有一些方法:
help可以調函式的註釋
.__name__調函式名
還有很多.__的方法。
這個時候用了裝飾器 index已經不是原來的index了,
現在index指的是wrapper的記憶體地址了,
想神不知鬼不覺的再調最原始的index方法怎麼辦

#from functools import wraps方法
from functools import wraps      #呼叫這個方法

import time

def timmer(func):           #寫一個裝飾器
    @wraps(func)       #在wrapper上面寫一個@wraps(func)把最原始函式的那些都調過來
    def wrapper(*args,**kwargs):
        start = time.time()
        res = func(*args,**kwargs):
        stop = time.time()
        print('run time is %s' %(stop-start))
        return res
    return wrapper

@timmer         #@後+裝飾圈的函式名,直接使用省了index = outter(index) 
def index():
    '''這是index功能 '''
    print('welcome to index page')
    time.sleep(2)
    return 123

@timmer       #@後+裝飾圈的函式名,直接使用省了index = home(index) 
def home(name):
    '''這是home功能 '''
    print('welcome %s to home page' %name)
    time.sleep(1)

print(help(index))      #這就顯示index的註釋
print(index.__name__)    #index的名字

  • 無參裝飾器

根據上面的裝飾器可以確定一個無參裝飾器的模板

#無參裝飾器的模板
def outter(func):
    def wrapper(*args,**kwargs):
        res = func(*args,**kwargs)
        return res
    return wrapper

用這個寫一個認證功能

import time

user_info = {'current_user':None}    #變數值是可變的

def auth(func):
    def wrapper(*args,**kwargs):
        if user_info['current_user'] is not None:
            res = func(*args,**kwargs)     
            return res      #return會結束函式
        inp_user = input('username>>>: ').strip()
        inp_pwd = input('password>>>: ').strip()
        if inp_user == 'egon' and inp_pwd == '123':
            # 記錄登入狀態
            user_info['current_user']=inp_user

            print('login successful')
            res = func(*args,**kwargs)
            return res
        else:
            print('user or password error')
    return wrapper

@auth
def index():
    """這是index功能"""
    print('welcome to index page')
    time.sleep(2)
    return 123

@auth
def home(name):
    """這是home功能"""
    print('welcome %s to home page' %name)
    time.sleep(1)

  • 有參裝飾器

之前我們說的都是無參裝飾器,裝飾器本身不需要引數的,引數都是為了轉給或轉到原函式的,現在說有參裝飾器,除了需要轉給原函式的引數外,裝飾器本身的功能也需要引數的情況

def outter2(xxx,yyy):
    #區域性內的兩個閉包函式的引數都是不能動的,在需要xxx,yyy就需要在往上找了,不能找到全域性作用域去吧
    #再包一下,三層閉包函式,最外層的給xxx,yyy傳值
    def outter(func):
        def wrapper(*args,**kwargs):
            res = func(*args,**kwargs)
            print(xxx)
            print(yyy)
            return res
        return wrapper
    return outter

我們上面的裝飾器是把認證的來源寫死了,如果我們是從檔案中呼叫資料來認證,如果我們是從mysql資料庫裡呼叫資料,ldap裡面呼叫資料

import time

user_info = {'current_user':None}

def auth2(engine = 'file'):    #定義一個預設形參,engine預設=‘file’
    def auth(func):
        def wrapper(*args,**kwargs):
            if user_info['current_user'] is not None:
                res = func(*args,**kwargs)
                return res
            inp_user = input('username>>>: ').strip()
            inp_pwd = input('password>>>: ').strip()

            if engine == 'file':
                print('基於檔案的認證')
                if inp_user == 'egon' and inp_pwd == '123':
                    # 記錄登入狀態
                    user_info['current_user']=inp_user

                    print('login successful')
                    res=func(*args,**kwargs)
                    return res
                else:
                    print('user or password error')
            elif engine == 'mysql':
                print('基於mysql資料的認證')
            elif engine == 'ldap':
                print('基於ldap的認證')
            else:
                print('無法識別認證源')
        return wrapper
    return auth

@auth2(engine = 'mysql') # @auth ===> index=auth(最原始那個index的記憶體地址)===》index=wrapper
def index():
    """這是index功能"""
    print('welcome to index page')
    time.sleep(2)
    return 123

@auth2(engine = 'file')
def home(name):
    """這是home功能"""
    print('welcome %s to home page' %name)
    time.sleep(1)

index() #wrapper()
home('egon')
  • 補充作用域,global與nonlocal
x = 1
def func():
   x = 2

func()
print(x)     #x在全局裡找,x=1  1是整型不能在區域性直接改


x = []
def func():
   x.append(1)
   x.append(2)
   x.append(3)

func()
print(x)     #x是列表,是可變的,可以在區域性直接改

# global: 在區域性宣告變數是全域性變數
x = 1
def func():
    global x       #global我就是要改
    x = 2

func()
print(x)      #print 2

# nonlocal:在區域性宣告變數是外層函式的變數,如果外層沒有,就在往更外存找,知道在外層的函式
x = 333
def f1():
    x = 222
    def f2():
        x = 111
        def f3():
            nonlocal x
            x = 0
        f3()
        print('f2內部的x: ',x)
    f2()
    print('這是f1內部的x: ',x)

f1()
print(x)

相關推薦

裝飾globalnonlocal

裝飾器 靈魂三問 1.什麼事裝飾器 器 => 工具 裝飾 => 指的是為被裝飾的物件新增新功能 裝飾器本身可以是任意可呼叫的物件 => 函式 被裝飾的物件也可以是任意可呼叫的物件 => 函式 目標:寫一個函式來為另一個函式新增新功能

Python基礎——作用域globalnonlocal

細碎知識,在此記錄 名稱空間 名稱空間:一個存放名字與值關係的空間,如a = 10 名稱空間分類:                                1.全域性名稱空間->我們直接在py檔案中,函式外宣告的變數都屬於全域性名稱空間            

Python之叠代生成器裝飾

新的 訪問 所有 image ges 中斷 往回 並發 函數調用 1》叠代器原理及使用:   1>原理:     叠代器是訪問集合元素的一種方式,叠代器對象從集合的第一個元素開始訪問,直到所有的元素被訪問完結束;叠代器只能往前不會後退,不過

迭代生成器裝飾

迭代:類似於迴圈,每一次重複的過程被稱為一次迭代的過程,而每一次迭代得到的結果會被用來作為 下一次迭代的初始值,提供迭代方法的容器稱為迭代器,通常接觸的迭代器有序列(列表、元組、字串), 還有字典也是迭代器,都支援迭代的操作。 關於迭代,python提供了兩個BIF:i

在函數被裝飾的情況下如何取消裝飾訪問原始函數

date 訪問 tool ror 幫助信息 函數 auth art run 在函數被裝飾器裝飾的情況下,需要保持原始函數的文檔,幫助信息等信息,或者直接調用原始函數,此時需要引入wraps模塊 #!/usr/bin/env python #coding:utf-8 [em

globalnonlocal

word 結果 練習 輸入 思路 調用 args read second global與nonlocal: global關鍵字: x=1 def foo(): x=10 print(x) #打印: 10 foo() print(x)

Python_裝飾生成器_幹貨哦

time() 原則 格式化 代碼 time_t war username 周幾 ons import timeimport calendarimport os# 時間格式熟悉"""# 格式化成2016-03-20 11:45:39形式time01 = time.strfti

python學習第四天列表生產式匿名函數生成器內置函數叠代裝飾json和pickle的序列化和反序列化

數據 其他 imp 函數名 fun pro serializa and cal 列表生成式,生產器 #列表生成式,可以是代碼更復雜 a = [i for i in range(10)] #這裏的i,可以使用函數來裝飾 print(a) #生產器:就是數據在調用的時候才有

4-2日裝飾帶參數的裝飾

tar 相關操作 rom 裝飾器 有用 緩存 false war cto 1,函數的有用信息 from functools import wraps#引用模塊 def wrapper(f): # f = func1 @wraps(f) def inner

python 培訓第三章 函數裝飾模塊內置函數之一函數

python目錄: 函數示例裝飾器模塊內置函數一、函數示例:  1、定義函數:    def fun(args):      ‘描述信息‘      函數體    return 返回值   定義函數的三種形式:    無參函數def foo():print(‘in the foo‘)

在Linux上搭建Samba服務用於Windows之間的跨平臺文件共享

Linux Samba Windows Samba是著名的開源軟件項目之一,它在Linux/UNIX系統中實現了微軟的SMB/CIFS網絡協議,使得跨平臺的文件共享變得更加容易。在部署Windows、Linux/UNIX混合平臺的企業環境時,選用Samba可以很好的解決在不同系統之間的文件互訪問題

請實現一個裝飾限制該函數被調用的頻率如10秒一次

空間 打包 函數作為參數 get false val orm cti res 一、通過函數的閉包/命名空間原理,裝飾器來實現這個功能 裝飾器及原理可參考我的這篇文章 這個裝飾器可以隨便設置時間很方便,每個函數都有獨立的標記時間 #!/usr/bin/env python #

python 通用裝飾帶有參數的裝飾

func == nbsp cti none 結果 能夠 參數 %s # 使用裝飾器對有返回值的函數進行裝飾# def func(functionName):   # print(‘---func-1----‘)  # def func_in():  

python 動態傳參名稱空間和作用域函數的嵌套globalnonlocal

turn 聚合 改變 名稱空間 class pytho 不能 inner 創建 一、動態傳參   1.位置參數動態傳參   def func(*args): *表示動態傳參   * 在這裏表示接受位置參數的動態傳參,接收到的是元組。 def fun(*args):

裝飾functools參數註解

uil lru 方便 fff ado 位置參數 nat src 獲取對象 裝飾器(無參)? 它是一個函數? 函數作為它的形參? 返回值也是一個函數裝飾器和高階函數? 裝飾器是高階函數,但裝飾器是對傳入函數的功能的裝飾(功能增強)帶參裝飾器? 它是一個函數? 函數作為它的形參

JS 裝飾一篇就夠

finall 裝飾類 child rec symbol etop 組合 定義 陌生 更多文章,請在Github blog查看 在 ES6 中增加了對類對象的相關定義和操作(比如 class 和 extends ),這就使得我們在多個不同類之間共享或者擴展一些方法或者行為的時

Python中關鍵字globalnonlocal的區別

版權宣告:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/xCyansun/article/details/79672634終於下定決心學習Python了。既然從頭開始,就需要認認真真。 首先需要說的是,我是初學Python,這篇文章只是用於展示global和nonl

關於裝飾看了幾篇文章總結下

裝飾器是為了動態為函式增加功能,而不改變函式的程式碼,而存在的。編寫一個高階函式,讓他接收另一個函式,在內部對其包裝,是為裝飾器。 裝飾器的本質就是一個函式,用來修飾你要裝飾的函式,別想複雜了。 呼叫裝飾器,下面是要修飾的函式,則下面的函式就整體看做一個變數,傳給了裝飾器函式,傳過去

Python-自定義裝飾使用裝飾記錄函式執行次數,一種埋點的實現形式

什麼是裝飾器? 裝飾器本質是一個函式,它可以在不改變原來的函式的基礎上額外的增加一些功能。如常見的@classmethod,@staticmethod等都是裝飾器,接下來記錄下如何自定義個裝飾器: 剛剛說過了,裝飾器的本質就是一個函式,所有想要自定義一個裝飾器,首先自定義一個函式

使用裝飾檢視函式的執行時間。深度解析python中對時間函式的使用

# Python time clock() 函式以浮點數計算的秒數返回當前的CPU時間。用來衡量不同程式的耗時,比time.time()更有用。 # 這個需要注意,在不同的系統上含義不同。在UNIX系統上,它返回的是"程序時間",它是用秒錶示的浮點數(時間戳)。 # 而在WINDOWS中,第一次呼叫