我通常对“属性”和“属性”之间的区别感到困惑,并且找不到一个很好的资源来简要地详细说明它们的区别。
一般来说,属性和属性是一样的东西。然而,Python中有一个属性装饰器,它提供了对属性(或其他数据)的getter/setter访问。
class MyObject(object):
# This is a normal attribute
foo = 1
@property
def bar(self):
return self.foo
@bar.setter
def bar(self, value):
self.foo = value
obj = MyObject()
assert obj.foo == 1
assert obj.bar == obj.foo
obj.bar = 2
assert obj.foo == 2
assert obj.bar == obj.foo
对于一个属性,你可以完全控制它的getter, setter和deleter方法,这是你在属性中所没有的(如果没有使用警告的话)。
class A(object):
_x = 0
'''A._x is an attribute'''
@property
def x(self):
'''
A.x is a property
This is the getter method
'''
return self._x
@x.setter
def x(self, value):
"""
This is the setter method
where I can check it's not assigned a value < 0
"""
if value < 0:
raise ValueError("Must be >= 0")
self._x = value
>>> a = A()
>>> a._x = -1
>>> a.x = -1
Traceback (most recent call last):
File "ex.py", line 15, in <module>
a.x = -1
File "ex.py", line 9, in x
raise ValueError("Must be >= 0")
ValueError: Must be >= 0
该属性允许您像普通属性一样获取和设置值,但在下面有一个方法被调用,将其转换为getter和setter。这实际上只是为了减少调用getter和setter的样板文件。
举个例子,你有一个类,它为你需要的东西保存了一些x和y坐标。要设置它们,你可能需要这样做:
myObj.x = 5
myObj.y = 10
这比写作更容易理解和思考:
myObj.setX(5)
myObj.setY(10)
问题是,如果有一天你的类发生了变化,你需要用一些值来抵消x和y,该怎么办?现在,您需要更改类定义和调用它的所有代码,这可能非常耗时且容易出错。该属性允许您使用前一种语法,同时允许您灵活更改后一种语法。
在Python中,可以使用属性函数定义getter、setter和delete方法。如果你只想要read属性,你还可以在你的方法上面添加一个@property装饰器。
http://docs.python.org/library/functions.html#property
属性是一种特殊的属性。基本上,当Python遇到以下代码时:
spam = SomeObject()
print(spam.eggs)
它在垃圾邮件中查找鸡蛋,然后检查鸡蛋是否有__get__, __set__或__delete__方法——如果有,它是一个属性。如果它是一个属性,它将不只是返回eggs对象(就像其他任何属性一样),而是调用__get__方法(因为我们在做查找)并返回该方法返回的任何内容。
更多关于Python数据模型和描述符的信息。
我从Bernd Klein site中学到了2个不同之处,总结如下:
1. 属性是实现数据封装的更方便的方式
例如,假设您有一个公共属性长度。稍后,你的项目需要你封装它,即改变它为私有并提供一个getter和setter =>,你必须改变你之前写的代码:
# Old code
obj1.length = obj1.length + obj2.length
# New code (using private attributes and getter and setter)
obj1.set_length(obj1.get_length() + obj2.get_length()) # => this is ugly
如果你使用@property和@length。Setter =>你不需要改变旧的代码。
2. 一个属性可以封装多个属性
class Person:
def __init__(self, name, physic_health, mental_health):
self.name = name
self.__physic_health = physic_health
self.__mental_health = mental_health
@property
def condition(self):
health = self.__physic_health + self.__mental_health
if(health < 5.0):
return "I feel bad!"
elif health < 8.0:
return "I am ok!"
else:
return "Great!"
在这个例子中,__physic_health和__mental_health是私有的,不能从外部直接访问。
还有一个不明显的区别,我使用缓存或刷新数据,通常我们有一个函数连接到类属性。例如,我需要读取文件一次,并保留分配给属性的内容,以便该值被缓存:
class Misc():
def __init__(self):
self.test = self.test_func()
def test_func(self):
print 'func running'
return 'func value'
cl = Misc()
print cl.test
print cl.test
输出:
func running
func value
func value
我们访问了属性两次,但是我们的函数只被触发了一次。将上面的例子改为使用property将导致每次访问它时属性的值刷新:
class Misc():
@property
def test(self):
print 'func running'
return 'func value'
cl = Misc()
print cl.test
print cl.test
输出:
func running
func value
func running
func value
我喜欢这样想,如果你想为一个属性设置限制,那就使用一个属性。
尽管所有属性都是公共的,但程序员通常用下划线(_)来区分公共属性和私有属性。考虑下面的类,
class A:
def __init__(self):
self.b = 3 # To show public
self._c = 4 # To show private
在这里,b属性意在从类A外部访问。但是,这个类的读者可能想知道,b属性可以从类A外部设置吗?
如果我们不打算从外部设置b,我们可以使用@property来显示这个意图。
class A:
def __init__(self):
self._c = 4 # To show private
@property
def b(self):
return 3
现在,b不能被设置。
a = A()
print(a.b) # prints 3
a.b = 7 # Raises AttributeError
或者,如果您希望只设置某些值,
class A:
@property
def b(self):
return self._b
@b.setter
def b(self, val):
if val < 0:
raise ValueError("b can't be negative")
self._b = val
a = A()
a.b = 6 # OK
a.b = -5 # Raises ValueError
推荐文章
- 输入对象的datetime。Datetime没有Datetime属性
- numpy数组的Python内存使用情况
- NumPy或Pandas:保持数组类型为整数,同时具有NaN值
- 列表理解条件中的' elif '
- Python的“property”和“attribute”有什么区别?
- 在Python中格式化多行字典的正确方法是什么?
- 向异常添加信息?
- Sphinx autodoc不够自动
- 如何限制Django模型中数值字段的最大值?
- 访问对象内存地址
- 为什么在Python方法中需要显式地有“self”参数?
- 如何升级Windows 10下的Python安装?
- tqdm在Jupyter笔记本重复打印新的进度条
- 如何在for循环中注释类型?
- 如何替换一个Pandas数据框架的字符串列中的文本?