Banyak jawaban yang disediakan membutuhkan begitu banyak baris per properti, yaitu / dan / atau - apa yang saya anggap implementasi yang jelek atau membosankan karena diperlukan pengulangan untuk banyak properti, dll. Saya lebih suka terus merebus / menyederhanakannya sampai mereka tidak dapat disederhanakan lagi atau sampai tidak ada gunanya untuk melakukannya.
Singkatnya: dalam pekerjaan yang diselesaikan, jika saya mengulangi 2 baris kode, saya biasanya mengubahnya menjadi fungsi pembantu baris tunggal, dan seterusnya ... Saya menyederhanakan matematika atau argumen aneh seperti (start_x, start_y, end_x, end_y) ke (x, y, w, h) yaitu x, y, x + w, y + h (kadang-kadang membutuhkan min / max atau jika w / h negatif dan implementasinya tidak menyukainya, saya akan kurangi dari x / y dan abs w / h dll.).
Mengesampingkan pengambil / penetapan internal adalah cara yang baik untuk pergi, tetapi masalahnya adalah Anda harus melakukan itu untuk setiap kelas, atau induk kelas ke basis itu ... Ini tidak bekerja untuk saya karena saya lebih suka menjadi bebas memilih anak / orang tua untuk warisan, simpul anak, dll.
Saya telah menciptakan solusi yang menjawab pertanyaan tanpa menggunakan tipe data Dict untuk memasok data karena saya menemukan bahwa menjadi membosankan untuk memasukkan data, dll ...
Solusi saya mengharuskan Anda untuk menambahkan 2 baris tambahan di atas kelas Anda untuk membuat kelas dasar untuk kelas yang ingin Anda tambahkan properti, kemudian 1 baris per dan Anda memiliki opsi untuk menambahkan panggilan balik untuk mengontrol data, memberi tahu Anda ketika data berubah , batasi data yang dapat diatur berdasarkan nilai dan / atau tipe data, dan banyak lagi.
Anda juga memiliki opsi untuk menggunakan _object.x, _object.x = value, _object.GetX (), _object.SetX (value) dan mereka ditangani secara setara.
Selain itu, nilai adalah satu-satunya data non-statis yang ditugaskan ke instance kelas, tetapi properti aktual ditugaskan ke kelas yang berarti hal-hal yang tidak ingin Anda ulangi, tidak perlu diulang ... Anda dapat menetapkan nilai default sehingga pengambil tidak perlu setiap kali, meskipun ada opsi untuk mengganti nilai default default, dan ada opsi lain sehingga pengambil mengembalikan nilai yang disimpan mentah dengan menimpa pengembalian default (catatan: metode ini berarti nilai mentah hanya diberikan ketika nilai diberikan, jika tidak, tidak ada - ketika nilai diatur ulang, maka itu menetapkan Tidak ada, dll.)
Ada banyak fungsi pembantu juga - properti pertama yang ditambahkan menambahkan 2 atau lebih pembantu ke kelas untuk mereferensikan nilai instance ... Mereka adalah ResetAccessors (_key, ..) vararg diulangi (semua dapat diulang menggunakan arg yang disebut pertama) ) dan SetAccessors (_key, _value) dengan opsi lebih banyak ditambahkan ke kelas utama untuk membantu dalam efisiensi - yang direncanakan adalah: cara untuk mengelompokkan pengakses bersama, jadi jika Anda cenderung mengatur ulang beberapa waktu, setiap kali , Anda dapat menetapkannya ke grup dan mengatur ulang grup alih-alih mengulangi tombol yang disebutkan setiap kali, dan lainnya.
Instance / nilai tersimpan mentah disimpan di kelas., kelas. referensi Kelas Accessor yang memegang vars / nilai / fungsi statis untuk properti. _kelas. adalah properti itu sendiri yang dipanggil saat diakses melalui kelas instan selama pengaturan / mendapatkan, dll.
Accessor _class .__ menunjuk ke kelas, tetapi karena itu internal maka perlu ditugaskan di kelas yang mengapa saya memilih untuk menggunakan __Name = AccessorFunc (...) untuk menetapkannya, satu baris per properti dengan banyak opsional argumen untuk digunakan (menggunakan vararg yang dikunci karena lebih mudah dan lebih efisien untuk mengidentifikasi dan memelihara) ...
Saya juga membuat banyak fungsi, seperti yang disebutkan, beberapa di antaranya menggunakan informasi fungsi accessor sehingga tidak perlu dipanggil (karena sedikit merepotkan saat ini - saat ini Anda perlu menggunakan _class. .FunctionName (_class_instance , args) - Saya sempat menggunakan stack / trace untuk mengambil referensi instance untuk mengambil nilai dengan menambahkan fungsi-fungsi yang menjalankan bit maraton ini, atau dengan menambahkan accessors ke objek dan menggunakan self (dinamai ini untuk menunjukkan mereka Sedang untuk instance dan untuk mempertahankan akses ke diri, referensi kelas AccessorFunc, dan informasi lainnya dari dalam definisi fungsi).
Ini tidak cukup dilakukan, tetapi ini adalah pegangan kaki yang fantastis. Catatan: Jika Anda tidak menggunakan __Name = AccessorFunc (...) untuk membuat properti, Anda tidak akan memiliki akses ke kunci __ meskipun saya mendefinisikannya dalam fungsi init. Jika Anda melakukannya, maka tidak ada masalah.
Juga: Perhatikan bahwa Nama dan Kunci berbeda ... Nama itu 'formal', digunakan dalam Pembuatan Nama Fungsi, dan kuncinya adalah untuk penyimpanan data dan akses. yaitu _class.x di mana huruf kecil x adalah kunci, namanya akan menjadi huruf besar X sehingga GetX () adalah fungsi alih-alih Getx () yang terlihat sedikit aneh. ini memungkinkan self.x bekerja dan terlihat sesuai, tetapi juga memungkinkan GetX () dan terlihat sesuai.
Saya memiliki contoh kelas yang diatur dengan kunci / nama yang identik, dan berbeda untuk ditampilkan. banyak fungsi pembantu dibuat untuk menampilkan data (Catatan: Tidak semua ini selesai) sehingga Anda dapat melihat apa yang sedang terjadi.
Daftar fungsi saat ini menggunakan kunci: x, nama: X output sebagai:
Ini bukan daftar lengkap - ada beberapa yang belum membuatnya pada saat posting ...
_instance.SetAccessors( _key, _value [ , _key, _value ] .. ) Instance Class Helper Function: Allows assigning many keys / values on a single line - useful for initial setup, or to minimize lines. In short: Calls this.Set<Name>( _value ) for each _key / _value pairing.
_instance.ResetAccessors( _key [ , _key ] .. ) Instance Class Helper Function: Allows resetting many key stored values to None on a single line. In short: Calls this.Reset<Name>() for each name provided.
Note: Functions below may list self.Get / Set / Name( _args ) - self is meant as the class instance reference in the cases below - coded as this in AccessorFuncBase Class.
this.GetX( _default_override = None, _ignore_defaults = False ) GET: Returns IF ISSET: STORED_VALUE .. IF IGNORE_DEFAULTS: None .. IF PROVIDED: DEFAULT_OVERRIDE ELSE: DEFAULT_VALUE 100
this.GetXRaw( ) RAW: Returns STORED_VALUE 100
this.IsXSet( ) ISSET: Returns ( STORED_VALUE != None ) True
this.GetXToString( ) GETSTR: Returns str( GET ) 100
this.GetXLen( _default_override = None, _ignore_defaults = False ) LEN: Returns len( GET ) 3
this.GetXLenToString( _default_override = None, _ignore_defaults = False ) LENSTR: Returns str( len( GET ) ) 3
this.GetXDefaultValue( ) DEFAULT: Returns DEFAULT_VALUE 1111
this.GetXAccessor( ) ACCESSOR: Returns ACCESSOR_REF ( self.__<key> ) [ AccessorFuncBase ] Key: x : Class ID: 2231452344344 : self ID: 2231448283848 Default: 1111 Allowed Types: {"<class 'int'>": "<class 'type'>", "<class 'float'>": "<class 'type'>"} Allowed Values: None
this.GetXAllowedTypes( ) ALLOWED_TYPES: Returns Allowed Data-Types {"<class 'int'>": "<class 'type'>", "<class 'float'>": "<class 'type'>"}
this.GetXAllowedValues( ) ALLOWED_VALUES: Returns Allowed Values None
this.GetXHelpers( ) HELPERS: Returns Helper Functions String List - ie what you're reading now... THESE ROWS OF TEXT
this.GetXKeyOutput( ) Returns information about this Name / Key ROWS OF TEXT
this.GetXGetterOutput( ) Returns information about this Name / Key ROWS OF TEXT
this.SetX( _value ) SET: STORED_VALUE Setter - ie Redirect to __<Key>.Set N / A
this.ResetX( ) RESET: Resets STORED_VALUE to None N / A
this.HasXGetterPrefix( ) Returns Whether or Not this key has a Getter Prefix... True
this.GetXGetterPrefix( ) Returns Getter Prefix... Get
this.GetXName( ) Returns Accessor Name - Typically Formal / Title-Case X
this.GetXKey( ) Returns Accessor Property Key - Typically Lower-Case x
this.GetXAccessorKey( ) Returns Accessor Key - This is to access internal functions, and static data... __x
this.GetXDataKey( ) Returns Accessor Data-Storage Key - This is the location where the class instance value is stored.. _x
Beberapa data yang dihasilkan adalah:
Ini untuk kelas baru yang dibuat menggunakan kelas Demo tanpa data yang diberikan selain nama (sehingga bisa menjadi output) yaitu _foo, nama variabel yang saya gunakan ...
_foo --- MyClass: ---- id( this.__class__ ): 2231452349064 :::: id( this ): 2231448475016
Key Getter Value | Raw Key Raw / Stored Value | Get Default Value Default Value | Get Allowed Types Allowed Types | Get Allowed Values Allowed Values |
Name: _foo | _Name: _foo | __Name.DefaultValue( ): AccessorFuncDemoClass | __Name.GetAllowedTypes( ) <class 'str'> | __Name.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
x: 1111 | _x: None | __x.DefaultValue( ): 1111 | __x.GetAllowedTypes( ) (<class 'int'>, <class 'float'>) | __x.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
y: 2222 | _y: None | __y.DefaultValue( ): 2222 | __y.GetAllowedTypes( ) (<class 'int'>, <class 'float'>) | __y.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
z: 3333 | _z: None | __z.DefaultValue( ): 3333 | __z.GetAllowedTypes( ) (<class 'int'>, <class 'float'>) | __z.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
Blah: <class 'int'> | _Blah: None | __Blah.DefaultValue( ): <class 'int'> | __Blah.GetAllowedTypes( ) <class 'str'> | __Blah.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
Width: 1 | _Width: None | __Width.DefaultValue( ): 1 | __Width.GetAllowedTypes( ) (<class 'int'>, <class 'bool'>) | __Width.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
Height: 0 | _Height: None | __Height.DefaultValue( ): 0 | __Height.GetAllowedTypes( ) <class 'int'> | __Height.GetAllowedValues( ) (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) |
Depth: 2 | _Depth: None | __Depth.DefaultValue( ): 2 | __Depth.GetAllowedTypes( ) Saved Value Restricted to Authorized Values ONLY | __Depth.GetAllowedValues( ) (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) |
this.IsNameSet( ): True this.GetName( ): _foo this.GetNameRaw( ): _foo this.GetNameDefaultValue( ): AccessorFuncDemoClass this.GetNameLen( ): 4 this.HasNameGetterPrefix( ): <class 'str'> this.GetNameGetterPrefix( ): None
this.IsXSet( ): False this.GetX( ): 1111 this.GetXRaw( ): None this.GetXDefaultValue( ): 1111 this.GetXLen( ): 4 this.HasXGetterPrefix( ): (<class 'int'>, <class 'float'>) this.GetXGetterPrefix( ): None
this.IsYSet( ): False this.GetY( ): 2222 this.GetYRaw( ): None this.GetYDefaultValue( ): 2222 this.GetYLen( ): 4 this.HasYGetterPrefix( ): (<class 'int'>, <class 'float'>) this.GetYGetterPrefix( ): None
this.IsZSet( ): False this.GetZ( ): 3333 this.GetZRaw( ): None this.GetZDefaultValue( ): 3333 this.GetZLen( ): 4 this.HasZGetterPrefix( ): (<class 'int'>, <class 'float'>) this.GetZGetterPrefix( ): None
this.IsBlahSet( ): False this.GetBlah( ): <class 'int'> this.GetBlahRaw( ): None this.GetBlahDefaultValue( ): <class 'int'> this.GetBlahLen( ): 13 this.HasBlahGetterPrefix( ): <class 'str'> this.GetBlahGetterPrefix( ): None
this.IsWidthSet( ): False this.GetWidth( ): 1 this.GetWidthRaw( ): None this.GetWidthDefaultValue( ): 1 this.GetWidthLen( ): 1 this.HasWidthGetterPrefix( ): (<class 'int'>, <class 'bool'>) this.GetWidthGetterPrefix( ): None
this.IsDepthSet( ): False this.GetDepth( ): 2 this.GetDepthRaw( ): None this.GetDepthDefaultValue( ): 2 this.GetDepthLen( ): 1 this.HasDepthGetterPrefix( ): None this.GetDepthGetterPrefix( ): (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
this.IsHeightSet( ): False this.GetHeight( ): 0 this.GetHeightRaw( ): None this.GetHeightDefaultValue( ): 0 this.GetHeightLen( ): 1 this.HasHeightGetterPrefix( ): <class 'int'> this.GetHeightGetterPrefix( ): (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
Dan ini setelah menetapkan semua properti _foo (kecuali nama) nilai-nilai berikut dalam urutan yang sama: 'string', 1.0, True, 9, 10, False
this.IsNameSet( ): True this.GetName( ): _foo this.GetNameRaw( ): _foo this.GetNameDefaultValue( ): AccessorFuncDemoClass this.GetNameLen( ): 4 this.HasNameGetterPrefix( ): <class 'str'> this.GetNameGetterPrefix( ): None
this.IsXSet( ): True this.GetX( ): 10 this.GetXRaw( ): 10 this.GetXDefaultValue( ): 1111 this.GetXLen( ): 2 this.HasXGetterPrefix( ): (<class 'int'>, <class 'float'>) this.GetXGetterPrefix( ): None
this.IsYSet( ): True this.GetY( ): 10 this.GetYRaw( ): 10 this.GetYDefaultValue( ): 2222 this.GetYLen( ): 2 this.HasYGetterPrefix( ): (<class 'int'>, <class 'float'>) this.GetYGetterPrefix( ): None
this.IsZSet( ): True this.GetZ( ): 10 this.GetZRaw( ): 10 this.GetZDefaultValue( ): 3333 this.GetZLen( ): 2 this.HasZGetterPrefix( ): (<class 'int'>, <class 'float'>) this.GetZGetterPrefix( ): None
this.IsBlahSet( ): True this.GetBlah( ): string Blah this.GetBlahRaw( ): string Blah this.GetBlahDefaultValue( ): <class 'int'> this.GetBlahLen( ): 11 this.HasBlahGetterPrefix( ): <class 'str'> this.GetBlahGetterPrefix( ): None
this.IsWidthSet( ): True this.GetWidth( ): False this.GetWidthRaw( ): False this.GetWidthDefaultValue( ): 1 this.GetWidthLen( ): 5 this.HasWidthGetterPrefix( ): (<class 'int'>, <class 'bool'>) this.GetWidthGetterPrefix( ): None
this.IsDepthSet( ): True this.GetDepth( ): 9 this.GetDepthRaw( ): 9 this.GetDepthDefaultValue( ): 2 this.GetDepthLen( ): 1 this.HasDepthGetterPrefix( ): None this.GetDepthGetterPrefix( ): (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
this.IsHeightSet( ): True this.GetHeight( ): 9 this.GetHeightRaw( ): 9 this.GetHeightDefaultValue( ): 0 this.GetHeightLen( ): 1 this.HasHeightGetterPrefix( ): <class 'int'> this.GetHeightGetterPrefix( ): (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
_foo --- MyClass: ---- id( this.__class__ ): 2231452349064 :::: id( this ): 2231448475016
Key Getter Value | Raw Key Raw / Stored Value | Get Default Value Default Value | Get Allowed Types Allowed Types | Get Allowed Values Allowed Values |
Name: _foo | _Name: _foo | __Name.DefaultValue( ): AccessorFuncDemoClass | __Name.GetAllowedTypes( ) <class 'str'> | __Name.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
x: 10 | _x: 10 | __x.DefaultValue( ): 1111 | __x.GetAllowedTypes( ) (<class 'int'>, <class 'float'>) | __x.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
y: 10 | _y: 10 | __y.DefaultValue( ): 2222 | __y.GetAllowedTypes( ) (<class 'int'>, <class 'float'>) | __y.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
z: 10 | _z: 10 | __z.DefaultValue( ): 3333 | __z.GetAllowedTypes( ) (<class 'int'>, <class 'float'>) | __z.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
Blah: string Blah | _Blah: string Blah | __Blah.DefaultValue( ): <class 'int'> | __Blah.GetAllowedTypes( ) <class 'str'> | __Blah.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
Width: False | _Width: False | __Width.DefaultValue( ): 1 | __Width.GetAllowedTypes( ) (<class 'int'>, <class 'bool'>) | __Width.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
Height: 9 | _Height: 9 | __Height.DefaultValue( ): 0 | __Height.GetAllowedTypes( ) <class 'int'> | __Height.GetAllowedValues( ) (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) |
Depth: 9 | _Depth: 9 | __Depth.DefaultValue( ): 2 | __Depth.GetAllowedTypes( ) Saved Value Restricted to Authorized Values ONLY | __Depth.GetAllowedValues( ) (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) |
Perhatikan bahwa karena tipe data atau batasan nilai terbatas, beberapa data tidak ditugaskan - ini adalah desain. Penyetel melarang tipe data atau nilai buruk ditugaskan, bahkan dari ditugaskan sebagai nilai default (kecuali Anda mengabaikan perilaku perlindungan nilai default)
Kode belum diposting di sini karena saya tidak punya ruang setelah contoh dan penjelasan ... Juga karena itu akan berubah.
Harap Catatan: pada saat posting ini, file berantakan - ini akan berubah. Tetapi, jika Anda menjalankannya dalam Sublime Text dan mengkompilasinya, atau menjalankannya dari Python, itu akan mengkompilasi dan mengeluarkan banyak informasi - bagian AccessorDB tidak dilakukan (yang akan digunakan untuk memperbarui Print Getters dan GetKeyOutput helper fungsi bersamaan dengan diubah menjadi fungsi Instance, mungkin dimasukkan ke dalam fungsi tunggal dan diganti namanya - lihat ..)
Berikutnya: Tidak semua yang diperlukan untuk menjalankannya - banyak hal yang dikomentari di bagian bawah adalah untuk informasi lebih lanjut yang digunakan untuk debugging - mungkin tidak ada di sana ketika Anda mengunduhnya. Jika ya, Anda harus dapat menghapus komentar dan mengkompilasi ulang untuk mendapatkan informasi lebih lanjut.
Saya mencari solusi untuk memerlukan MyClassBase: pass, MyClass (MyClassBase): ... - jika Anda tahu solusinya - posting.
Satu-satunya hal yang diperlukan di kelas adalah baris __ - str adalah untuk debugging seperti halnya init - mereka dapat dihapus dari Kelas Demo tetapi Anda perlu mengomentari atau menghapus beberapa baris di bawah ini (_foo / 2/3 ) ..
Kelas String, Dict, dan Util di bagian atas adalah bagian dari perpustakaan Python saya - mereka tidak lengkap. Saya menyalin beberapa hal yang saya butuhkan dari perpustakaan, dan saya membuat beberapa hal baru. Kode lengkap akan ditautkan ke perpustakaan lengkap dan akan memasukkannya bersama dengan memberikan panggilan yang diperbarui dan menghapus kode (sebenarnya, satu-satunya kode yang tersisa adalah Kelas Demo dan pernyataan cetak - sistem AccessorFunc akan dipindahkan ke perpustakaan). ..
Bagian dari file:
##
## MyClass Test AccessorFunc Implementation for Dynamic 1-line Parameters
##
class AccessorFuncDemoClassBase( ):
pass
class AccessorFuncDemoClass( AccessorFuncDemoClassBase ):
__Name = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'Name', default = 'AccessorFuncDemoClass', allowed_types = ( TYPE_STRING ), allowed_values = VALUE_ANY, documentation = 'Name Docs', getter_prefix = 'Get', key = 'Name', allow_erroneous_default = False, options = { } )
__x = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'X', default = 1111, allowed_types = ( TYPE_INTEGER, TYPE_FLOAT ), allowed_values = VALUE_ANY, documentation = 'X Docs', getter_prefix = 'Get', key = 'x', allow_erroneous_default = False, options = { } )
__Height = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'Height', default = 0, allowed_types = TYPE_INTEGER, allowed_values = VALUE_SINGLE_DIGITS, documentation = 'Height Docs', getter_prefix = 'Get', key = 'Height', allow_erroneous_default = False, options = { } )
Keindahan ini membuatnya sangat mudah untuk membuat kelas baru dengan properti yang ditambahkan secara dinamis dengan AccessorFuncs / callbacks / tipe data / penegakan nilai, dll.
Untuk saat ini, tautannya ada di (Tautan ini harus mencerminkan perubahan pada dokumen.): Https://www.dropbox.com/s/6gzi44i7dh58v61/dynamic_properties_accessorfuncs_and_more.py?dl=0
Juga: Jika Anda tidak menggunakan Teks Sublime, saya merekomendasikannya pada Notepad ++, Atom, Visual Code, dan lainnya karena implementasi threading yang tepat membuatnya jauh, lebih cepat untuk digunakan ... Saya juga bekerja pada kode seperti IDE sistem pemetaan untuk itu - lihat di: https://bitbucket.org/Acecool/acecoolcodemappingsystem/src/master/ (Tambahkan Repo di Package Manager terlebih dahulu, lalu Instal Plugin - ketika versi 1.0.0 siap, saya akan menambahkan ke daftar plugin utama ...)
Saya harap solusi ini membantu ... dan, seperti biasa:
Hanya karena berfungsi, tidak membuatnya benar - Josh 'Acecool' Moser
:
dan__init__
referensiself.fn_readyonly
.