转自: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详解及底层实现介绍的更多相关文章

  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. XSS注入

    XSS 原理: 程序对输入和输出没有做合适的处理,导致"精心构造"的字符输出在前端时被浏览器当作有效代码解析执行从而产生危害. 分类 : 危害:存储型 > 反射型 > ...

  2. CF786C-Till I Collapse【树状数组倍增,优先队列】

    正题 题目链接:https://www.luogu.com.cn/problem/CF786C 题目大意 给出一个长度为\(n\)的序列. 对于每个\(k\in[1,n]\)求将\(n\)分成最少的段 ...

  3. YbtOJ#883-最大的割【带修线性基】

    正题 题目链接:http://www.ybtoj.com.cn/contest/118/problem/3 解题思路 给出\(n\)个点,\(m\)次动态插入一条无向边询问:割掉一些边使得图中至少两点 ...

  4. Cookbook:pandas的学习之路——10 Minutes to pandas

    按照pandas官网上10 Minutes to pandas的快速练习: 一 .对象创建: 导入练习所需要的工具包: 通过列表中的值创建序列Series,pandas在创建序列的同时会默认为列表中值 ...

  5. Ubuntu安装Oracleclient远程连接数据库

    平时Oracle数据库都安装在本地或者WindowsServer上进行使用,但因为工作需要,领导要求在虚拟机中安装Ubuntu来连接Windows本地安装的数据库,先将操作过程和遇到的问题进行梳理总结 ...

  6. Java网络爬虫技术《二》Jsoup

    Jsoup 当我们成功抓取到页面数据了之后,还需要对抓取的数据进行解析,而刚好,Jsoup 是一款专门解析 html 页面的技术.Jsoup是一款基于 Java 的HTML 解析器,可直接解析某个 U ...

  7. Java AES 加密小试牛刀

    目录 问题出处 解决方法 方法一 方法二 方法三 补充 总结 在java开发过程中,很多时候我们都需要加密数据,例如声音.敏感信息等.我们通常使用的是 MD5加密.SHA加密.DES 加密.AES 加 ...

  8. 10.13 Nginx 负载均衡

    七层负载均衡server { listen 80; server_name localhost; location / { proxy_pass http://name; //调用集群 } } ups ...

  9. 无法解析的外部符号之_cvLoadImage,_cvCreateMat,_cvReleaseImage之类

    一个错误可能是:附加依赖项少添加了库函数: 还有一个可能是:配置设置错误了,比如该是64位,却设置成win32了.改过来就好了. 要注意opencv的使用中 在Debug.Release模式以及x64 ...

  10. 基本的bash shell命令

    目录 基本的bash shell命令 启动shell shell提示符 基本的bash shell命令 启动shell GNU bash shell 能提供对Linux系统的交互式访问.它是作为普通程 ...