Багато відповідей, що надаються, вимагають стільки рядків на власність, тобто / та / або - що я вважаю некрасивим або стомлюючим реалізацією через повторюваність, необхідну для декількох властивостей і т. Д. Я вважаю за краще зберігати речі / спрощувати їх, поки вони не стануть більше не можна спрощувати або поки це не служить великій меті.
Коротше кажучи: у завершених роботах, якщо я повторюю 2 рядки коду, я зазвичай перетворюю його в однопорядкову функцію помічника тощо. Я спрощую математичні чи непарні аргументи, такі як (start_x, start_y, end_x, end_y) в (x, y, w, h), тобто x, y, x + w, y + h (іноді потрібні min / max або якщо w / h негативні, і реалізація не сподобається, я віднімаю з x / y та abs w / h тощо.).
Переосмислення внутрішніх геттерів / сеттерів - це нормальний шлях, але проблема полягає в тому, що вам потрібно зробити це для кожного класу або батьківського класу до цієї бази ... Це не працює для мене, як я вважаю за краще вільний вибір дітей / батьків на спадщину, дитячі вузли тощо.
Я створив рішення, яке відповідає на питання, не використовуючи тип даних Dict для подання даних, оскільки я вважаю, що це втомлює введення даних тощо.
Моє рішення вимагає, щоб ви додали 2 додаткові рядки над своїм класом, щоб створити базовий клас для класу, до якого потрібно додати властивості, потім 1 рядок на кожен, і у вас є можливість додавати зворотні дзвінки для управління даними, повідомляти вас про зміну даних , обмежте дані, які можна встановити на основі значення та / або типу даних та багато іншого.
У вас також є можливість використовувати _object.x, _object.x = значення, _object.GetX (), _object.SetX (значення), і вони обробляються рівнозначно.
Крім того, значення - це єдині нестатичні дані, які призначаються екземпляру класу, але фактичне властивість присвоюється класу, тобто речі, які ви не хочете повторювати, не потрібно повторювати ... можна призначити значення за замовчуванням, щоб геттер не потребував його щоразу, хоча є можливість змінити значення за замовчуванням за замовчуванням, і є інший варіант, щоб геттер повертав збережене значення, що не зберігається, замінюючи повернення за замовчуванням (зверніть увагу: цей метод означає, що необроблене значення присвоюється лише тоді, коли присвоєно значення, інакше воно не має значення - коли значення "Скидання", воно призначає "ні", тощо.)
Також є багато допоміжних функцій - перше додане властивість додає 2 або більше помічників до класу для посилань на значення екземплярів ... Вони повторюються вараги ResetAccessors (_key, ..) (усі можна повторити, використовуючи перші названі аргументи ) та SetAccessors (_key, _value) з можливістю додаткового додавання до основного класу для сприяння ефективності - заплановані такі: спосіб згрупувати аксесуари разом, тож якщо ви прагнете скидати декілька разів за раз, кожен раз , ви можете призначити їх групі та скинути групу замість повторення названих клавіш кожного разу тощо.
Екземпляр / сировина, що зберігається, зберігається у класі., клас. посилається на клас Accessor, який містить статичні параметри / значення / функції для властивості. _клас. - це саме властивість, яке викликається при зверненні через клас екземпляра під час встановлення / отримання тощо.
Accessor _class .__ вказує на клас, але, оскільки він є внутрішнім, його потрібно призначити в класі, тому я вирішив використовувати __Name = AccessorFunc (...) для його призначення, один рядок на власність з багатьма необов'язковими аргументи для використання (використання ключових варагрів, тому що їх простіше та ефективніше ідентифікувати та підтримувати) ...
Як було сказано, я також створюю безліч функцій, деякі з яких використовують інформацію про функції аксесуара, тому її не потрібно називати (оскільки це наразі трохи незручно - зараз вам потрібно використовувати _class. _class .UnctionName (_class_instance , аргументи) - Я обійшов за допомогою стека / трасування, щоб захопити посилання на екземпляр, щоб захопити значення, додавши функції, які виконують цей бітовий марафон, або додавши до нього об’єкт і використовуючи self (назвав це, щоб вказати на те, що вони - це екземпляр і зберегти доступ до себе, посилання класу AccessorFunc та інша інформація з визначень функції).
Це не зовсім зроблено, але це фантастичне утримання ніг. Примітка: Якщо ви не використовуєте __Name = AccessorFunc (...) для створення властивостей, ви не матимете доступу до клавіші __, хоча я визначаю її у функції init. Якщо ви це зробите, то проблем немає.
Також: Зауважте, що ім'я та ключ різні ... Ім'я є "формальним", яке використовується у створенні функції імен, а ключ призначений для зберігання та доступу до даних. тобто _class.x, де нижній регістр x є ключовим, ім'я буде великим регістром X, так що GetX () є функцією замість Getx (), яка виглядає трохи дивним. це дозволяє self.x працювати і виглядати доречно, але також дозволяє GetX () і виглядати відповідним.
У мене є клас прикладу, створений з ідентичним ключем / іменем та різним для показу. безліч допоміжних функцій, створених для виведення даних (Примітка: Не все це завершено), щоб ви могли побачити, що відбувається.
Поточний список функцій, що використовують клавішу: x, ім'я: X виводить як:
Це аж ніяк не вичерпний список - є декілька, які не зробили цього на момент публікації ...
_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
Деякі дані, що виводяться, це:
Це для абсолютно нового класу, створеного за допомогою класу Demo без будь-яких даних, призначених, крім імені (щоб його можна було вивести), який є _foo, ім'я змінної, яку я використав ...
_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)
І це після призначення всіх властивостей _foo (крім імені) наступних значень у тому ж порядку: '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) |
Зауважте, що через обмежені типи даних або обмеження значень деякі дані не призначаються - це задумано. Установник забороняє призначати погані типи даних або значення, навіть не призначати їх як значення за замовчуванням (якщо ви не перекриєте поведінку захисту значення за замовчуванням)
Код тут не розміщено, тому що я не мав місця після прикладів та пояснень ... Також тому, що він зміниться.
Зверніть увагу: на момент публікації цього файлу брудний файл - це зміниться. Але якщо запустити його в Sublime Text і скласти його або запустити його з Python, він збиратиме і випльовує тону інформації - частина AccessorDB не робиться (що буде використано для оновлення помічників друку та GetKeyOutput функції разом із зміною на функцію екземпляра, ймовірно, введені в одну функцію та перейменовані - шукайте її ..)
Далі: Для його запуску не потрібно все - багато коментованих матеріалів внизу призначені для отримання додаткової інформації, яка використовується для налагодження - можливо, її не буде під час завантаження. Якщо це так, ви повинні мати змогу скаментувати та перекомпілювати, щоб отримати більше інформації.
Я шукаю обхід необхідності MyClassBase: pass, MyClass (MyClassBase): ... - якщо ви знаєте рішення - опублікуйте його.
Єдине, що необхідно в класі - це рядки __ - str для налагодження, як і init - їх можна видалити з демонстраційного класу, але вам потрібно буде прокоментувати або видалити деякі рядки нижче (_foo / 2/3 ) ..
Класи String, Dict та Util вгорі є частиною моєї бібліотеки Python - вони не є повною. Я скопіював із бібліотеки кілька потрібних речей, і створив кілька нових. Повний код буде посилатися на повну бібліотеку і буде включати його разом із наданням оновлених дзвінків та видаленням коду (насправді єдиним кодом, що залишився, буде демо-клас та друковані виписки - система AccessorFunc буде переміщена до бібліотеки). ..
Частина файлу:
##
## 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 = { } )
Ця краса дозволяє неймовірно легко створювати нові класи з динамічно доданими властивостями за допомогою AccessorFuncs / callbacks / тип даних / примусового застосування і т.д.
Наразі посилання знаходиться на (Цей посилання має відображати зміни до документа.): Https://www.dropbox.com/s/6gzi44i7dh58v61/dynamic_properties_accessorfuncs_and_more.py?dl=0
Також: Якщо ви не використовуєте Sublime Text, я рекомендую його над Notepad ++, Atom, Visual Code та іншими, оскільки належні реалізації потоків роблять його набагато, набагато швидшим у використанні ... Я також працюю над кодом, схожим на IDE система картографування для неї - подивіться на: https://bitbucket.org/Acecool/acecoolcodemappingsystem/src/master/ (Спочатку додайте Repo в Package Manager, потім встановіть плагін - коли версія 1.0.0 буде готова, я додам його до основного списку плагінів ...)
Я сподіваюся, що це рішення допоможе ... і, як завжди:
Тільки тому, що це працює, це не робить правильно - Джош 'Acecool' Moser
:
та__init__
посиланняself.fn_readyonly
.