![](/img/trans.png)
[英]What's the difference in Python between creating an attribute and declaring it in the class?
[英]What's the difference between a Python "property" and "attribute"?
我通常對“屬性”和“屬性”之間的區別感到困惑,並且找不到一個很好的資源來簡明地詳細說明這些區別。
屬性是一種特殊的屬性。 基本上,當Python遇到如下代碼時:
spam = SomeObject()
print(spam.eggs)
它在spam
查找eggs
,然后檢查eggs
以查看它是否具有__get__
、 __set__
或__delete__
方法——如果有,它就是一個屬性。 如果它是一個屬性,它會調用__get__
方法(因為我們正在執行查找)並返回該方法返回的任何內容,而不是僅僅返回eggs
對象(就像任何其他屬性一樣)。
有關Python 的數據模型和描述符的更多信息。
使用屬性,您可以完全控制其 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 中有一個屬性裝飾器,它提供對屬性(或其他數據)的 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。 減少調用 getter 和 setter 的樣板真的只是一種方便。
比方說,您有一個類,其中包含您需要的一些 x 和 y 坐標。 要設置它們,您可能需要執行以下操作:
myObj.x = 5
myObj.y = 10
這比寫作更容易看和思考:
myObj.setX(5)
myObj.setY(10)
問題是,如果有一天你的班級發生變化,你需要用某個值來抵消 x 和 y 怎么辦? 現在您需要進入並更改您的類定義和所有調用它的代碼,這可能非常耗時且容易出錯。 該屬性允許您使用前者的語法,同時為您提供更改后者的靈活性。
在 Python 中,您可以使用屬性函數定義 getter、setter 和 delete 方法。 如果您只想要 read 屬性,還可以在方法上方添加一個 @property 裝飾器。
我從 Bernd Klein 的網站了解到 2 個不同之處,總結如下:
1.屬性是更方便的實現數據封裝的方式
例如,假設您有一個公共屬性length
。 稍后,你的項目需要你封裝它,即把它改成private並提供一個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
我們訪問了該屬性兩次,但我們的函數只被觸發了一次。 將上面的示例更改為 use 屬性將導致每次訪問時刷新屬性的值:
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.