Saya mengubah beberapa kelas saya dari penggunaan ekstensif getter dan setter ke penggunaan properti yang lebih pythonic.
Tapi sekarang saya macet karena beberapa getter atau setter saya sebelumnya akan memanggil metode yang sesuai dari kelas dasar, dan kemudian melakukan sesuatu yang lain. Tapi bagaimana ini bisa dilakukan dengan properti? Bagaimana memanggil pengambil atau penyetel properti di kelas induk?
Tentu saja memanggil atribut itu sendiri memberikan rekursi tak terbatas.
class Foo(object):
@property
def bar(self):
return 5
@bar.setter
def bar(self, a):
print a
class FooBar(Foo):
@property
def bar(self):
# return the same value
# as in the base class
return self.bar # --> recursion!
@bar.setter
def bar(self, c):
# perform the same action
# as in the base class
self.bar = c # --> recursion!
# then do something else
print 'something else'
fb = FooBar()
fb.bar = 7
sumber
Foo.bar.fset(self, c)
penyetel yang diwariskan? Mengapa tidakFoo.bar.fset(c)
- tanpa "diri" - Saya pikir ini secara implisit telah berlalu?self
get menyiratkan dari rantaiFoo.bar.fset
?foo = Foo()
\foo.bar(c)
tidak ada yang lulus sendiri , tetapi bar () menerimanya dari Python. Saya bukan ahli Python, kurang lebih pemula juga. Itu hanya sebuah pikiran.self
hanya diteruskan secara implisit saat metode dipanggil pada instance kelas. Misalnya, jika saya memiliki kelasA
dengan metodeb(self, arg)
, dan saya membuat instancec = A()
, maka panggilannyac.b(arg)
sama denganA.b(c, arg)
Super harus melakukan trik:
return super().bar
Di Python 2.x Anda perlu menggunakan sintaks yang lebih verbose:
return super(FooBar, self).bar
sumber
AttributeError
.Ada penggunaan alternatif
super
yang tidak perlu secara eksplisit mereferensikan nama kelas dasar.Kelas dasar A:
class A(object): def __init__(self): self._prop = None @property def prop(self): return self._prop @prop.setter def prop(self, value): self._prop = value class B(A): # we want to extend prop here pass
Di B, mengakses pengambil properti dari kelas induk A:
Seperti yang telah dijawab orang lain, ini:
super(B, self).prop
Atau dengan Python 3:
super().prop
Ini mengembalikan nilai yang dikembalikan oleh pengambil properti, bukan pengambil itu sendiri, tetapi itu cukup untuk memperluas pengambil.
Di B, mengakses penyetel properti dari kelas induk A:
Rekomendasi terbaik yang pernah saya lihat sejauh ini adalah sebagai berikut:
Saya yakin yang ini lebih baik:
super(B, self.__class__).prop.fset(self, value)
Dalam contoh ini, kedua opsi setara tetapi menggunakan super memiliki keuntungan karena tidak bergantung pada kelas dasar
B
. JikaB
mewarisi dariC
kelas juga memperluas properti, Anda tidak perlu memperbaruiB
kode.Kode lengkap B yang memperluas properti A:
class B(A): @property def prop(self): value = super(B, self).prop # do something with / modify value here return value @prop.setter def prop(self, value): # do something with / modify value here super(B, self.__class__).prop.fset(self, value)
Satu peringatan:
Kecuali jika properti Anda tidak memiliki penyetel, Anda harus menentukan penyetel dan pengambil
B
meskipun Anda hanya mengubah perilaku salah satunya.sumber
super(B, self.__class__)
tepatnya bekerja dengansuper(class, class)
? Dimana didokumentasikan?mencoba
@property def bar: return super(FooBar, self).bar
Meskipun saya tidak yakin apakah python mendukung pemanggilan properti kelas dasar. Properti sebenarnya adalah objek yang dapat dipanggil yang disiapkan dengan fungsi yang ditentukan dan kemudian menggantikan nama tersebut di kelas. Ini bisa dengan mudah berarti bahwa tidak ada fungsi super yang tersedia.
Anda selalu dapat mengganti sintaks Anda untuk menggunakan fungsi property ():
class Foo(object): def _getbar(self): return 5 def _setbar(self, a): print a bar = property(_getbar, _setbar) class FooBar(Foo): def _getbar(self): # return the same value # as in the base class return super(FooBar, self)._getbar() def bar(self, c): super(FooBar, self)._setbar(c) print "Something else" bar = property(_getbar, _setbar) fb = FooBar() fb.bar = 7
sumber
Beberapa perbaikan kecil pada jawaban Maxime :
__class__
untuk menghindari menulisB
. Perhatikan bahwaself.__class__
ini adalah jenis runtimeself
, tetapi__class__
tanpaself
adalah nama definisi kelas yang melampirkan.super()
adalah singkatan darisuper(__class__, self)
.__set__
bukanfset
. Yang terakhir khusus untukproperty
s, tetapi yang pertama berlaku untuk semua objek mirip properti (deskriptor).class B(A): @property def prop(self): value = super().prop # do something with / modify value here return value @prop.setter def prop(self, value): # do something with / modify value here super(__class__, self.__class__).prop.__set__(self, value)
sumber
Anda dapat menggunakan template berikut:
class Parent(): def __init__(self, value): self.__prop1 = value #getter @property def prop1(self): return self.__prop1 #setter @prop1.setter def prop1(self, value): self.__prop1 = value #deleter @prop1.deleter def prop1(self): del self.__prop1 class Child(Parent): #getter @property def prop1(self): return super(Child, Child).prop1.__get__(self) #setter @prop1.setter def prop1(self, value): super(Child, Child).prop1.__set__(self, value) #deleter @prop1.deleter def prop1(self): super(Child, Child).prop1.__delete__(self)
Catatan! Semua metode properti harus didefinisikan ulang bersama. Jika tidak ingin mendefinisikan ulang semua metode, gunakan template berikut sebagai gantinya:
class Parent(): def __init__(self, value): self.__prop1 = value #getter @property def prop1(self): return self.__prop1 #setter @prop1.setter def prop1(self, value): self.__prop1 = value #deleter @prop1.deleter def prop1(self): del self.__prop1 class Child(Parent): #getter @Parent.prop1.getter def prop1(self): return super(Child, Child).prop1.__get__(self) #setter @Parent.prop1.setter def prop1(self, value): super(Child, Child).prop1.__set__(self, value) #deleter @Parent.prop1.deleter def prop1(self): super(Child, Child).prop1.__delete__(self)
sumber
class Base(object): def method(self): print "Base method was called" class Derived(Base): def method(self): super(Derived,self).method() print "Derived method was called" d = Derived() d.method()
(kecuali saya melewatkan sesuatu dari penjelasan Anda)
sumber