神奇的Python property装饰器:1行代码让Python方法秒变属性

1. property装饰器的基本用法
在讲property装饰器之前,先来看一个例子:
class MyClass: def __init__(self, word): self._word = word def word(self): return self._word
my = MyClass('Hello')print(my.word())print(my.word)
执行这段代码,会输出如下的结果:
Hello<bound method MyClass.word of <__main__.MyClass object at 0x7fee500b61f0>>
这段代码的主要功能就是通过word方法返回一个字符串。而最后一行直接访问了word方法。在Python语言中,任何东西都可视为对象,方法也不例外。所以直接输出了word方法的对象形式。
不过my.word这种调用形式,其实也是访问属性的方式,所以这段代码也可以看做将word方法作为属性使用,而不是获取word对象本身。因此,如果要想将word方法作为属性使用,就要使用property装饰器。下面看一下改进的代码:
class MyClass: def __init__(self, word): self._word = word # 将word方法变成属性 @property def word(self): return self._word
my = MyClass('Hello')# 输出Helloprint(my.word)
这段代码使用@property修饰了word方法,这时就会将word方法直接变成了属性,所以可以使用my.word形式调用word方法,运行这段代码,会输出Hello。
我们可以看到,只需要1行代码,就可以将任何一个普通的Python方法变成属性。
如果用@property修饰方法,那么就不能再当做方法调用了,例如,不能再使用my.word()形式调用word方法了,否则会抛出如下异常:
2. property装饰器的原理
可能有很多小伙伴感到很神奇,为何直接用@property修饰方法,就可以将Python方法变成属性呢?本节就来详细描述property装饰器的原理。
首先要了解property到底是什么,使用下面的代码输出property:
print(property)
输出结果如下:
<class 'property'>
很明显,property是一个类。而Python装饰器其实就是一个语法糖,本质上是将Python装饰器作为函数使用,并将被修饰器修饰的方法/函数作为参数值传入装饰器函数。例如,使用@property装饰word方法,那么就相当于使用下面的代码包装word方法:
property(word)
也就是说,word方法被@property修饰后,就会变成property类的实例。
可以用下面的代码来演示property装饰器的原理。在这段代码中,使用@property修饰了word方法,而new_word方法直接通过创建property实例的方式修饰。
class MyClass: def __init__(self, word): self._word = word @property def word(self): return self._word # 输出被修饰的word方法的类型 print('word:', type(word))
def new_word(self): return self._word # 输出未被修饰的new_word方法的类型 print('new_word:', type(new_word)) new_word = property(new_word) print(type(new_word))my = MyClass('android')
print(my.word)print(my.new_word)
执行这段代码,会输出如下内容:
从输出结果可以看出,被@property修饰的word方法的类型是property类,而未被@property修饰的new_word方法的类型是function类。而且通过创建property实例的方式包装的new_word方法也可以当做属性使用,与下面的代码等效:
@propertydef new_word(self):    return self._word
3. 让属性可写、可删除
用@property修饰的方法是只读属性,既不可以写,也不可以删除,否则会抛出异常。
如果使用my.word = 'new'设置word属性,会抛出如下异常。
如果使用del my.word删除word属性,会抛出如下异常:
其实property类还有setter方法和deleter方法,可以将属性变成可写和可删除的,先看下面的代码:
class MyClass: def __init__(self, word): self._word = word @property def word(self): return self._word # 设置可写属性 @word.setter def word(self, value): self._word = value # 设置可删除属性,删除word属性时会调用该方法 @word.deleter def word(self): print('delete word') self._word = '' # 通过创建property实例的方式将new_word方法变成可读写和可删除的 def new_word(self): return self._word # 将new_word变成只读的属性,并且需要将property实例赋给一个新的变量,否则会被后面的new_word方法覆盖 new_word1 = property(new_word) def new_word(self, value): self._word = value # 将new_word变成可写的属性 new_word1 = new_word1.setter(new_word)
def new_word(self): print('delete new word') # 将new_word变成可删除的属性 new_word = new_word1.deleter(new_word)

