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装饰器、描述符模拟源码实现相关推荐
- python编程锦囊pdf百度云_python编程锦囊 相关实例(示例源码)下载 - 好例子网
开发语言:Python | 大小:42.01M | 发布时间:2020-08-05 | 立即下载 开发语言:Python | 大小:41.83M | 发布时间:2020-11-11 | 立即下载 开发 ...
- python抖音表白程序代码_python 下载抖音视频示例源码
[实例简介] 下载抖音视频 [实例截图] [核心代码] #code:utf-8 import requests from bs4 import BeautifulSoup import json se ...
- 设计模式 结构型模式 -- 装饰者模式(概述 快餐店案例 模式优点 使用场景 源码解析 BufferedWriter 和代理模式的区别)
1. 装饰者模式 1.1 概述 我们先来看一个快餐店的例子: 快餐店有炒面.炒饭这些快餐,可以额外附加鸡蛋.火腿.培根这些配菜,当然加配菜需要额外加钱,每个配菜的价钱通常不太一样,那么计算总价就会显得 ...
- 【Python工具】Python版本的天眼查,是不是就很nice啦 | 附带源码
相关文件 关注小编,私信小编领取哟! 当然别忘了一件三连哟~~ 公众号:Python日志 可以关注小编公众号,会不定时的发布一下Python小技巧,还有很多资源可以免费领取哟!! 源码领取:加Pyth ...
- [智慧农业]Python基于改进YOLOv5的猕猴桃叶病害检测系统(完整源码&数据集&视频教程)
1.背景 现如今由于农作物病虫害的多样性和复杂性,在特定的条件下其很容易在大范围内发生,导致农产品产量急剧下降.因此,预防和监测农作物病虫害已成为农业生产活动中的重要环节.当前,耕地面积逐渐减少,世界 ...
- android毕业设计——基于Android+Java+Python的手机端办公自动化OA系统设计与实现(毕业论文+程序源码)——办公自动化OA系统
基于Android+Java+Python的手机端办公自动化OA系统设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于Android+Java+Python的手机端办公自动化OA系统设计与实 ...
- python 抓取解析接口数据_[干货]用python抓取摩拜单车API数据并做可视化分析(源码)...
原标题:[干货]用python抓取摩拜单车API数据并做可视化分析(源码) 在APP中能看到很多单车,但走到那里的时候,才发现车并不在那里.有些车不知道藏到了哪里:有些车或许是在高楼的后面,由于有GP ...
- Mybatis底层原理学习(二):从源码角度分析一次查询操作过程
在阅读这篇文章之前,建议先阅读一下我之前写的两篇文章,对理解这篇文章很有帮助,特别是Mybatis新手: 写给mybatis小白的入门指南 mybatis底层原理学习(一):SqlSessionFac ...
- 【Vue-Router】模拟源码,解析 Vue-Router 的实现原理
前言 笔记来源:拉勾教育 大前端高薪训练营 阅读建议:建议通过左侧导航栏进行阅读 Vue-Router 基础知识 编程式导航 this.$router.replace() this.$router.p ...
最新文章
- Django 模板HTML转义和CSRF4.3
- 我的世界基岩版json_我的世界基岩版合集
- java word表格_Java 添加Word表格行或列
- python程序员在公司都是做什么的-程序员是做什么的?工资待遇怎么样?
- 腾讯爬虫python_Python爬虫,爬取腾讯漫画实战
- 单个字段去重并保留其他字段值
- eclipse中复制导入的项目并且修改了项目名字,项目后面的括号显示原来项目的名字
- Vue提示warn:”[vue-router] Named Route ‘home’ has a default child route…”
- HCIE Security PKI 备考笔记(幕布)
- 统计学习中常用的损失函数
- 【24点】java减治法实现二十四点,输出所有求值结果为24的组合
- js 实现删除确认提示框
- 33种名车的标志及名称来历
- 服务器的上行带宽和下行带宽是什么意思
- 《高效能青少年的七个习惯》读后感作文3900字
- Linux远程访问的方法
- 开源的C++静态分析工具
- 按键精灵X学习笔记(二):键盘命令
- matlab中的subplot函数
- MySQL删除数据后,释放磁盘空间
热门文章
- 统计gitlab代码行脚本_详解代码统计工具cloc--计算文件数、空白行数、注释行和代码行...
- 发现 postman 自动生成接口调用代码的一个问题
- Chrome 开发者工具无法显示服务器正常返回的 HTTP 请求 - Failed to load response data
- SAP Fiori Elements 公开课第一单元概要介绍
- SAP UI的加载动画效果和幽灵设计(Ghost Design)
- SAP Spartacus 读取payment detail数据的API
- SAP Data Intelligence Graph使用浏览器访问的url规范
- 如何在S/4HANA里创建Custom Business object并实现自定义逻辑
- 开发一个简单的工具,导出github仓库所有issue列表
- 通过配置文件避免硬编码的一个例子