问题:Python的“属性”和“属性”之间有什么区别?
我通常对“属性”和“属性”之间的区别感到困惑,并且找不到合适的资源来简洁地详细说明这些区别。
I am generally confused about the difference between a “property” and an “attribute”, and can’t find a great resource to concisely detail the differences.
回答 0
属性是一种特殊的属性。基本上,当Python遇到以下代码时:
spam = SomeObject()
print(spam.eggs)
它查找eggs
中spam
,然后检查eggs
,看它是否有一个__get__
,__set__
或__delete__
方法-如果这样做,这是一个性质。如果它是一个属性,则不仅会返回该eggs
对象(就像对其他任何属性一样),还会调用该__get__
方法(因为我们一直在进行查找),并返回该方法返回的内容。
有关Python的数据模型和描述符的更多信息。
Properties are a special kind of attribute. Basically, when Python encounters the following code:
spam = SomeObject()
print(spam.eggs)
it looks up eggs
in spam
, and then examines eggs
to see if it has a __get__
, __set__
, or __delete__
method — if it does, it’s a property. If it is a property, instead of just returning the eggs
object (as it would for any other attribute) it will call the __get__
method (since we were doing lookup) and return whatever that method returns.
More information about Python’s data model and descriptors.
回答 1
有了属性,您就可以完全控制其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
With a property you have complete control on its getter, setter and deleter methods, which you don’t have (if not using caveats) with an attribute.
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
回答 2
一般来说,属性和属性是同一件事。但是,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
In general speaking terms a property and an attribute are the same thing. However, there is a property decorator in Python which provides getter/setter access to an attribute (or other data).
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
回答 3
该属性使您可以像获取普通属性一样获取和设置值,但是在其下面有一种方法称为为您将其转换为getter和setter。减少调用getter和setter的样板实际上只是一种便利。
例如,假设您有一个类,其中包含一些您需要的x和y坐标。要设置它们,您可能需要执行以下操作:
myObj.x = 5
myObj.y = 10
与编写相比,这看起来更容易思考和思考:
myObj.setX(5)
myObj.setY(10)
问题是,如果某一天您的Class发生变化,从而需要将x和y偏移一些值,该怎么办?现在,您需要进入并更改您的类定义以及所有调用它的代码,这可能非常耗时且容易出错。该属性使您可以使用前一种语法,同时又可以灵活地更改后者。
在Python中,您可以使用property函数定义getter,setter和delete方法。如果只需要read属性,则可以在方法上方添加一个@property装饰器。
http://docs.python.org/library/functions.html#property
The property allows you to get and set values like you would normal attributes, but underneath there is a method being called translating it into a getter and setter for you. It’s really just a convenience to cut down on the boilerplate of calling getters and setters.
Lets say for example, you had a class that held some x and y coordinates for something you needed. To set them you might want to do something like:
myObj.x = 5
myObj.y = 10
That is much easier to look at and think about than writing:
myObj.setX(5)
myObj.setY(10)
The problem is, what if one day your class changes such that you need to offset your x and y by some value? Now you would need to go in and change your class definition and all of the code that calls it, which could be really time consuming and error prone. The property allows you to use the former syntax while giving you the flexibility of change of the latter.
In Python, you can define getters, setters, and delete methods with the property function. If you just want the read property, there is also a @property decorator you can add above your method.
http://docs.python.org/library/functions.html#property
回答 4
总的来说,我从Bernd Klein的网站中学到了2个区别 :
1.属性是一种更方便的数据封装方式。
例如:如果您具有对象的公共属性长度,那么以后,您的项目需要您对其进行封装,即:将其更改为私有并提供getter和setter =>您必须更改之前编写的许多代码:
#Old codes
obj1.length=obj1.length+obj2.length
#New codes(Using private attibutes and getter and setter)
obj1.set_lenght(obj1.get_length()+obj2.get_length()) #=> this is ugly
如果使用@property和@ lenght.setter =>,则无需更改这些旧代码
2.一个属性可以封装多个属性
class Person:
def __init__(self, name, physic_health, mental_health):
self.name=name
self.__physic_health=physic_health #physic_health is real value in range [0, 5.0]
self.__mental_health=mental_health #mental_health is real value in range [0, 5.0]
@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
是私有的并且不能直接从外部访问,所以类外部与之交互的唯一方法是通过属性condition
I learnt 2 differences from site of Bernd Klein, in summary:
1. A property is a more convenient way to achieve data encapsulation
For example, let’s say you have a public attribute length
. Later on, your project requires you to encapsulate it, i.e. to change it to private and provide a getter and setter => you have to change the the code you wrote before:
# 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
If you use @property
and @length.setter
=> you don’t need to change that old code.
2. A property can encapsulate multiple attributes
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!"
In this example, __physic_health
and __mental_health
are private and cannot be accessed directly from outside.
回答 5
我用来缓存或刷新数据还有一个不明显的区别,通常我们有一个连接到class属性的函数。例如,我需要读取一次文件并将内容分配给该属性,以便将值缓存:
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
There is also one not obvious difference that i use to cache or refresh data , often we have a function connected to class attribute. For instance i need to read file once and keep content assigned to the attribute so the value is cached:
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
Output:
func running
func value
func value
We accessed the attribute twice but our function was fired only once. Changing the above example to use property will cause attribute’s value refresh each time you access it:
class Misc():
@property
def test(self):
print 'func running'
return 'func value'
cl = Misc()
print cl.test
print cl.test
Output:
func running
func value
func running
func value