簡體   English   中英

Python“屬性”和“屬性”有什么區別?

[英]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 裝飾器。

http://docs.python.org/library/functions.html#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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM