Sự khác biệt giữa thuộc tính Python và thuộc tính của Google là gì?


146

Tôi thường bối rối về sự khác biệt giữa "thuộc tính" và "thuộc tính" và không thể tìm thấy một nguồn tài nguyên tuyệt vời để chi tiết chính xác về sự khác biệt.

Câu trả lời:


184

Thuộc tính là một loại thuộc tính đặc biệt. Về cơ bản, khi Python gặp đoạn mã sau:

spam = SomeObject()
print(spam.eggs)

nó sẽ tra cứu eggstrong spam, và sau đó kiểm tra eggsđể xem nếu nó có một __get__, __set__hoặc __delete__phương pháp - nếu có, đó là một tài sản. Nếu nó một thuộc tính, thay vì chỉ trả về eggsđối tượng (như đối với bất kỳ thuộc tính nào khác), nó sẽ gọi __get__phương thức (vì chúng ta đang thực hiện tra cứu) và trả về bất cứ phương thức nào trả về.

Thông tin thêm về mô hình dữ liệu và mô tả của Python .


Có vẻ như các thuộc tính liên quan đến việc xử lý bổ sung để truy cập giá trị đích ... bạn có biết mức độ quan trọng / chậm hơn nhiều không?
martineau

@martineau: Chà, có một cuộc gọi chức năng bổ sung, nhưng rất có thể công việc làm thêm và thời gian sẽ phụ thuộc vào mức độ tài sản đang làm (lời khuyên chung: không / không / sử dụng các thuộc tính để ẩn I / O).
Ethan Furman

56

Với một thuộc tính, bạn có toàn quyền kiểm soát các phương thức getter, setter và deleter của nó, mà bạn không có (nếu không sử dụng caveats) với một thuộc tính.

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

Điều này ("kiểm soát hoàn toàn") cũng có thể được thực hiện với các thuộc tính "phi tài sản", chỉ cần không có các trang trí đơn giản như vậy.

8
Tôi thích rằng câu trả lời này cung cấp một ví dụ thực tế và hữu ích. Tôi cảm thấy rằng có quá nhiều câu trả lời trên trang web này không cần giải thích cách mọi thứ hoạt động ở mặt sau mà không làm rõ cách người dùng nên tương tác với chúng. Nếu người ta không hiểu tại sao / khi nào sử dụng một số chức năng, sẽ không có lý do gì để biết cách thức hoạt động của nó phía sau hậu trường.
Tom

Câu trả lời này vi phạm "Zen of Python - Nên có một - và tốt nhất là chỉ có một - cách rõ ràng để làm điều đó". Có 2 cách để đặt giá trị x.
Tin Lưu

@TinLuu - Chỉ có một cách để đặt giá trị của x. Cũng chỉ có một cách để đặt giá trị của _x. Thực tế là chúng giống nhau là một chi tiết thực hiện. Người dùng thông thái của lớp này không sử dụng _x.
sáng

1
@TinLuu - Tôi nghĩ rằng cả hai chúng ta đều nói cùng một điều từ hai đầu đối diện của quan điểm. Người dùng của lớp chỉ nên xem x. Một chiều. Nếu người dùng của lớp phát hiện ra về _x, họ sẽ tự chịu rủi ro khi sử dụng nó.
sáng

19

Nói chung, thuật ngữ nói chung một thuộc tính và thuộc tính là cùng một thứ. Tuy nhiên, có một trình trang trí thuộc tính trong Python cung cấp quyền truy cập getter / setter vào một thuộc tính (hoặc dữ liệu khác).

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

1
bạn có thể vui lòng đề cập đến kết quả mong đợi của mã này?
Hasan Iqbal

2
Ý anh là gì? Không phải đó là ở dưới cùng của mã?
Six8

12

Thuộc tính cho phép bạn nhận và thiết lập các giá trị như các thuộc tính thông thường, nhưng bên dưới có một phương thức được gọi là dịch nó thành getter và setter cho bạn. Nó thực sự chỉ là một sự tiện lợi để cắt giảm bản tóm tắt của việc gọi getters và setters.

Ví dụ, hãy nói rằng bạn có một lớp chứa một số tọa độ x và y cho thứ bạn cần. Để đặt chúng, bạn có thể muốn làm một cái gì đó như:

myObj.x = 5
myObj.y = 10

Điều đó dễ nhìn và suy nghĩ hơn nhiều so với viết:

myObj.setX(5)
myObj.setY(10)

Vấn đề là, điều gì sẽ xảy ra nếu một ngày nào đó lớp của bạn thay đổi đến mức bạn cần phải bù x và y của mình theo một giá trị nào đó? Bây giờ bạn sẽ cần phải đi vào và thay đổi định nghĩa lớp của bạn và tất cả các mã gọi nó, điều này có thể thực sự tốn thời gian và dễ bị lỗi. Thuộc tính cho phép bạn sử dụng cú pháp trước trong khi cung cấp cho bạn sự linh hoạt thay đổi của cú pháp sau.

Trong Python, bạn có thể định nghĩa getters, setters và xóa các phương thức với hàm property. Nếu bạn chỉ muốn thuộc tính đọc, đó cũng là một trang trí @property bạn có thể thêm ở trên phương thức của bạn.

http://docs.python.org/l Library / fiances.html #property


Chỉ trả lời mà có ý nghĩa thực tế!
Dude156

8

Tóm lại, tôi đã học được 2 điểm khác biệt từ trang Bernd Klein:

1. Tài sản là một cách thuận tiện hơn để thực hiện đóng gói dữ liệu.

vd

#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

Nếu bạn sử dụng @property và @ lenght.setter => bạn không cần thay đổi các mã cũ đó

2. Một thuộc tính có thể gói gọn nhiều thuộc tính

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!"

Trong ví dụ này, __physic_health__mental_healthlà riêng tư và không thể được truy cập trực tiếp từ bên ngoài, cách duy nhất bên ngoài lớp tương tác với chúng là thuộc tính thông quacondition


8

Ngoài ra còn có một sự khác biệt không rõ ràng mà tôi sử dụng để lưu trữ hoặc làm mới dữ liệu, thường thì chúng ta có một chức năng được kết nối với thuộc tính lớp. Chẳng hạn, tôi cần đọc tệp một lần và giữ nội dung được gán cho thuộc tính để giá trị được lưu trữ:

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

Đầu ra:

func running
func value
func value

Chúng tôi đã truy cập thuộc tính hai lần nhưng chức năng của chúng tôi chỉ bị bắn một lần. Thay đổi ví dụ trên để sử dụng thuộc tính sẽ khiến giá trị của thuộc tính được làm mới mỗi khi bạn truy cập vào nó:

class Misc():

    @property
    def test(self):
        print 'func running'
        return 'func value'

cl = Misc()
print cl.test
print cl.test

Đầu ra:

func running
func value
func running
func value
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.