使用@property
来源:互联网 发布:党章党规面前知敬畏 编辑:程序博客网 时间:2024/06/06 01:43
1.转载一
在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改:
s = Student()s.score = 9999
这显然不合逻辑。为了限制score的范围,可以通过一个set_score()
方法来设置成绩,再通过一个get_score()
来获取成绩,这样,在set_score()
方法里,就可以检查参数:
class Student(object): def get_score(self): return self._score def set_score(self, value): if not isinstance(value, int): raise ValueError('score must be an integer!') if value < 0 or value > 100: raise ValueError('score must between 0 ~ 100!') self._score = value
现在,对任意的Student实例进行操作,就不能随心所欲地设置score了:
>>> s = Student()>>> s.set_score(60) # ok!>>> s.get_score()60>>> s.set_score(9999)Traceback (most recent call last): ...ValueError: score must between 0 ~ 100!
但是,上面的调用方法又略显复杂,没有直接用属性这么直接简单。
有没有既能检查参数,又可以用类似属性这样简单的方式来访问类的变量呢?对于追求完美的Python程序员来说,这是必须要做到的!
还记得装饰器(decorator)可以给函数动态加上功能吗?对于类的方法,装饰器一样起作用。Python内置的@property
装饰器就是负责把一个方法变成属性调用的:
class Student(object): @property def score(self): return self._score @score.setter def score(self, value): if not isinstance(value, int): raise ValueError('score must be an integer!') if value < 0 or value > 100: raise ValueError('score must between 0 ~ 100!') self._score = value
@property
的实现比较复杂,我们先考察如何使用。把一个getter方法变成属性,只需要加上@property
就可以了,此时,@property
本身又创建了另一个装饰器@score.setter
,负责把一个setter方法变成属性赋值,于是,我们就拥有一个可控的属性操作:
>>> s = Student()>>> s.score = 60 # OK,实际转化为s.set_score(60)>>> s.score # OK,实际转化为s.get_score()60>>> s.score = 9999Traceback (most recent call last): ...ValueError: score must between 0 ~ 100!
注意到这个神奇的@property
,我们在对实例属性操作的时候,就知道该属性很可能不是直接暴露的,而是通过getter和setter方法来实现的。
还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性:
class Student(object): @property def birth(self): return self._birth @birth.setter def birth(self, value): self._birth = value @property def age(self): return 2014 - self._birth
上面的birth
是可读写属性,而age
就是一个只读属性,因为age
可以根据birth
和当前时间计算出来。
小结
@property
广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。
Python中有一个被称为属性函数(property)的小概念,它可以做一些有用的事情。在这篇文章中,我们将看到如何能做以下几点:
- 将类方法转换为只读属性
- 重新实现一个属性的setter和getter方法
在本文中,您将学习如何以几种不同的方式来使用内置的属性函数。希望读到文章的末尾时,你能看到它是多么有用。
开始
使用属性函数的最简单的方法之一是将它作为一个方法的装饰器来使用。这可以让你将一个类方法转变成一个类属性。当我需要做某些值的合并时,我发现这很有用。其他想要获取它作为方法使用的人,发现在写转换函数时它很有用。让我们来看一个简单的例子:
- ########################################################################
- class Person(object):
- """"""
- #----------------------------------------------------------------------
- def __init__(self, first_name, last_name):
- """Constructor"""
- self.first_name = first_name
- self.last_name = last_name
- #----------------------------------------------------------------------
- @property
- def full_name(self):
- """
- Return the full name
- """
- return "%s %s" % (self.first_name, self.last_name)
- >>> person = Person("Mike", "Driscoll")
- >>> person.full_name
- 'Mike Driscoll'
- >>> person.first_name
- 'Mike'
- >>> person.full_name = "Jackalope"
- Traceback (most recent call last):
- File "<string>", line 1, in <fragment>
- AttributeError: can't set attribute
- >>> person.first_name = "Dan"
- >>> person.full_name
- 'Dan Driscoll'
这是一种限制,因此让我们来看看另一个例子,其中我们可以创建一个允许设置的属性。
使用Python property取代setter和getter方法
让我们假设我们有一些遗留代码,它们是由一些对Python理解得不够好的人写的。如果你像我一样,你之前已经看到过这类的代码:
- from decimal import Decimal
- ########################################################################
- class Fees(object):
- """"""
- #----------------------------------------------------------------------
- def __init__(self):
- """Constructor"""
- self._fee = None
- #----------------------------------------------------------------------
- def get_fee(self):
- """
- Return the current fee
- """
- return self._fee
- #----------------------------------------------------------------------
- def set_fee(self, value):
- """
- Set the fee
- """
- if isinstance(value, str):
- self._fee = Decimal(value)
- elif isinstance(value, Decimal):
- self._fee = value
- >>> f = Fees()
- >>> f.set_fee("1")
- >>> f.get_fee()
- Decimal('1')
- from decimal import Decimal
- ########################################################################
- class Fees(object):
- """"""
- #----------------------------------------------------------------------
- def __init__(self):
- """Constructor"""
- self._fee = None
- #----------------------------------------------------------------------
- def get_fee(self):
- """
- Return the current fee
- """
- return self._fee
- #----------------------------------------------------------------------
- def set_fee(self, value):
- """
- Set the fee
- """
- if isinstance(value, str):
- self._fee = Decimal(value)
- elif isinstance(value, Decimal):
- self._fee = value
- fee = property(get_fee, set_fee)
- >>> f = Fees()
- >>> f.set_fee("1")
- >>> f.fee
- Decimal('1')
- >>> f.fee = "2"
- >>> f.get_fee()
- Decimal('2')
- from decimal import Decimal
- ########################################################################
- class Fees(object):
- """"""
- #----------------------------------------------------------------------
- def __init__(self):
- """Constructor"""
- self._fee = None
- #----------------------------------------------------------------------
- @property
- def fee(self):
- """
- The fee property - the getter
- """
- return self._fee
- #----------------------------------------------------------------------
- @fee.setter
- def fee(self, value):
- """
- The setter of the fee property
- """
- if isinstance(value, str):
- self._fee = Decimal(value)
- elif isinstance(value, Decimal):
- self._fee = value
- #----------------------------------------------------------------------
- if __name__ == "__main__":
- f = Fees()
- >>> f = Fees()
- >>> f.fee = "1"
如果你看属性函数的说明,它有fget, fset, fdel和doc几个参数。如果你想对属性使用del命令,你可以使用@fee.deleter创建另一个装饰器来装饰相同名字的函数从而实现删除的同样效果。
结束语
现在你知道如何在你的类中使用Python的属性函数。希望你能找到更有用的方式,在你的代码中使用它们。
补充阅读:
- Python中的getter和setter方法
- 官方Python文档中对property的介绍
- StackOverflow中对给Python属性函数增加文档字符串的一个讨论
- 使用@property
- 使用@property
- 使用@property
- 使用@property
- 使用@property
- 使用@property
- 使用Property设置ORBInitRef
- property的使用
- @property使用属性说明
- @property 的使用
- ARC之@property使用
- ant的property使用
- objective-c @property 使用
- @property , @synthesize 使用
- <s:property>使用
- @property 的使用
- 关于@property的使用
- OC属性property使用
- html设置表主体格式
- 安卓学习笔记(四):加载器Loaders 跟着API指南来学习
- html设置表尾格式
- 如何在Oracle中实现SELECT TOP N的方法
- HBase vs. MongoDB vs. MySQL vs. Oracle vs. Redis,三大主流开源 NoSQL 数据库的 PK 两大主流传统 SQL 数据库
- 使用@property
- 数据库外键的使用
- (一)STL之list
- Linux操作系统下/etc/hosts文件详解
- The JSP specification requires that an attribute name is preceded by whitespace
- RecyclerView上拉刷新,下拉加载
- C#使用DataSet Datatable更新数据库的三种实现方法
- POJ 3516 数学期望 解题报告
- 四边形不等式优化讲解(详解)