Python“属性”和“属性”有啥区别?
Posted
技术标签:
【中文标题】Python“属性”和“属性”有啥区别?【英文标题】:What's the difference between a Python "property" and "attribute"?Python“属性”和“属性”有什么区别? 【发布时间】:2011-11-14 13:00:23 【问题描述】:我通常对“属性”和“属性”之间的区别感到困惑,并且找不到一个很好的资源来简明扼要地详细说明这些区别。
【问题讨论】:
【参考方案1】:属性是一种特殊的属性。基本上,当 Python 遇到如下代码时:
spam = SomeObject()
print(spam.eggs)
它在spam
中查找eggs
,然后检查eggs
以查看它是否具有__get__
、__set__
或__delete__
方法 — 如果有,它就是一个属性。如果它是一个属性,它会调用__get__
方法(因为我们正在查找)而不是仅仅返回eggs
对象(因为它会返回任何其他属性)并返回任何东西方法返回。
更多关于Python's data model and descriptors的信息。
【讨论】:
听起来属性涉及访问目标值的额外处理......你知道它有多重要/慢得多吗? @martineau:嗯,有一个额外的函数调用,但很可能额外的工作和时间取决于属性正在做什么(一般建议:不要/不要/使用属性来隐藏 I/ O)。【参考方案2】:有了一个属性,你可以完全控制它的 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
【讨论】:
这个(“完全控制”)也可以用“非属性”属性来完成,只是没有这些简单的装饰器。 我喜欢这个答案提供了一个现实而有用的例子。我觉得这个网站上的太多答案不必要地解释了后端是如何工作的,而没有阐明用户应该如何与他们交互。如果人们不明白为什么/何时使用某些功能,那么了解它在幕后的运作方式就毫无意义。 这个答案违反了“Python 之禅——应该有一种——最好只有一种——明显的方法”。有两种方法可以设置 x 值。 @TinLuu - 只有一种方法可以设置 x 的值。设置_x 的值也只有一种方法。它们是同一事物的事实是实现细节。这个类的聪明用户不会使用_x。 @TinLuu - 我认为我们都在从不同的角度说同样的话。该类的用户只能看到x
。单程。如果该课程的用户发现了 _x,他们将自行承担使用它的风险。【参考方案3】:
一般来说,属性和属性是一回事。但是,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
【讨论】:
能否请您提一下这段代码的预期结果? 什么意思?这不是在代码的底部吗?【参考方案4】:该属性允许您像使用普通属性一样获取和设置值,但在下面有一个称为将其转换为您的 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
【讨论】:
只有实际意义的答案!【参考方案5】:我从 Bernd Klein 的 site 中学到了 2 个不同之处,总结如下:
1.属性是实现数据封装更便捷的方式
例如,假设您有一个公共属性length
。稍后,您的项目需要您对其进行封装,即将其更改为私有并提供 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
是私有的,不能从外部直接访问。
【讨论】:
【参考方案6】:我用来缓存或刷新数据还有一个不明显的区别,通常我们有一个连接到类属性的函数。例如,我需要读取一次文件并保留分配给属性的内容,以便缓存值:
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
我们两次访问了该属性,但我们的函数只被触发了一次。将上面的示例更改为使用属性将导致每次访问它时都会刷新属性的值:
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
【讨论】:
【参考方案7】:我喜欢这样认为,如果你想为属性设置限制,请使用属性。
虽然所有属性都是公共的,但程序员通常用下划线(_
)区分公共属性和私有属性。考虑以下类,
class A:
def __init__(self):
self.b = 3 # To show public
self._c = 4 # To show private
这里,b
属性旨在从 A 类外部访问。但是,这个类的读者可能想知道,可以从外部类 A
设置b
属性吗?
如果我们不打算从外部设置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
【讨论】:
以上是关于Python“属性”和“属性”有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章