转自:https://blog.csdn.net/weixin_42681866/article/details/83376484

前文

Python内置有三大装饰器:@staticmethod(静态方法)、@classmethod(类方法)、@property(描述符),其中静态方法就是定义在类里的函数,并没有非要定义的必要;类方法则是在调用类属性、传递类对象时使用;而@property则是一个非常好用的语法糖。@property最大的好处就是在类中把一个方法变成属性调用,起到既能检查属性,还能用属性的方式来访问该属性的作用。

@property应用

让我们先看下@property的应用,其功能1是可定义只读属性,也就是真正意义上的私有属性(属性前双下划线的私有属性也是可以访问的,具体参照这篇文章:私有属性真的是私有的吗?)实例需求是定义类Person,具有年龄和姓名,要求年龄必须等于18,则代码如下:

  1. class Person(object):
  2. def __init__(self, name, age=18):
  3. self.name = name
  4. self.__age = 18
  5. @property
  6. def age(self):
  7. return self.__age
  8. xm = Person('xiaoming') # 定义一个人名小明
  9. print(xm.age) # 结果为18
  10. xm.age = -4 # 报错无法给年龄赋值
  11. print(xm.age)

结果如下:

  1. 18
  2. Traceback (most recent call last):
  3. xm.age = 18
  4. AttributeError: can't set attribute

在python中定义只读属性非@property莫属,如果细心留意大部分源码,都跑不了@property的身影。而定义只读属性也很简单:以需要定义的属性为方法名(上例age属性定义为方法),其上装饰内置装饰器@property就ok了。

@property真正强大的是可以限制属性的定义。往往我们定义类,希望其中的属性必须符合实际,但因为在__ init __里定义的属性可以随意的修改,导致很难实现。如我想实现Person类,规定每个人(即创建的实例)的年龄必须大于18岁,正常实现的话,则必须将属性age设为只读属性,然后通过方法来赋值,代码如下:

  1. class Person(object):
  2. def __init__(self, name, age):
  3. self.name = name
  4. self.__age = 18
  5. @property
  6. def age(self):
  7. return self.__age
  8. def set_age(self, age): # 定义函数来给self.__age赋值
  9. if age < 18:
  10. print('年龄必须大于18岁')
  11. return
  12. self.__age = age
  13. return self.__age
  14. xm = Person('xiaoming', 20)
  15. print(xm.age)
  16. print('----------')
  17. xm.set_age(10)
  18. print(xm.age)
  19. print('----------')
  20. xm.set_age(20)
  21. print(xm.age)

为了便于区分结果,增加了分隔符,结果如下:

  1. 18
  2. ----------
  3. 年龄必须大于18
  4. 18
  5. ----------
  6. 20

可以看到,通过方法的确能限制输入,但是不是每个人都记得方法名,有什么简化的方法呢?@property就能很轻松办到,修改代码如下:

  1. class Person(object):
  2. def __init__(self, name, age):
  3. self.name = name
  4. self.__age = 18
  5. @property
  6. def age(self):
  7. return self.__age
  8. @age.setter
  9. def age(self, age):
  10. if age < 18:
  11. print('年龄必须大于18岁')
  12. return
  13. self.__age = age
  14. return self.__age
  15. xm = Person('xiaoming', 20)
  16. print(xm.age)
  17. print('----------')
  18. xm.age = 10
  19. print(xm.age)
  20. print('----------')
  21. xm.age = 20
  22. print(xm.age)

结果和上图一致。两段代码变化的内容:将set_age修改为age,并且在上方加入装饰器@age.setter。这就是@property定义可访问属性的语法,即仍旧以属性名为方法名,并在方法名上增加@属性.setter就行了

@property实现原理

在开头说过,@property是个描述符(decorator),实际上他本身是类,不信的话,可以将上述代码修改如下:

  1. class Person(object):
  2. def __init__(self, name, age):
  3. self.name = name
  4. self.__age = 18
  5. def get_age(self): # 恢复用方法名来获取以及定义
  6. return self.__age
  7. def set_age(self, age):
  8. if age < 18:
  9. print('年龄必须大于18岁')
  10. return
  11. self.__age = age
  12. return self.__age
  13. age = property(get_age, set_age) # 增加property类

上述代码的运行结果和前面一致,将@property装饰的属性方法再次修改回定义方法名,然后再类的最下方,定义:属性=property(get,set,del),这个格式是固定的,通过源码可以知道原因,property部分源码如下:

  1. class property(object):
  2. def __init__(self, fget=None, fset=None, fdel=None, doc=None):
  3. """
  4. Property attribute.
  5. fget
  6. function to be used for getting an attribute value
  7. fset
  8. function to be used for setting an attribute value
  9. fdel
  10. function to be used for del'ing an attribute
  11. class C(object):
  12. @property
  13. def x(self):
  14. "I am the 'x' property."
  15. return self._x
  16. @x.setter
  17. def x(self, value):
  18. self._x = value
  19. @x.deleter
  20. def x(self):
  21. del self._x
  22. """
  23. pass
  24. def __set__(self, *args, **kwargs): # real signature unknown
  25. """
  26. Set an attribute of instance to value.
  27. """
  28. pass
  29. def __get__(self, *args, **kwargs): # real signature unknown
  30. """
  31. Return an attribute of instance, which is of type owner.
  32. """
  33. pass
  34. def __delete__(self, *args, **kwargs): # real signature unknown
  35. """
  36. Delete an attribute of instance.
  37. """
  38. pass

