日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

python元编程_Python 元编程

發(fā)布時(shí)間:2025/3/15 python 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python元编程_Python 元编程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1.為函數(shù)添加包裝器

總是存在這樣的場景,在一個(gè)函數(shù)執(zhí)行前后需要做一些操作處理,常見于日志創(chuàng)建、權(quán)限認(rèn)證或者性能分析等。但有一個(gè)問題存在,那就是被裝飾的函數(shù),其元信息會(huì)丟失,函數(shù)引用會(huì)指向裝飾器的返回值(函數(shù))引用

這里介紹functools模塊下的wraps函數(shù), 能夠避免函數(shù)元信息丟失的情況發(fā)生, 保留原始函數(shù)的元數(shù)據(jù)。

from functools import wraps

def outer_nowraps(func):

def inner(*args, **kwargs):

pass

return func(*args, **kwargs)

return inner

def outer_wraps(func):

@wraps(func)

def inner(*args, **kwargs):

pass

return func(*args, **kwargs)

return inner

@outer_nowraps

def handle_nowraps(*args, **kwargs00):

pass

@outer_wraps

def handle_wraps(*args, **kwargs):

pass

if __name__ == '__main__':

print(handle_nowraps)

# .inner at 0x0000026363980620> 指向裝飾器返回值(函數(shù))

help(handle_nowraps)

# Help on function inner in module __main__:inner(*args, **kwargs)

print(handle_wraps)

# 指向自身

help(handle_wraps)

# Help on function handle_wraps in module __main__:handle_wraps(*args, **kwargs)

此外,值得說明的是,裝飾器就是一個(gè)函數(shù),它接收一個(gè)函數(shù)作為參數(shù)返回一個(gè)新的函數(shù)(利用partial實(shí)現(xiàn)),例如以下情況是等效的

@outer_wraps

def handle_wraps(*args, **kwargs):

pass

handle_wraps = outer_wraps(handle_wraps)

對于類而言,諸如@staticmethod, @classmethod, @property原理也是一樣的,例如以下情況是等效的

class A:

@classmethod

def method(cls):

pass

class A:

def method(cls):

pass

method = classmethod(method)

2.解除裝飾器

如果一個(gè)裝飾器(內(nèi)部被wraps包裝)已經(jīng)作用在了一個(gè)函數(shù)上,如果想撤銷它,直接訪問原始的未包裝的那個(gè)函數(shù),可以使用該函數(shù)對象的__wrapped__屬性來實(shí)現(xiàn),當(dāng)然并不是所有的裝飾器內(nèi)部均是使用wraps進(jìn)行包裝,例如常見的@staticmethod、@classmethod、@property等等,被這些裝飾的函數(shù)是不具備解除裝飾器的能力的。

3. 定義帶參數(shù)的裝飾器

對于logging模塊來說,日志常常分為DEBUG、INFO、WARNING、ERROR及CRITICAL等,如果此時(shí)要實(shí)現(xiàn)一個(gè)裝飾器,在不同函數(shù)上應(yīng)用不同的裝飾級(jí)別,就可以考慮使用一個(gè)帶參數(shù)的裝飾器來完成。

from functools import wraps

import logging

def logged(level, name=None, message=None):

"""實(shí)現(xiàn)在不同函數(shù)上自定義日志級(jí)別及日志輸出"""

def decorator(func: function):

log_name = name if name else func.__module__

log = logging.getLogger(log_name)

log_msg = message if message else func.__name__

@wraps(func)

def wrapper(*args, **kwargs):

log.log(level, log_msg)

return func(*args, **kwargs)

return wrapper

return decorator

@logged(logging.DEBUG)

def add(x, y):

return x + y

@logged(logging.CRITICAL, "example")

def spam():

print("Spam")

剛剛我們了解到了如何定義不帶參數(shù)的裝飾器,以及如何使用等效的語法表示,那么對于這種有參裝飾器,又如何在語法上等效表示呢?logged(logging.DEBUG)實(shí)際上返回了一個(gè)decorator的引用,所以等效表示語法如下:

add = logged(logging.DEBUG)(add) # 函數(shù)引用

4.可自定義屬性的裝飾器

這也正是Python作為面向?qū)ο笳Z言的高級(jí)特性,在裝飾器返回時(shí),實(shí)際上是一個(gè)函數(shù)引用被接收,那么,這個(gè)函數(shù)也是function對象,一切對象都可以動(dòng)態(tài)的自定義添加屬性,由此便可以實(shí)現(xiàn)操作最內(nèi)層函數(shù)引用的屬性的方式,來動(dòng)態(tài)的改變裝飾器最外層作用域的變量(nonlocal)。

from functools import wraps

from functools import partial

import logging

def modify_wrapper(obj, func=None):

if func is None:

return partial(modify_wrapper, obj)

setattr(obj, func.__name__, func)

return func

def logged(level, name=None, message=None):

"""實(shí)現(xiàn)在不同函數(shù)上自定義日志級(jí)別及日志輸出"""

def decorator(func):

log_name = name if name else func.__module__

log = logging.getLogger(log_name)

log_msg = message if message else func.__name__

@wraps(func)

def wrapper(*args, **kwargs):

log.log(level, log_msg)

return func(*args, **kwargs)

@modify_wrapper(wrapper)

def set_level(newlevel):

nonlocal level

level = newlevel

# 1. modify_wrapper(wrapper)返回一個(gè)partial(modify_wrapper, obj),固定了obj(即wrapper對象)

# 2. 返回的partial對象接收了一個(gè)set_level函數(shù)對象參數(shù)(未固定)

# 3. setattr(obj, func.__name__, func)為obj(即wrapper對象)添加了func(即set_level屬性)

# 4. 返回的仍然是set_level這一函數(shù)引用

# 上述4步的作用就是為wrapper賦以set_level這一函數(shù)引用作為其屬性

# set_level = modify_wrapper(wrapper)(set_level)

@modify_wrapper(wrapper)

def set_message(new_msg):

nonlocal log_msg

log_msg = new_msg

# 理由同上

return wrapper

return decorator

@logged(logging.DEBUG)

def add(x, y):

return x + y

@logged(logging.CRITICAL, "example")

def spam():

print("Spam")

if __name__ == '__main__':

logging.basicConfig(level=logging.DEBUG)

print(add(1, 2)) # 輸出: DEBUG:__main__:add 3

add.set_message("set msg")

print(add(3, 4)) # 輸出: DEBUG:__main__:set msg 7

add.set_level(logging.CRITICAL)

print(add(1, 4)) # 輸出: CRITICAL:__main__:set msg 5

上述代碼的精妙之處就在于,

1.partial以裝飾器(modify_wrapper)自身展開固定(固定參數(shù)是裝飾器(logged)內(nèi)部wrapper函數(shù)對象)。

2.當(dāng)再次調(diào)用modify_wrapper時(shí)候(即modify_wrapper(wrapper)(set_level)時(shí),不定參數(shù)func以set_level傳遞進(jìn)來),在對wrapper完成屬性綁定后,返回了set_level函數(shù)對象,并等待繼續(xù)調(diào)用

總結(jié)

以上是生活随笔為你收集整理的python元编程_Python 元编程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。