โดยทั่วไปฉันสับสนเกี่ยวกับความแตกต่างระหว่าง "คุณสมบัติ" และ "แอตทริบิวต์" และไม่สามารถหาแหล่งข้อมูลที่ดีเพื่อสรุปความแตกต่างได้อย่างชัดเจน
โดยทั่วไปฉันสับสนเกี่ยวกับความแตกต่างระหว่าง "คุณสมบัติ" และ "แอตทริบิวต์" และไม่สามารถหาแหล่งข้อมูลที่ดีเพื่อสรุปความแตกต่างได้อย่างชัดเจน
คำตอบ:
คุณสมบัติเป็นแอตทริบิวต์ชนิดพิเศษ โดยทั่วไปเมื่อ Python พบรหัสต่อไปนี้:
spam = SomeObject()
print(spam.eggs)
มันเงยหน้าขึ้นมองeggsในspamและจากนั้นจะตรวจสอบeggsเพื่อดูว่ามันมี__get__, __set__หรือ__delete__วิธี - ถ้ามันไม่เป็นสถานที่ให้บริการ ถ้ามันเป็นคุณสมบัติแทนที่จะส่งคืนeggsวัตถุ (เช่นเดียวกับคุณสมบัติอื่น ๆ ) มันจะเรียก__get__เมธอด (เนื่องจากเราทำการค้นหา) และคืนสิ่งที่วิธีนั้นกลับมา
ด้วยคุณสมบัติที่คุณมีการควบคุมที่สมบูรณ์ในวิธีการทะเยอทะยาน 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
xผู้ใช้ของชั้นควรดู ทางเดียว. หากผู้ใช้ของชั้นเรียนพบเกี่ยวกับ _x พวกเขาใช้มันด้วยความเสี่ยงของตัวเอง
โดยทั่วไปแล้วคำพูดคุณสมบัติและคุณสมบัติเป็นสิ่งเดียวกัน อย่างไรก็ตามมี 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
คุณสมบัติช่วยให้คุณได้รับและตั้งค่าเช่นเดียวกับที่คุณทำกับคุณสมบัติปกติ แต่ภายใต้มีวิธีการที่เรียกว่าการแปลเป็น getter และ setter สำหรับคุณ เป็นเพียงความสะดวกสบายในการลดจำนวนผู้โทรเข้าและผู้ตั้งค่า
ยกตัวอย่างเช่นคุณมีคลาสที่มีค่าพิกัด x และ y สำหรับสิ่งที่คุณต้องการ หากต้องการตั้งค่าคุณอาจต้องการทำสิ่งต่อไปนี้:
myObj.x = 5
myObj.y = 10
ดูและคิดได้ง่ายกว่าเขียน:
myObj.setX(5)
myObj.setY(10)
ปัญหาคือเกิดอะไรขึ้นถ้าวันหนึ่งชั้นเรียนของคุณเปลี่ยนแปลงเช่นนั้นคุณต้องชดเชยค่า x และ y ของคุณด้วยค่าบางค่า? ตอนนี้คุณจะต้องเข้าไปข้างในและเปลี่ยนนิยามคลาสของคุณและรหัสทั้งหมดที่เรียกมันซึ่งอาจเสียเวลามากและเกิดข้อผิดพลาด คุณสมบัติช่วยให้คุณใช้ไวยากรณ์เดิมในขณะที่ให้ความยืดหยุ่นในการเปลี่ยนแปลงของหลัง
ใน Python คุณสามารถกำหนด getters, setters และวิธีการลบด้วยฟังก์ชั่นคุณสมบัติ หากคุณต้องการอ่านคุณสมบัติมี @ มัณฑนากรตกแต่งบ้านคุณสามารถเพิ่มวิธีการของคุณ
ฉันเรียนรู้ความแตกต่าง 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
นอกจากนี้ยังมีความแตกต่างที่เห็นได้ชัดอย่างหนึ่งที่ฉันใช้เพื่อแคชหรือรีเฟรชข้อมูลเรามักจะมีฟังก์ชั่นที่เชื่อมต่อกับแอตทริบิวต์ 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