Python之@property详解及底层实现介绍
转自:https://blog.csdn.net/weixin_42681866/article/details/83376484
前文
Python内置有三大装饰器:@staticmethod(静态方法)、@classmethod(类方法)、@property(描述符),其中静态方法就是定义在类里的函数,并没有非要定义的必要;类方法则是在调用类属性、传递类对象时使用;而@property则是一个非常好用的语法糖。@property最大的好处就是在类中把一个方法变成属性调用,起到既能检查属性,还能用属性的方式来访问该属性的作用。
@property应用
让我们先看下@property的应用,其功能1是可定义只读属性,也就是真正意义上的私有属性(属性前双下划线的私有属性也是可以访问的,具体参照这篇文章:私有属性真的是私有的吗?)实例需求是定义类Person,具有年龄和姓名,要求年龄必须等于18,则代码如下:
class Person(object):
def __init__(self, name, age=18):
self.name = name
self.__age = 18
@property
def age(self):
return self.__age
xm = Person('xiaoming') # 定义一个人名小明
print(xm.age) # 结果为18
xm.age = -4 # 报错无法给年龄赋值
print(xm.age)
结果如下:
18
Traceback (most recent call last):
xm.age = 18
AttributeError: can't set attribute
在python中定义只读属性非@property莫属,如果细心留意大部分源码,都跑不了@property的身影。而定义只读属性也很简单:以需要定义的属性为方法名(上例age属性定义为方法),其上装饰内置装饰器@property就ok了。
@property真正强大的是可以限制属性的定义。往往我们定义类,希望其中的属性必须符合实际,但因为在__ init __里定义的属性可以随意的修改,导致很难实现。如我想实现Person类,规定每个人(即创建的实例)的年龄必须大于18岁,正常实现的话,则必须将属性age设为只读属性,然后通过方法来赋值,代码如下:
class Person(object):
def __init__(self, name, age):
self.name = name
self.__age = 18
@property
def age(self):
return self.__age
def set_age(self, age): # 定义函数来给self.__age赋值
if age < 18:
print('年龄必须大于18岁')
return
self.__age = age
return self.__age
xm = Person('xiaoming', 20)
print(xm.age)
print('----------')
xm.set_age(10)
print(xm.age)
print('----------')
xm.set_age(20)
print(xm.age)
为了便于区分结果,增加了分隔符,结果如下:
18
----------
年龄必须大于18岁
18
----------
20
可以看到,通过方法的确能限制输入,但是不是每个人都记得方法名,有什么简化的方法呢?@property就能很轻松办到,修改代码如下:
class Person(object):
def __init__(self, name, age):
self.name = name
self.__age = 18
@property
def age(self):
return self.__age
@age.setter
def age(self, age):
if age < 18:
print('年龄必须大于18岁')
return
self.__age = age
return self.__age
xm = Person('xiaoming', 20)
print(xm.age)
print('----------')
xm.age = 10
print(xm.age)
print('----------')
xm.age = 20
print(xm.age)
结果和上图一致。两段代码变化的内容:将set_age修改为age,并且在上方加入装饰器@age.setter。这就是@property定义可访问属性的语法,即仍旧以属性名为方法名,并在方法名上增加@属性.setter就行了。
@property实现原理
在开头说过,@property是个描述符(decorator),实际上他本身是类,不信的话,可以将上述代码修改如下:
class Person(object):
def __init__(self, name, age):
self.name = name
self.__age = 18
def get_age(self): # 恢复用方法名来获取以及定义
return self.__age
def set_age(self, age):
if age < 18:
print('年龄必须大于18岁')
return
self.__age = age
return self.__age
age = property(get_age, set_age) # 增加property类
上述代码的运行结果和前面一致,将@property装饰的属性方法再次修改回定义方法名,然后再类的最下方,定义:属性=property(get,set,del),这个格式是固定的,通过源码可以知道原因,property部分源码如下:
class property(object):
def __init__(self, fget=None, fset=None, fdel=None, doc=None):
"""
Property attribute.
fget
function to be used for getting an attribute value
fset
function to be used for setting an attribute value
fdel
function to be used for del'ing an attribute
class C(object):
@property
def x(self):
"I am the 'x' property."
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
"""
pass
def __set__(self, *args, **kwargs): # real signature unknown
"""
Set an attribute of instance to value.
"""
pass
def __get__(self, *args, **kwargs): # real signature unknown
"""
Return an attribute of instance, which is of type owner.
"""
pass
def __delete__(self, *args, **kwargs): # real signature unknown
"""
Delete an attribute of instance.
"""
pass
为了不让篇幅过长,同时影响到阅读效果,这边截取了部分,可以看到代码注释里写了官方的@property用法,同时如果是用类来实现的话,必须得按__ init __ 的参数里顺序fget/fset/fdel依次填入get、set、del方法,因为都是默认参数,所以都可以省略不写。
介绍下python的描述符,定义:如果一个类里定义了__ set __ 、__ get __ 、__ delete __三个方法之一,同时给另一个类的属性赋值为实例,那么该类可以称之为描述符。因为描述符的使用目前就python,所以了解下就行了。
总结
关于@property的介绍到此为止,@property装饰器就是一个语法糖(语法糖指那些没有给计算机语言添加新功能,而只是对人类来说更“甜蜜”的语法。 语法糖往往给程序员提供了更实用的编码方式,有益于更好的编码风格,更易读。)。
Python之@property详解及底层实现介绍的更多相关文章
- (转)python中@property详解
转:https://www.cnblogs.com/zhangfengxian/p/10199935.html
- (转)python collections模块详解
python collections模块详解 原文:http://www.cnblogs.com/dahu-daqing/p/7040490.html 1.模块简介 collections包含了一些特 ...
- python协程详解,gevent asyncio
python协程详解,gevent asyncio 新建模板小书匠 #协程的概念 #模块操作协程 # gevent 扩展模块 # asyncio 内置模块 # 基础的语法 1.生成器实现切换 [1] ...
- Python基础知识详解 从入门到精通(七)类与对象
本篇主要是介绍python,内容可先看目录其他基础知识详解,欢迎查看本人的其他文章Python基础知识详解 从入门到精通(一)介绍Python基础知识详解 从入门到精通(二)基础Python基础知识详 ...
- Block详解二(底层分析)
Block专辑: Block讲解一 MRC-block与ARC-block Block详解一(底层分析) 今天讲述Block的最后一篇,后两篇仅仅是加深1,2篇的理解,废话少说,开始讲解! __blo ...
- python之struct详解
python之struct详解 2018-05-23 18:20:29 醉小义 阅读数 20115更多 分类专栏: python 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议 ...
- Python 字符串方法详解
Python 字符串方法详解 本文最初发表于赖勇浩(恋花蝶)的博客(http://blog.csdn.net/lanphaday),如蒙转载,敬请保留全文完整,切勿去除本声明和作者信息. ...
- python time模块详解
python time模块详解 转自:http://blog.csdn.net/kiki113/article/details/4033017 python 的内嵌time模板翻译及说明 一.简介 ...
- Python中dict详解
from:http://www.cnblogs.com/yangyongzhi/archive/2012/09/17/2688326.html Python中dict详解 python3.0以上,pr ...
随机推荐
- [第十五篇]——Swarm 集群管理之Spring Cloud直播商城 b2b2c电子商务技术总结
Swarm 集群管理 简介 Docker Swarm 是 Docker 的集群管理工具.它将 Docker 主机池转变为单个虚拟 Docker 主机. Docker Swarm 提供了标准的 Dock ...
- scrum项目冲刺_day07总结
摘要:今日完成任务. 1.短信服务正在进行 2.路线规划正在进行 总任务: 一.appUI页面(已完成) 二.首页功能: 1.图像识别功能(已完成) 2.语音识别功能(已完成) 3.垃圾搜索功能 4. ...
- PHP的Mcrypt加密扩展知识了解
今天我们来学习的是 PHP 中的一个过时的扩展 Mcrypt .在 PHP7 之前,这个扩展是随 PHP 安装包一起内置发布的,但是现在新版本的 PHP 中已经没有了,需要使用这个扩展的话我们需要单独 ...
- vscode 本地启动配置
安装vscode 编辑器后,找到插件 1.安装Debugger for Chrome 2.找到本地需要启动的项目,配置文件,从左到右依次点击红圈中的按钮,然后出现launch.json文件,在里面添加 ...
- vs code安装leetcode插件
vs code 安装不成功啊 1.首先确保有node.js 10+,没有的话去官网下载,安装就可以,安装好之后在cmd命令行中输入: node -v 若出现相关版本信息说明安装成功 2.由于leetc ...
- Docker 配置国内镜像加速器
Docker 默认是从官方镜像地址 Docker Hub 下下载镜像,由于服务器在国外的缘故,导致经常下载速度非常慢.为了提升镜像的下载速度,我们可以手动配置国内镜像加速器,让下载速度飚起来. 国内的 ...
- ggplot2 画图随笔
ggplot2 盒图+显著性线 compire <- list(c('1','2'),c('1','4')) ggplot(info,aes(x=cluster,y=value))+ stat_ ...
- GDOI 2021 退役记
Day -n 时常想自己不学OI会怎样,经常畏惧自己其实没有心里想的那样有能力,去机房来麻痹自己 从 3.21 始加大频率刷题,复习以前都学会,而现在都被抛在脑后的算法 反正都要退役了,成绩也得鲜亮点 ...
- CF932G-Palindrome Partition【PAM】
正题 题目链接:https://www.luogu.com.cn/problem/CF932G 题目大意 给出一个长度为\(n\)的字符串,将其分为\(k\)段(\(k\)为任意偶数),记为\(p\) ...
- Visual Studio Code (VSCode) 配置 C/C++ 开发编译环境
前言 工作多年,突然发现很多C++的基础都忘记了,加之C++不断更新换代后的各种新特性,于是想重拾C++的基础学习.虽然现在工作都是Linux平台,但考虑到个人方便,自己也仅仅想重温语法,家里家外都可 ...