Saya punya kelas dengan dua metode kelas (menggunakan fungsi classmethod ()) untuk mendapatkan dan mengatur apa yang pada dasarnya adalah variabel statis. Saya mencoba menggunakan fungsi properti () dengan ini, tetapi menghasilkan kesalahan. Saya dapat mereproduksi kesalahan dengan yang berikut dalam juru bahasa:
class Foo(object):
_var = 5
@classmethod
def getvar(cls):
return cls._var
@classmethod
def setvar(cls, value):
cls._var = value
var = property(getvar, setvar)
Saya bisa menunjukkan metode kelas, tetapi mereka tidak berfungsi sebagai properti:
>>> f = Foo()
>>> f.getvar()
5
>>> f.setvar(4)
>>> f.getvar()
4
>>> f.var
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
>>> f.var=5
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
Apakah mungkin untuk menggunakan fungsi properti () dengan fungsi yang didekorasi dengan metode kelas?
class Foo(metaclass=...)
sintaks baru .Membaca catatan rilis Python 2.2 , saya menemukan yang berikut ini.
CATATAN: Metode di bawah ini sebenarnya tidak berfungsi untuk setter, hanya getter.
Oleh karena itu, saya percaya solusi yang ditentukan adalah membuat ClassProperty sebagai subkelas properti.
Namun, setter tidak benar-benar berfungsi:
foo._var
tidak berubah, Anda cukup menimpa properti dengan nilai baru.Anda juga dapat menggunakan
ClassProperty
sebagai dekorator:sumber
self.fget(owner)
dan menghapus keharusan harus menggunakan@classmethod
sama sekali di sini? (itulah yangclassmethod
dilakukan , terjemahkan.__get__(instance, owner)(*args, **kwargs)
kefunction(owner, *args, **kwargs)
panggilan, melalui perantara; properti tidak membutuhkan perantara).foo.var = 3
tugas Anda tidak benar-benar melewati properti , dan sebagai gantinya hanya mengganti objek properti padafoo
dengan integer. Jika Anda menambahkanassert isinstance(foo.__dict__['var'], ClassProperty)
panggilan di antara pernyataan Anda, Anda akan melihat bahwa kegagalan setelahfoo.var = 3
dieksekusi.instance.attr
,instance.attr = value
dandel instance.attr
semua mengikat descriptor akan ditemukan padatype(instance)
, tapi sementaraclassobj.attr
mengikat,classobj.attr = value
dandel classobj.attr
jangan tidak dan bukannya mengganti atau menghapus objek deskriptor itu sendiri). Anda memerlukan metaclass untuk mendukung pengaturan dan menghapus (membuat objek kelas sebagai instance, dan metaclass tipe).Saya berharap
@classproperty
dekorator read-only mati-sederhana ini akan membantu seseorang mencari properti class.sumber
class D(C): x = 2; assert D.x == 2
.format
seperti"{x}".format(**dict(self.__class__.__dict__, **self.__dict__))
:(x
akses oleh10
. Saya suka pendekatan ini karena rapi dan sederhana tetapi kedengarannya seperti antipattern__set__
yang menaikkanValueError
untuk mencegah penggantian.Tidak.
Namun, metode kelas hanyalah metode terikat (fungsi parsial) pada kelas yang dapat diakses dari instance kelas itu.
Karena instance adalah fungsi dari kelas dan Anda bisa mendapatkan kelas dari instance, Anda bisa mendapatkan perilaku apa pun yang diinginkan yang mungkin Anda inginkan dari properti kelas dengan
property
:Kode ini dapat digunakan untuk menguji - kode harus lulus tanpa menimbulkan kesalahan:
Dan perhatikan bahwa kita sama sekali tidak membutuhkan metaclasses - dan Anda tidak secara langsung mengakses metaclass melalui instance kelasnya.
menulis
@classproperty
dekoratorAnda sebenarnya dapat membuat
classproperty
dekorator hanya dalam beberapa baris kode dengan mensubclassingproperty
(ini diterapkan dalam C, tetapi Anda dapat melihat Python yang setara di sini ):Kemudian perlakukan dekorator seolah-olah itu adalah metode kelas yang dikombinasikan dengan properti:
Dan kode ini seharusnya bekerja tanpa kesalahan:
Tapi saya tidak yakin seberapa baik ini disarankan. Artikel milis lama menyarankan itu tidak akan berfungsi.
Membuat properti bekerja di kelas:
Kelemahan dari di atas adalah bahwa "properti kelas" tidak dapat diakses dari kelas, karena itu hanya akan menimpa deskriptor data dari kelas
__dict__
.Namun, kita bisa menimpanya dengan properti yang didefinisikan dalam metaclass
__dict__
. Sebagai contoh:Dan kemudian instance kelas dari metaclass dapat memiliki properti yang mengakses properti kelas menggunakan prinsip yang sudah ditunjukkan di bagian sebelumnya:
Dan sekarang kita melihat keduanya
dan kelas
memiliki akses ke properti kelas.
sumber
Python 3!
Pertanyaan lama, banyak pandangan, sangat membutuhkan cara Python 3 yang benar.
Untungnya, mudah dengan
metaclass
kwarg:Kemudian,
>>> Foo.var
sumber
Foo
adalah instance dari metaclass-nya, dan@property
dapat digunakan untuk metode-metodenya seperti halnya untuk contoh-contohnyaFoo
.Foo.__new__
. Meskipun pada titik itu mungkin layak menggunakan getattribute sebagai gantinya, atau mempertanyakan apakah berpura-pura memiliki fitur bahasa benar-benar pendekatan yang ingin Anda ambil sama sekali.Tidak ada cara yang masuk akal untuk membuat sistem "properti kelas" ini bekerja dengan Python.
Ini adalah salah satu cara yang tidak masuk akal untuk membuatnya bekerja. Anda tentu bisa membuatnya lebih mulus dengan meningkatnya jumlah metaclass magic.
Simpul dari masalah ini adalah bahwa properti adalah apa yang Python sebut "deskriptor". Tidak ada cara yang singkat dan mudah untuk menjelaskan cara kerja pemrograman seperti ini, jadi saya harus mengarahkan Anda ke deskriptor howto .
Anda hanya perlu memahami hal-hal semacam ini jika Anda menerapkan kerangka kerja yang cukup maju. Seperti ketekunan objek transparan atau sistem RPC, atau sejenis bahasa khusus domain.
Namun, dalam komentar untuk jawaban sebelumnya, Anda mengatakan itu
Menurut saya, yang Anda inginkan adalah pola desain Observer .
sumber
Mengaturnya hanya pada kelas meta tidak membantu jika Anda ingin mengakses properti kelas melalui objek instantiated, dalam hal ini Anda perlu menginstal properti normal pada objek juga (yang dikirim ke properti kelas). Saya pikir yang berikut ini sedikit lebih jelas:
sumber
Setengah solusi, __set__ di kelas tidak bekerja, masih. Solusinya adalah kelas properti kustom yang mengimplementasikan properti dan metode statis
sumber
Apakah Anda memiliki akses ke setidaknya satu instance kelas? Saya bisa memikirkan cara untuk melakukannya:
sumber
Cobalah ini, ini menyelesaikan pekerjaan tanpa harus mengubah / menambahkan banyak kode yang ada.
The
property
Fungsi membutuhkan duacallable
argumen. memberi mereka pembungkus lambda (yang melewati contoh sebagai argumen pertama) dan semuanya baik-baik saja.sumber
Inilah solusi yang harus bekerja untuk akses baik melalui kelas dan akses melalui contoh yang menggunakan metaclass.
Ini juga bekerja dengan setter yang didefinisikan dalam metaclass.
sumber
Setelah mencari tempat yang berbeda, saya menemukan metode untuk mendefinisikan classproperty yang valid dengan Python 2 dan 3.
Semoga ini bisa membantu seseorang :)
sumber
Ini saran saya. Jangan gunakan metode kelas.
Serius.
Apa alasan menggunakan metode kelas dalam kasus ini? Mengapa tidak memiliki objek biasa dari kelas biasa?
Jika Anda hanya ingin mengubah nilainya, properti tidak terlalu membantu bukan? Cukup atur nilai atribut dan lakukan dengan itu.
Properti hanya boleh digunakan jika ada sesuatu yang disembunyikan - sesuatu yang mungkin berubah dalam implementasi di masa depan.
Mungkin contoh Anda dilucuti, dan ada beberapa perhitungan jahat yang Anda tinggalkan. Tapi itu tidak terlihat seperti properti menambah nilai signifikan.
Teknik "privasi" yang dipengaruhi Java (dengan Python, nama atribut yang dimulai dengan _) tidak terlalu membantu. Pribadi dari siapa? Titik pribadi agak samar ketika Anda memiliki sumber (seperti yang Anda lakukan dengan Python.)
Getter dan setter gaya EJB yang dipengaruhi Java (sering kali dilakukan sebagai properti dengan Python) ada untuk memfasilitasi introspeksi primitif Java serta lulus dengan kompiler bahasa statis. Semua getter dan setter tidak membantu dalam Python.
sumber