为了不让篇幅过长,同时影响到阅读效果,这边截取了部分,可以看到代码注释里写了官方的@property用法,同时如果是用类来实现的话,必须得按__ init __ 的参数里顺序fget/fset/fdel依次填入get、set、del方法,因为都是默认参数,所以都可以省略不写。

介绍下python的描述符,定义:如果一个类里定义了__ set __ 、__ get __ 、__ delete __三个方法之一,同时给另一个类的属性赋值为实例,那么该类可以称之为描述符。因为描述符的使用目前就python,所以了解下就行了。

总结

关于@property的介绍到此为止,@property装饰器就是一个语法糖(语法糖指那些没有给计算机语言添加新功能,而只是对人类来说更“甜蜜”的语法。 语法糖往往给程序员提供了更实用的编码方式,有益于更好的编码风格,更易读。)。

Python之@property详解及底层实现介绍的更多相关文章

  1. (转)python中@property详解

    转:https://www.cnblogs.com/zhangfengxian/p/10199935.html

  2. (转)python collections模块详解

    python collections模块详解 原文:http://www.cnblogs.com/dahu-daqing/p/7040490.html 1.模块简介 collections包含了一些特 ...

  3. python协程详解,gevent asyncio

    python协程详解,gevent asyncio 新建模板小书匠 #协程的概念 #模块操作协程 # gevent 扩展模块 # asyncio 内置模块 # 基础的语法 1.生成器实现切换 [1] ...

  4. Python基础知识详解 从入门到精通(七)类与对象

    本篇主要是介绍python,内容可先看目录其他基础知识详解,欢迎查看本人的其他文章Python基础知识详解 从入门到精通(一)介绍Python基础知识详解 从入门到精通(二)基础Python基础知识详 ...

  5. Block详解二(底层分析)

    Block专辑: Block讲解一 MRC-block与ARC-block Block详解一(底层分析) 今天讲述Block的最后一篇,后两篇仅仅是加深1,2篇的理解,废话少说,开始讲解! __blo ...

  6. python之struct详解

    python之struct详解 2018-05-23 18:20:29 醉小义 阅读数 20115更多 分类专栏: python   版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议 ...

  7. Python 字符串方法详解

    Python 字符串方法详解 本文最初发表于赖勇浩(恋花蝶)的博客(http://blog.csdn.net/lanphaday),如蒙转载,敬请保留全文完整,切勿去除本声明和作者信息.        ...

  8. python time模块详解

    python time模块详解 转自:http://blog.csdn.net/kiki113/article/details/4033017 python 的内嵌time模板翻译及说明  一.简介 ...

  9. Python中dict详解

    from:http://www.cnblogs.com/yangyongzhi/archive/2012/09/17/2688326.html Python中dict详解 python3.0以上,pr ...

随机推荐

  1. Linux从头学12:读完这篇【特权级】文章,你就比别人更“精通”操作系统!

    作 者:道哥,10+年嵌入式开发老兵,专注于:C/C++.嵌入式.Linux. 关注下方公众号,回复[书籍],获取 Linux.嵌入式领域经典书籍:回复[PDF],获取所有原创文章( PDF 格式). ...

  2. Docker容器基本命令注意点

    Docker 容器基本命令注意点 前言: a. 本文主要为 Docker的视频教程 笔记. b. 本机环境为 Windows 10 专业版,使用的命令行为 PowerShell. 1. docker ...

  3. HTML音乐悬浮播放器

    话不多说先上代码 <link rel="stylesheet" href="http://47.102.203.92/css/APlayer.min.css&quo ...

  4. 433MHZ SPI模块使用心得

    最近使用了433MHZ的模块进行了一个通讯项目,选用的是SX1208模块,对接了RTOS和Linux两个操作系统,使用心得如下: 1. 首先要拿来datasheet看一遍,通揽一下它的功能.可以得到一 ...

  5. Jmeter系列(3)- 常用断言之响应断言

    断言的作用 确定请求是有效还是无效的 添加断言 面板模块介绍 Apply to 作用:指定断言作用范围 Main sample and sub-sample:作用于主main sample和子sub- ...

  6. Elasticsearch6.8.6版本 在head插件中 对数据的增删改操作

    一.访问ES方法:http://IP:PORT/ 一.创建索引:head插件创建索引的实例:在"索引"-"新建索引"中创建索引名称,默认了分片与副本情况: 直接 ...

  7. Leetcode 矩阵置零

    题目描述(中等难度) 给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 .请使用 原地 算法. 进阶: 一个直观的解决方案是使用  O(mn) 的额外空间,但这 ...

  8. 鸿蒙内核源码分析(任务切换篇) | 看汇编如何切换任务 | 百篇博客分析OpenHarmony源码 | v41.03

    百篇博客系列篇.本篇为: v41.xx 鸿蒙内核源码分析(任务切换篇) | 看汇编如何切换任务 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度谁 ...

  9. WPF进阶技巧和实战04-资源

    资源集合 每个元素都有Resources属性,该属性存储了一个资源字典集合(它是ResourceDictionary类的实例).资源集合可以包含任意类型的对象,并根据字符串编写索引. 每个元素既可以访 ...

  10. Redis之品鉴之旅(一)

    Redis之品鉴之旅(一) 好知识就如好酒,需要我们坐下来,静静的慢慢的去品鉴.Redis作为主流nosql数据库,在提升性能的方面是不可或缺的.下面就拿好小板凳,我们慢慢的来一一品鉴. 1)redi ...