python-property、__get__、__set__
property
property装饰器的应用来自这样一个问题:如果对实例的属性值不加以限制,那么实例的属性值会出现明显不合理的情况,为了解决这个问题也许你会思考在对属性的修改时利用实例方法加以限制,但python中引入了@property 装饰器更方便的解决这个问题。
class Person(object):
def __init__(self, age=1):
self.age = age
p = Person()
p.age = -1 # 这显然是不合理的
class Person(object):
def __init__(self):
self._age = 1 # 私有属性,外部无法直接修改和访问
def age_setter(self, age):
if 0 < age < 120 and isinstance(age, int):
self._age = age
else:
raise ValueError('age must between 0-120 and be integer')
def age_getter(self):
return self._age
# 这时虽然做到了属性值的控制,但是每次设置和获取值的时候要调用不同的方法,不太方便
@property 装饰器兼顾了方便和控制,让实例的使用显得更加优雅,提高了可用性。另外,@property装饰器不设置setter时,就是一个只读属性,相当于对属性起到了保护作用,如下实验
class Person(object):
def __init__(self):
self._height = 1
@property # 这里就是height的getter
def height(self):
return self._height
@height.setter
def height(self, height):
if 0 < height < 220 and isinstance(height, int):
self._height = height
else:
raise ValueError('height must between 0-220 and be an integer')
@property
def normal_weight(self):
return round(22.86*(self.height/100)**2*2, 2)
p = Person()
p.height = 190
print(p.height)
print(p.normal_weight)
------ 结果 ——————
190
165.05
__set__ 和 _get_
理解set和get方法,实际上必须知道描述器是什么,成为一个描述器,一个类必须至少有__get__,__set__,__delete__方法被实现。如果一个对象同时定义了 __get__() 和 __set__(),它叫做资料描述器(data descriptor)。仅定义了 __get__() 的描述器叫非资料描述器(non-data descriptor)。
__get__(self, obj, type=None) --> value
定义了当描述器的值被取得的时候的行为。instance是拥有该描述器对象的一个实例。owner是拥有者本身
__set__(self, obj, value) --> None
定义了当描述器的值被改变的时候的行为。instance是拥有该描述器类的一个实例。value是要设置的值。
__delete__(self, instance) --> None
定义了当描述器的值被删除的时候的行为。instance是拥有该描述器对象的一个实例。
几个注意事项:资料描述器的执行顺序优先于实例字典,而实例字典的执行顺序优先于非资料描述器,重写getattribute可能会阻止描述器的使用。关于属性查找优先顺序的问题,后面会写一篇博客描述和实验,这里不重复。
class Descriptor:
def __get__(self, instance, owner):
print('1 get called,', 'instance is', instance, ',owner is', owner)
return instance._a
def __set__(self, instance, value):
print('2 set called,', 'instance is', instance, ',value is', value)
instance._a = value * 2
class T:
desc = Descriptor() # 类方法
def __init__(self):
self._a = 123
t = T()
t.desc = 5
print('result:', t.desc)
其实这里的使用已经很像@property了,但@property则更加简单方便。
--------结果------------
2 set called, instance is <__main__.T object at 0x00000182D90DC630> ,value is 5
1 get called, instance is <__main__.T object at 0x00000182D90DC630> ,owner is <class '__main__.T'>
result: 10
描述器协议是一个理解python内部机制的知识点,属性(property), 方法(bound和unbound method), 静态方法和类方法都是基于描述器协议的。
参考:
https://pyzh.readthedocs.io/en/latest/Descriptor-HOW-TO-Guide.html
https://blog.csdn.net/huithe/article/details/7484606
python-property、__get__、__set__的更多相关文章
- python的__get__、__set__、__delete__(1)
内容: 描述符引导 摘要 定义和介绍 描述符协议 调用描述符 样例 Properties 函数和 ...
- python 面向对象专题(八):特殊方法 (一)__get__、__set__、__delete__ 描述符(一)
https://www.cnblogs.com/flashBoxer/p/9771797.html 实现了 __get__.__set__ 或 __delete__ 方法的类是描述符.描述符的用法是, ...
- python 面向对象专题(十一):特殊方法 (四)__get__、__set__、__delete__ 描述符(四)描述符用法建议
使用特性以保持简单 内置的 property 类创建的其实是覆盖型描述符,__set__ 方法和__get__ 方法都实现了,即便不定义设值方法也是如此. 特性的__set__ 方法默认抛出 Attr ...
- python 面向对象专题(九):特殊方法 (二)__get__、__set__、__delete__ 描述符(二)覆盖型与非覆盖型描述符对比
前言 根据是否定义__set__ 方法,描述符可分为两大类. 实现 __set__ 方法的描述符属于覆盖型描述符,因为虽然描述符是类属性,但是实现 __set__ 方法的话,会覆盖对实例属性的赋值操作 ...
- python描述符(descriptor)、属性(property)、函数(类)装饰器(decorator )原理实例详解
1.前言 Python的描述符是接触到Python核心编程中一个比较难以理解的内容,自己在学习的过程中也遇到过很多的疑惑,通过google和阅读源码,现将自己的理解和心得记录下来,也为正在为了该问题 ...
- python 3全栈开发-面向对象之绑定方法(classmethod与staticmethod的区别)、多态、封装的特性property
一.面向对象绑定方法 一.类中定义的函数分成两大类 1.绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入): 1. 绑定到类的方法:用classmethod装饰器装饰的方法. 为类量身定制 ...
- python基础-abstractmethod、__属性、property、setter、deleter、classmethod、staticmethod
python基础-abstractmethod.__属性.property.setter.deleter.classmethod.staticmethod
- 【Python】__slots__ 、@property、多重继承、定制类、枚举类、元类
__slots__ @property 多重继承 定制类 枚举类 元类 [使用__slots__] 1.动态语言的一个特点就是允许给实例绑定任意的方法和变量,而静态语言(例如Java)必须事先将属性方 ...
- 第7.26节 Python中的@property装饰器定义属性访问方法getter、setter、deleter 详解
第7.26节 Python中的@property装饰器定义属性访问方法getter.setter.deleter 详解 一. 引言 Python中的装饰器在前面接触过,老猿还没有深入展开介绍装饰 ...
随机推荐
- C语言函数指针 和 OC-Block
C语言函数指针 和 OC-Block 一. C语言函数指针 关于函数指针的知识详细可参考:http://www.cnblogs.com/mjios/archive/2013/03/19/2967037 ...
- 我的QT5学习之路(四)——信号槽
一.前言 前面说了Qt最基本的实例创建.控件以及工具集的介绍,相当于对于Qt有了一个初次的认识,这次我们开始认识Qt信号通信的重点之一——信号槽. 二.信号槽 信号槽是 Qt 框架引以为豪的机制之一. ...
- 1<=portNo<=4竟然在keil4.71里面不报错
1.if( 1<=portNo<=4 ) { CardIn2_CS_L; //pull low CardIn1_CS_H; CardOut1_CS_H; CardOut2_CS_H ...
- oracle创建用户、表空间、临时表空间、分配权限步骤详解
首先登陆管理员账号,或者有DBA权限的用户,接下来依次: --查询所有用户select * from dba_users;--创建新用户create user gpmgt identified by ...
- Oracle 数据库备份和恢复配置
可能的失败及其解决方法 失败类型 我们坑你遇到的失败或错误分为两大类:物理和逻辑.物理错误一般是硬件错误或使用数据库的应用程序中的软件错误,而逻辑错误一般在终端用户级别(数据库用户和管理员). 按从轻 ...
- 利用纯JS和HTML Canvas生成随机迷宫过程中产生的有趣的事情
上效果图: #先看生成随机迷宫的代码吧↓ <html> <head> <title>生成随机迷宫v1.0</title> </head> & ...
- ajax 动态载入html后不能执行其中的js解决方法
事件背景 有一个公用页面需要在多个页面调用,其中涉及到部分js已经写在了公用页面中,通过ajax加载该页面后无法执行其中的js. 解决思路 1. 采用附加一个iframe的方法去执行js,为我等代码洁 ...
- JAVA WEB 前台实时监控后台程序运行
基本思路: 1. 操作状态在类中以静态变量方式(或公共类存储公共变量方式,SESSION方式.COOKIE方式)存在 2. 前台采用AJAX方式激发后台进行业务逻辑操作,并实时更新操作状态信息 3. ...
- WebGl 缩放(矩阵变换)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 从零开始的Python学习Episode 14——日志操作
日志操作 一.logging模块 %(message)s 日志信息 %(levelno)s 日志级别 datefmt 设置时间格式 filename 设置日志保存的路径 level 设置日志记录的级别 ...