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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python装饰器setter实现原理_python装饰器、描述符模拟源码实现

發布時間:2023/12/19 python 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python装饰器setter实现原理_python装饰器、描述符模拟源码实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

概要

本人python理論知識遠達不到傳授級別,寫文章主要目的是自我總結,并不能照顧所有人,請見諒,文章結尾貼有相關鏈接可以作為補充

全文分為三個部分裝飾器理論知識、裝飾器應用、裝飾器延申

裝飾理基礎:無參裝飾器、有參裝飾器、functiontools、裝飾器鏈

裝飾器進階:property、staticmethod、classmethod源碼分析(python代碼實現)

裝飾器基礎

無參裝飾器

'''

假定有一個需求是:打印程序函數運行順序

此案例打印的結果為:

foo1 function is starting

foo2 function is starting

'''

from functools import wraps

def NoParamDec(func):

#函數在被裝飾器裝時后,其函數屬性也會改變,wraps作用就是保證被裝飾函數屬性不變

@wraps(func)

def warpper(*args, **kwargs):

print('{} function is starting'.format(func.__name__))

return func(*args, **kwargs)

return warpper

#python黑魔法省略了NoParamDec=NoParamDec(foo1)

@NoParamDec

def foo1():

foo2()

@NoParamDec

def foo2():

pass

if __name__ == "__main__":

foo1()

有參裝飾器

'''

假定有一個需求是:檢查函數參數的類型,只允許匹配正確的函數通過程序

此案例打印結果為:

('a', 'b', 'c')

-----------------------分割線------------------------

ERROS!!!!b must be

ERROS!!!!c must be

('a', 2, ['b', 'd'])

'''

from functools import wraps

from inspect import signature

def typeAssert(*args, **kwargs):

deco_args = args

deco_kwargs = kwargs

def factor(func):

#python標準模塊類,可以用來檢查函數參數類型,只允許特定類型通過

sig = signature(func)

#將函數形式參數和規定類型進行綁定

check_bind_args = sig.bind_partial(*deco_args, **deco_kwargs).arguments

@wraps(func)

def wrapper(*args, **kwargs):

#將實際參數值和形式參數進行綁定

wrapper_bind_args = sig.bind(*args, **kwargs).arguments.items()

for name, obj in wrapper_bind_args:

#遍歷判斷是否實際參數值是規定參數的實例

if not isinstance(obj, check_bind_args[name]):

try:

raise TypeError('ERROS!!!!{arg} must be {obj} '.format(**{'arg': name, 'obj': check_bind_args[name]}))

except Exception as e:

print(e)

return func(*args, **kwargs)

return wrapper

return factor

@typeAssert(str, str, str)

def inspect_type(a, b, c):

return (a, b, c)

if __name__ == "__main__":

print(inspect_type('a', 'b', 'c'))

print('{:-^50}'.format('分割線'))

print(inspect_type('a', 2, ['b', 'd']))

裝飾器鏈

'''

假定有一個需求是:

輸入類似代碼:

@makebold

@makeitalic

def say():

return "Hello"

輸出:

Hello

'''

from functools import wraps

def html_deco(tag):

def decorator(fn):

@wraps(fn)

def wrapped(*args, **kwargs):

return '<{tag}>{fn_result}<{tag}>'.format(**{'tag': tag, 'fn_result': fn(*args, **kwargs)})

return wrapped

return decorator

@html_deco('b')

@html_deco('i')

def greet(whom=''):

# 等價于 geet=html_deco('b')(html_deco('i)(geet))

return 'Hello' + (' ' + whom) if whom else ''

if __name__ == "__main__":

print(greet('world')) # -> Hello world

裝飾器進階

property 原理

通常,描述符是具有“綁定行為”的對象屬性,其屬性訪問已經被描述符協議中的方法覆蓋。這些方法是__get__()、__set__()和__delete__()。如果一個對象定義這些方法中的任何一個,它被稱為一個描述符。如果對象定義__get__()和__set__(),則它被認為是數據描述符。僅定義__get__()的描述器稱為非數據描述符(它們通常用于方法,但是其他用途也是可能的)。

屬性查找優先級為:

類屬性

數據描述符

實例屬性

非數據描述符

默認為__getattr__()

class Property(object):

'''

內部property是用c實現的,這里用python模擬實現property功能

代碼參考官方doc文檔

'''

def __init__(self, fget=None, fset=None, fdel=None, doc=None):

self.fget = fget

self.fset = fset

self.fdel = fdel

self.__doc__ = doc

def __get__(self, obj, objtype=None):

if obj is None:

return self

if self.fget is None:

raise (AttributeError, "unreadable attribute")

print('self={},obj={},objtype={}'.format(self,obj,objtype))

return self.fget(obj)

def __set__(self, obj, value):

if self.fset is None:

raise (AttributeError, "can't set attribute")

self.fset(obj, value)

def __delete__(self, obj):

if self.fdel is None:

raise (AttributeError, "can't delete attribute")

self.fdel(obj)

def getter(self, fget):

return type(self)(fget, self.fset, self.fdel, self.__doc__)

def setter(self, fset):

return type(self)(self.fget, fset, self.fdel, self.__doc__)

def deleter(self, fdel):

return type(self)(self.fget, self.fset, fdel, self.__doc__)

class Student( object ):

@Property

def score( self ):

return self._score

@score.setter

def score( self, val ):

if not isinstance( val, int ):

raise ValueError( 'score must be an integer!' )

if val > 100 or val < 0:

raise ValueError( 'score must between 0 ~ 100!' )

self._score = val

if __name__ == "__main__":

s = Student()

s.score = 60

s.score

staticmethod 原理

@staticmethod means: when this method is called, we don't pass an instance of the class to it (as we normally do with methods). This means you can put a function inside a class but you can't access the instance of that class (this is useful when your method does not use the instance).

class StaticMethod(object):

"python代碼實現staticmethod原理"

def __init__(self, f):

self.f = f

def __get__(self, obj, objtype=None):

return self.f

class E(object):

#StaticMethod=StaticMethod(f)

@StaticMethod

def f( x):

return x

if __name__ == "__main__":

print(E.f('staticMethod Test'))

classmethod

@staticmethod means: when this method is called, we don't pass an instance of the class to it (as we normally do with methods). This means you can put a function inside a class but you can't access the instance of that class (this is useful when your method does not use the instance).

class ClassMethod(object):

"python代碼實現classmethod原理"

def __init__(self, f):

self.f = f

def __get__(self, obj, klass=None):

if klass is None:

klass = type(obj)

def newfunc(*args):

return self.f(klass, *args)

return newfunc

class E(object):

#ClassMethod=ClassMethod(f)

@ClassMethod

def f(cls,x):

return x

if __name__ == "__main__":

print(E().f('classMethod Test'))

參考資料

總結

以上是生活随笔為你收集整理的python装饰器setter实现原理_python装饰器、描述符模拟源码实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。