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

开发 后端
用@property修饰的方法,就会被property实例取代。那么如何获取原始的方法呢?这就要通过property类的如下3个方法:(1)fget:获取被@property或@property.getter修饰的方法(2)fset:获取被@property.setter修饰的方法 (3)fdel:获取被@property.deleter修饰的方法

[[393351]]

1. property装饰器的基本用法

在讲property装饰器之前,先来看一个例子:

  1. class MyClass: 
  2.     def __init__(self, word): 
  3.         self._word = word 
  4.     def word(self): 
  5.         return self._word 
  6.  
  7. my = MyClass('Hello'
  8. print(my.word()) 
  9. print(my.word) 

执行这段代码,会输出如下的结果:

  1. Hello 
  2. <bound method MyClass.word of <__main__.MyClass object at 0x7fee500b61f0>> 

这段代码的主要功能就是通过word方法返回一个字符串。而最后一行直接访问了word方法。在Python语言中,任何东西都可视为对象,方法也不例外。所以直接输出了word方法的对象形式。

不过my.word这种调用形式,其实也是访问属性的方式,所以这段代码也可以看做将word方法作为属性使用,而不是获取word对象本身。因此,如果要想将word方法作为属性使用,就要使用property装饰器。下面看一下改进的代码:

  1. class MyClass: 
  2.     def __init__(self, word): 
  3.         self._word = word 
  4.     # 将word方法变成属性     
  5.     @property 
  6.     def word(self): 
  7.         return self._word 
  8.  
  9. my = MyClass('Hello'
  10. # 输出Hello 
  11. print(my.word) 

这段代码使用@property修饰了word方法,这时就会将word方法直接变成了属性,所以可以使用my.word形式调用word方法,运行这段代码,会输出Hello。

我们可以看到,只需要1行代码,就可以将任何一个普通的Python方法变成属性。

如果用@property修饰方法,那么就不能再当做方法调用了,例如,不能再使用my.word()形式调用word方法了,否则会抛出如下异常:

2. property装饰器的原理

可能有很多小伙伴感到很神奇,为何直接用@property修饰方法,就可以将Python方法变成属性呢?本节就来详细描述property装饰器的原理。

首先要了解property到底是什么,使用下面的代码输出property:

  1. print(property) 

输出结果如下:

  1. <class 'property'

很明显,property是一个类。而Python装饰器其实就是一个语法糖,本质上是将Python装饰器作为函数使用,并将被修饰器修饰的方法/函数作为参数值传入装饰器函数。例如,使用@property装饰word方法,那么就相当于使用下面的代码包装word方法:

  1. property(word) 

也就是说,word方法被@property修饰后,就会变成property类的实例。

可以用下面的代码来演示property装饰器的原理。在这段代码中,使用@property修饰了word方法,而new_word方法直接通过创建property实例的方式修饰。

  1. class MyClass: 
  2.     def __init__(self, word): 
  3.         self._word = word 
  4.     @property 
  5.     def word(self): 
  6.         return self._word 
  7.     # 输出被修饰的word方法的类型     
  8.     print('word:', type(word)) 
  9.  
  10.     def new_word(self): 
  11.         return self._word 
  12.     # 输出未被修饰的new_word方法的类型      
  13.     print('new_word:', type(new_word)) 
  14.     new_word = property(new_word) 
  15.     print(type(new_word)) 
  16. my = MyClass("android"
  17.  
  18. print(my.word) 
  19. print(my.new_word) 

执行这段代码,会输出如下内容:

从输出结果可以看出,被@property修饰的word方法的类型是property类,而未被@property修饰的new_word方法的类型是function类。而且通过创建property实例的方式包装的new_word方法也可以当做属性使用,与下面的代码等效:

  1. @property 
  2. def new_word(self): 
  3.     return self._word 

3. 让属性可写、可删除

用@property修饰的方法是只读属性,既不可以写,也不可以删除,否则会抛出异常。

如果使用my.word = 'new'设置word属性,会抛出如下异常。

如果使用del my.word删除word属性,会抛出如下异常:

其实property类还有setter方法和deleter方法,可以将属性变成可写和可删除的,先看下面的代码:

  1. class MyClass: 
  2.     def __init__(self, word): 
  3.         self._word = word 
  4.     @property 
  5.     def word(self): 
  6.         return self._word 
  7.     # 设置可写属性     
  8.     @word.setter 
  9.     def word(self, value): 
  10.         self._word = value 
  11.     # 设置可删除属性,删除word属性时会调用该方法     
  12.     @word.deleter 
  13.     def word(self): 
  14.         print('delete word'
  15.         self._word = '' 
  16.     # 通过创建property实例的方式将new_word方法变成可读写和可删除的 
  17.     def new_word(self): 
  18.         return self._word 
  19.     # 将new_word变成只读的属性,并且需要将property实例赋给一个新的变量,否则会被后面的new_word方法覆盖 
  20.     new_word1 = property(new_word) 
  21.     def new_word(self, value): 
  22.         self._word = value 
  23.     # 将new_word变成可写的属性 
  24.     new_word1 = new_word1.setter(new_word) 
  25.  
  26.     def new_word(self): 
  27.         print('delete new word'
  28.     # 将new_word变成可删除的属性 
  29.     new_word = new_word1.deleter(new_word) 
  30.  
  31.  
  32. my = MyClass('hello'
  33.  
  34. print(my.word) 
  35. my.word = 'world'   #  def word(self, value): 
  36. print(my.word) 
  37. del my.word 
  38. print(my.word) 
  39.  
  40. print('---------'
  41. my = MyClass('ios'
  42.  
  43. print(my.new_word) 
  44. my.new_word = 'harmony' 
  45. print(my.new_word) 
  46. del my.new_word 
  47. print(my.new_word) 

执行这段代码啊,会输出如下内容:

4. 获得原始方法

用@property修饰的方法,就会被property实例取代。那么如何获取原始的方法呢?这就要通过property类的如下3个方法:

(1)fget:获取被@property或@property.getter修饰的方法

(2)fset:获取被@property.setter修饰的方法

(3)fdel:获取被@property.deleter修饰的方法

在下面的例子中,分别获取了word属性的3个原始方法,并且调用了这3个原始方法

  1. class MyClass: 
  2.     def __init__(self, word): 
  3.         self._word = word 
  4.     @property 
  5.     def word(self): 
  6.         return self._word 
  7.     @word.setter 
  8.     def word(self, value): 
  9.         self._word = value 
  10.     @word.deleter 
  11.     def word(self): 
  12.         print('delete word'
  13.         self._word = '' 
  14.     fget_word = word.fget 
  15.     fset_word = word.fset 
  16.     fdel_word = word.fdel 
  17.  
  18. my = MyClass('android'
  19. print(my.fget_word()) 
  20. my.fset_word('harmony'
  21. print(my.fget_word()) 
  22. print(my.fdel_word()) 

执行这段代码,会输出如下的结果。

 

责任编辑:武晓燕 来源: 极客起源
相关推荐

2021-04-11 08:21:20

Python@property装饰器

2021-11-02 16:25:41

Python代码技巧

2021-01-01 14:36:03

Python开发语言

2015-12-03 10:03:38

夜神

2020-02-19 15:02:23

代码开发工具

2016-11-01 09:24:38

Python装饰器

2020-11-17 09:10:44

装饰器

2023-12-06 13:43:00

python代码

2017-04-05 11:10:23

Javascript代码前端

2010-02-01 17:50:32

Python装饰器

2021-04-07 13:43:07

PythonDash数据库

2023-02-07 07:47:52

Python装饰器函数

2024-03-08 08:00:00

Python开发装饰器

2019-11-26 09:47:50

代码开发工具

2022-02-23 14:37:48

代码Pythonbug

2022-09-19 23:04:08

Python装饰器语言

2021-02-14 13:38:17

Python开发函数

2024-01-03 08:12:10

计算求和Python内置函数

2023-01-12 09:06:55

装饰器Python

2021-06-01 07:19:58

Python函数装饰器
点赞
收藏

51CTO技术栈公众号