ความแตกต่างระหว่าง Python“ คุณสมบัติ” และ“ attribute” คืออะไร?


146

โดยทั่วไปฉันสับสนเกี่ยวกับความแตกต่างระหว่าง "คุณสมบัติ" และ "แอตทริบิวต์" และไม่สามารถหาแหล่งข้อมูลที่ดีเพื่อสรุปความแตกต่างได้อย่างชัดเจน

คำตอบ:


184

คุณสมบัติเป็นแอตทริบิวต์ชนิดพิเศษ โดยทั่วไปเมื่อ Python พบรหัสต่อไปนี้:

spam = SomeObject()
print(spam.eggs)

มันเงยหน้าขึ้นมองeggsในspamและจากนั้นจะตรวจสอบeggsเพื่อดูว่ามันมี__get__, __set__หรือ__delete__วิธี - ถ้ามันไม่เป็นสถานที่ให้บริการ ถ้ามันเป็นคุณสมบัติแทนที่จะส่งคืนeggsวัตถุ (เช่นเดียวกับคุณสมบัติอื่น ๆ ) มันจะเรียก__get__เมธอด (เนื่องจากเราทำการค้นหา) และคืนสิ่งที่วิธีนั้นกลับมา

ข้อมูลเพิ่มเติมเกี่ยวกับรูปแบบข้อมูลหลามและอธิบาย


ดูเหมือนว่าคุณสมบัติเกี่ยวข้องกับการประมวลผลเพิ่มเติมเพื่อเข้าถึงค่าเป้าหมาย ... คุณรู้หรือไม่ว่ามันมีความสำคัญ / ช้าลงเพียงใด?
martineau

@ Smartineau: มีการเรียกฟังก์ชั่นพิเศษหนึ่งครั้ง แต่ส่วนใหญ่แล้วงานพิเศษและเวลาจะขึ้นอยู่กับจำนวนทรัพย์สินที่กำลังทำอยู่ (คำแนะนำทั่วไป: ห้ามทำ / ไม่ใช้คุณสมบัติเพื่อซ่อน I / O)
Ethan Furman

56

ด้วยคุณสมบัติที่คุณมีการควบคุมที่สมบูรณ์ในวิธีการทะเยอทะยาน setter และ deleter ซึ่งคุณไม่ได้มี (ถ้าไม่ได้ใช้ caveats) ด้วยคุณสมบัติ

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

("การควบคุมที่สมบูรณ์") นี้สามารถทำได้ด้วยคุณลักษณะ "ที่ไม่ใช่คุณสมบัติ" เช่นกันโดยไม่ต้องใช้เครื่องมือตกแต่งอย่างง่าย

8
ฉันชอบที่คำตอบนี้ให้ตัวอย่างที่เป็นจริงและมีประโยชน์ ฉันรู้สึกว่าคำตอบมากมายในเว็บไซต์นี้ไม่จำเป็นต้องอธิบายว่าสิ่งต่าง ๆ ทำงานอย่างไรกับส่วนหลังโดยไม่ต้องชี้แจงว่าผู้ใช้ควรโต้ตอบกับพวกเขาอย่างไร หากไม่มีใครเข้าใจว่าทำไม / เมื่อต้องใช้ฟังก์ชั่นบางอย่างไม่มีประโยชน์ที่จะรู้ว่ามันทำงานอย่างไรเบื้องหลัง
Tom

คำตอบนี้ละเมิด "Zen of Python - ควรมีอย่างใดอย่างหนึ่งและดีกว่าเพียงหนึ่ง - วิธีที่ชัดเจนที่จะทำ" มี 2 ​​วิธีในการตั้งค่า x
Tin Luu

@TinLuu - มีวิธีเดียวเท่านั้นในการตั้งค่าของ x นอกจากนี้ยังมีวิธีเดียวเท่านั้นในการตั้งค่าของ _x ความจริงที่ว่าพวกเขาเป็นสิ่งเดียวกันคือรายละเอียดการใช้งาน ผู้ใช้ที่ชาญฉลาดของคลาสนี้ไม่ได้ใช้ _x
สว่าง

1
@TinLuu - ฉันคิดว่าเราทั้งคู่กำลังพูดสิ่งเดียวกันจากมุมมองตรงข้าม xผู้ใช้ของชั้นควรดู ทางเดียว. หากผู้ใช้ของชั้นเรียนพบเกี่ยวกับ _x พวกเขาใช้มันด้วยความเสี่ยงของตัวเอง
สว่าง

19

โดยทั่วไปแล้วคำพูดคุณสมบัติและคุณสมบัติเป็นสิ่งเดียวกัน อย่างไรก็ตามมี decorator คุณสมบัติใน 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

1
คุณช่วยพูดถึงผลลัพธ์ที่คาดหวังของรหัสนี้ได้หรือไม่
Hasan Iqbal

2
คุณหมายถึงอะไร ไม่ใช่ที่ด้านล่างของรหัสใช่หรือไม่
six8

12

คุณสมบัติช่วยให้คุณได้รับและตั้งค่าเช่นเดียวกับที่คุณทำกับคุณสมบัติปกติ แต่ภายใต้มีวิธีการที่เรียกว่าการแปลเป็น getter และ setter สำหรับคุณ เป็นเพียงความสะดวกสบายในการลดจำนวนผู้โทรเข้าและผู้ตั้งค่า

ยกตัวอย่างเช่นคุณมีคลาสที่มีค่าพิกัด x และ y สำหรับสิ่งที่คุณต้องการ หากต้องการตั้งค่าคุณอาจต้องการทำสิ่งต่อไปนี้:

myObj.x = 5
myObj.y = 10

ดูและคิดได้ง่ายกว่าเขียน:

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

ปัญหาคือเกิดอะไรขึ้นถ้าวันหนึ่งชั้นเรียนของคุณเปลี่ยนแปลงเช่นนั้นคุณต้องชดเชยค่า x และ y ของคุณด้วยค่าบางค่า? ตอนนี้คุณจะต้องเข้าไปข้างในและเปลี่ยนนิยามคลาสของคุณและรหัสทั้งหมดที่เรียกมันซึ่งอาจเสียเวลามากและเกิดข้อผิดพลาด คุณสมบัติช่วยให้คุณใช้ไวยากรณ์เดิมในขณะที่ให้ความยืดหยุ่นในการเปลี่ยนแปลงของหลัง

ใน Python คุณสามารถกำหนด getters, setters และวิธีการลบด้วยฟังก์ชั่นคุณสมบัติ หากคุณต้องการอ่านคุณสมบัติมี @ มัณฑนากรตกแต่งบ้านคุณสามารถเพิ่มวิธีการของคุณ

http://docs.python.org/library/functions.html#property


ตอบเท่านั้นที่ทำให้รู้สึกจริง!
Dude156

8

ฉันเรียนรู้ความแตกต่าง 2 อย่างจาก เว็บไซต์ของ Bernd Klein โดยสรุป:

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


8

นอกจากนี้ยังมีความแตกต่างที่เห็นได้ชัดอย่างหนึ่งที่ฉันใช้เพื่อแคชหรือรีเฟรชข้อมูลเรามักจะมีฟังก์ชั่นที่เชื่อมต่อกับแอตทริบิวต์ 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.