作者Hsins (迅雷不及掩耳盗铃)
看板Python
标题Re: [问题] Django 的 @property
时间Mon Feb 3 02:59:50 2020
这件事情要从物件导向先开始说起。
在物件导向程式设计(Object-Oriented Programming)的理念下,我们将原本在
程序式程式设计(Procedural Programming) 中的变数和函数对应到物件的属性
与方法,宣告类别作为实例物件的基础,以此达到封装(Encapsulation)、继承
(Inhertitance)和多型(polymorphism)这三大物件导向的特性。 这里暂且不
提其他内容,先聊聊
封装这件事:
---
在物件导向程式设计方法中,封装是指,一种将抽象性函式介面的实作细节
部份包装、隐藏起来的方法。同时,它也是一种防止外界呼叫端,去存取物
件内部实作细节的手段,这个手段是由程式语言本身来提供的。
---
简单来说,一个类别在定义时可以决定自己所属的属性和方法是否能够被其他类
别所使用。在 Java 中,开发者习惯撰写所谓的
setter 与
getter 来对类别下
的
私有属性进行取值和赋值(或更新)的操作,在 Python 中可能会写成这样:
```python
class MyClass:
def __init__(self, value):
self._value = value
def get_value(self):
return self._value
def set_value(self, value):
self._value = value
# create the object
my_object = MyClass(100)
# get the value
print(my_object.get_value())
# set the value
my_object.set_value(200)
```
只是这样写起来不够 Pythonic,所以在 Python 2.2 之後新增了
@property 这
个装饰器,让开发者可以直接存取类别的属性,而在需要时又可以如同使用一般
公开属性一样地对私有属性进行访问与修改:
```python
class MyClass:
def __init__(self, value):
self._value = value
@property
def value(self):
return self._value
@value.setter
def value(self, value):
self._value = value
# create the object
my_object = MyClass(100)
# get the value
print(my_object.value)
# set the value
my_object.value = 200
```
这样一来在使用起来就不用呼叫 getter 和 setter 而是采用很直观的点操作符
来存取物件的属性,但实际上这个属性仍然是私有的(不过其实 Python 中的属
性严格说起来并不私有... )。然而
虽然取得属性值与设定值时的作法看起来是
一样的,但他其实是调用你所定义的不同方法,只是透过 @property 这个装饰
器来实现这样的结果。
※ 引述《Philethan (Ethan)》之铭言:
: 大家好,小弟大概知道 @property 有助於日後修改 class 的参数条件限制,
: 例如几个月前我定义了球类(class Ball),接着我建立了数十颗球,现在才
: 想起我忘记强调它的半径必须大於零,所以倘若还要制定一个 set_radius()
: 来限制半径,那麽我得回去将所有 ball.radius = 10 之类的程式码都修改为
: ball.set_radius(10),这会很麻烦,所以就有了 @property 这种东西出来。
: 不过我不知道怎麽将上述我对 @property 的理解,应用在底下 Django 中QQ
: 我正在读 "Django Tutorial Part 8: User authentication and permissions"
: https://reurl.cc/xD5g8E
: 其中有一段程式码为(https://i.imgur.com/HMcdolW.png):
: @property
: def is_overdue(self):
: if self.due_back and date.today() > self.due_back:
: return True
: return False
: 就我理解,这段程式码的用意在於检查「书籍借阅是否已过期」,所以总觉得
: 如果我拿掉 @property,好像也有相同效果?(测试结果:拿掉 @property 後,
: 确实看不出有什麽异样)。另外,这里似乎也没有修改资料库中的任何资料,
: 所以我就也无法用上述的「球半径的例子」来理解这里的 @property 用途 QQ
: 另外,我有在 StackOverflow 查到:
: "What the @property decorator does, is declare that
: it can be accessed like it's a regular property."
: https://stackoverflow.com/questions/58558989/what-does-djangos-property-do
: 但我还是不太懂 QQ
: 还请各位大大协助,谢谢您们!
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 140.112.247.1 (台湾)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/Python/M.1580669992.A.EF4.html
1F:推 Philethan: @O@ 未看先推!! 02/03 09:59
2F:推 Philethan: 这让我想起,我好像有在 python docs(?) 看到其实"取值 02/03 10:06
3F:→ Philethan: "(点操作)并不是直接取,而是会先检查有没有定义 02/03 10:07
4F:→ Philethan: __get__ 与 __set__,有的话那就用(就是property), 02/03 10:07
5F:→ Philethan: 没有的话就直接取,找它的 class member 02/03 10:08
6F:→ Philethan: 所以,若在 def is_overdue(self) 前加上 @property 02/03 10:09
7F:→ Philethan: 那麽就可以更 pythonic,把 is_overdue() 函数看成 02/03 10:09
8F:→ Philethan: 一种变数,应该是这意思罗?感谢大大教学~~ 02/03 10:10
9F:→ Philethan: 虽然总觉得这种"把函数看成变数"的背後机制,似乎跟 02/03 10:10
10F:→ Philethan: 刚才提的"先检查有没有定义__get__与__set__"不太一样 02/03 10:10
11F:推 Philethan: 哦哦我在 python docs 看到了! 02/03 10:14
12F:→ Philethan: The @property decorator turns the .... method into 02/03 10:15
13F:→ Philethan: a "getter" for a read-only attribute with the same 02/03 10:15
16F:推 cuteSquirrel: push 02/03 21:46
17F:推 Ryspon: 推个 02/06 02:16
18F:推 AugustusHsu: 推个~ 02/21 18:02
※ 编辑: Hsins (1.162.105.89 台湾), 01/27/2021 17:20:57