Jawaban:
Properti adalah jenis atribut khusus. Pada dasarnya, ketika Python menemukan kode berikut:
spam = SomeObject()
print(spam.eggs)
itu mendongak eggsdi spam, dan kemudian memeriksa eggsuntuk melihat apakah ia memiliki __get__, __set__atau __delete__metode - jika tidak, itu sebuah properti. Jika itu adalah properti, alih-alih hanya mengembalikan eggsobjek (seperti halnya atribut lainnya), ia akan memanggil __get__metode (karena kami melakukan pencarian) dan mengembalikan apa pun yang dikembalikan metode itu.
Informasi lebih lanjut tentang model data dan deskriptor Python .
Dengan properti Anda memiliki kontrol penuh pada metode pengambil, penyetel, dan deleter, yang tidak Anda miliki (jika tidak menggunakan peringatan) dengan atribut.
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. Satu arah. Jika pengguna kelas mengetahui tentang _x, mereka menggunakannya dengan risiko sendiri.
Secara umum, properti dan atribut adalah hal yang sama. Namun, ada dekorator properti di Python yang menyediakan akses pengambil / penyetel ke atribut (atau data lainnya).
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
Properti memungkinkan Anda untuk mendapatkan dan menetapkan nilai seperti yang Anda lakukan atribut normal, tetapi di bawahnya ada metode yang disebut menerjemahkannya menjadi pengambil dan penyetel untuk Anda. Ini benar-benar hanya kenyamanan untuk mengurangi pelat panggil getter dan setter.
Katakanlah misalnya, Anda memiliki kelas yang memegang beberapa koordinat x dan y untuk sesuatu yang Anda butuhkan. Untuk mengaturnya, Anda mungkin ingin melakukan sesuatu seperti:
myObj.x = 5
myObj.y = 10
Itu jauh lebih mudah untuk dilihat dan dipikirkan daripada menulis:
myObj.setX(5)
myObj.setY(10)
Masalahnya adalah, bagaimana jika suatu hari kelas Anda berubah sedemikian rupa sehingga Anda perlu mengimbangi x dan y Anda dengan beberapa nilai? Sekarang Anda harus masuk dan mengubah definisi kelas Anda dan semua kode yang menyebutnya, yang bisa sangat memakan waktu dan rawan kesalahan. Properti ini memungkinkan Anda untuk menggunakan sintaks yang sebelumnya sambil memberi Anda fleksibilitas untuk perubahan yang terakhir.
Dengan Python, Anda bisa mendefinisikan getter, setter, dan menghapus metode dengan fungsi properti. Jika Anda hanya ingin properti baca, ada juga dekorator @ properti yang dapat Anda tambahkan di atas metode Anda.
Saya belajar 2 perbedaan dari situs Bernd Klein, dalam ringkasan:
1. Properti adalah cara yang lebih mudah untuk melakukan enkapsulasi data.
mis: Jika Anda memiliki atribut publik yang panjang dari Object, nanti, proyek Anda mengharuskan Anda untuk merangkumnya, yaitu: ubah ke pribadi dan berikan pengambil dan penyetel => Anda harus mengubah banyak kode yang Anda tulis sebelumnya:
#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
Jika Anda menggunakan @property dan @ lenght.setter => Anda tidak perlu mengubah kode lama itu
2. Properti dapat merangkum beberapa atribut
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!"
Dalam contoh ini, __physic_healthdan __mental_healthbersifat pribadi dan tidak dapat diakses langsung dari luar, satu-satunya cara di luar kelas berinteraksi dengan mereka adalah properti terbukacondition
Ada juga satu perbedaan tidak jelas yang saya gunakan untuk cache atau menyegarkan data, seringkali kita memiliki fungsi yang terhubung ke atribut kelas. Misalnya saya perlu membaca file sekali dan menyimpan konten yang ditugaskan ke atribut sehingga nilainya di-cache:
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
Keluaran:
func running
func value
func value
Kami mengakses atribut dua kali tetapi fungsi kami dipecat hanya sekali. Mengubah contoh di atas untuk menggunakan properti akan menyebabkan refresh nilai atribut setiap kali Anda mengaksesnya:
class Misc():
@property
def test(self):
print 'func running'
return 'func value'
cl = Misc()
print cl.test
print cl.test
Keluaran:
func running
func value
func running
func value