my = MyClass('hello')
print(my.word)my.word = 'world' # def word(self, value):print(my.word)del my.wordprint(my.word)
print('---------')my = MyClass('ios')
print(my.new_word)my.new_word = 'harmony'print(my.new_word)del my.new_wordprint(my.new_word)
执行这段代码啊,会输出如下内容:
4. 获得原始方法
用@property修饰的方法,就会被property实例取代。那么如何获取原始的方法呢?这就要通过property类的如下3个方法:
(1)fget:获取被@property或@property.getter修饰的方法
(2)fset:获取被@property.setter修饰的方法
(3)fdel:获取被@property.deleter修饰的方法
在下面的例子中,分别获取了word属性的3个原始方法,并且调用了这3个原始方法
class MyClass:    def __init__(self, word):        self._word = word    @property    def word(self):        return self._word    @word.setter    def word(self, value):        self._word = value    @word.deleter    def word(self):        print('delete word')        self._word = ''    fget_word = word.fget    fset_word = word.fset    fdel_word = word.fdelmy = MyClass('android')print(my.fget_word())my.fset_word('harmony')print(my.fget_word())print(my.fdel_word())
执行这段代码,会输出如下的结果。
- EOF -
(0)

相关推荐

  • 感觉自己的代码很乱?因为你不懂套路

    编程教室开了这么久,已经有很多人从完全零基础的小白成为了会写代码的菜鸟程序员,能够自己独立开发程序.不过到此阶段,常常会遇到瓶颈,感觉功能可以实现,但代码看起来有些别扭: 代码中有很多相似的重复代码 ...

  • 面向对象编程(二)

    使用__slots__ 正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性.先定义class: class Student ...

  • 第20天:Python 之装饰器

    第20天:Python 之装饰器

  • 一文看懂Python的装饰器

    在 Python 中使用装饰器,可以在不修改代码的前提下,为已有的函数添加新功能,例如打印日志.缓存数据等. 为什么需要装饰器 假如你要为某个函数添加新功能.直接的办法是,在该函数中实现这个功能,或者 ...

  • Python学习—装饰器

    学习Python已经有一段时间了,陆续学了一些基础部分,但是理解的不是很深刻,每过一段时间就会忘记,所以不得不写一些博客进行记录,加深自己的理解.这两个星期一直在研究装饰器,开始觉得很简单,但是只知其 ...

  • 实战:使用 Python 用不到 10 行代码计算汽车数量

    重磅干货,第一时间送达 在这篇文章中,将教你如何使用 Python 用 10 行代码构建自己的汽车计数器程序.本文所依赖的 python 库: opencv-pythoncvlib matplotli ...

  • 只需 10 行代码,Python 教你自制屏幕翻译工具,高效办公

    只需 10 行代码,Python 教你自制屏幕翻译工具,高效办公

  • 经脉循行记不住?试试这个方法秒变记忆大师!

    十二条经脉循行路线,是学习经络的基础,如何有效地记住它,有许多简单实用的方法可以借鉴.今天,小编带来一种简单的记忆方法,希望对大家能有所帮助.一起去看看吧~~ 一. 肺 起点:中焦 主要站点:大肠→胃 ...

  • Python 中的函数装饰器和闭包

    函数装饰器可以被用于增强方法的某些行为,如果想自己实现装饰器,则必须了解闭包的概念. 装饰器的基本概念 装饰器是一个可调用对象,它的参数是另一个函数,称为被装饰函数.装饰器可以修改这个函数再将其返回, ...

  • Selenium2+python自动化55-unittest之装饰器(@classmethod)

    前言 前面讲到unittest里面setUp可以在每次执行用例前执行,这样有效的减少了代码量,但是有个弊端,比如打开浏览器操作,每次执行用例时候都会重新打开,这样就会浪费很多时间. 于是就想是不是可以 ...

  • 浅析Python装饰器

    浅析Python装饰器