Многие из предоставленных ответов требуют так много строк для каждого свойства, то есть / и / или - что я бы назвал уродливой или утомительной реализацией из-за повторяемости, требуемой для нескольких свойств и т. Д. Я предпочитаю сводить детали вниз / упрощать их, пока они больше не может быть упрощено или пока это не принесет особой цели.
Вкратце: в завершенных работах, если я повторяю 2 строки кода, я обычно преобразую его в вспомогательную функцию в одну строку и так далее ... Я упрощаю математические или нечетные аргументы, такие как (start_x, start_y, end_x, end_y), до (x, y, w, h) то есть x, y, x + w, y + h (иногда требуется min / max или если w / h отрицательны и реализации не нравится, я вычту из x / у и пресс с ч / ч и т. д.).
Переопределение внутренних методов получения / установки является нормальным способом, но проблема в том, что вы должны сделать это для каждого класса или создать родительский класс для этой базы ... Это не работает для меня, поскольку я предпочел бы свободно выбирать детей / родителей для наследования, дочерних узлов и т. д.
Я создал решение, которое отвечает на вопрос, не используя тип данных Dict для предоставления данных, так как считаю, что ввод данных является утомительным и т. Д.
Мое решение требует, чтобы вы добавили 2 дополнительные строки над вашим классом, чтобы создать базовый класс для класса, в который вы хотите добавить свойства, затем 1 строку на каждый, и у вас есть возможность добавить обратные вызовы для управления данными, сообщать вам об изменениях данных ограничить данные, которые могут быть установлены на основе значения и / или типа данных, и многое другое.
У вас также есть возможность использовать _object.x, _object.x = значение, _object.GetX (), _object.SetX (значение), и они обрабатываются эквивалентно.
Кроме того, значения являются единственными нестатическими данными, которые назначаются экземпляру класса, но фактическое свойство присваивается классу, то есть вещи, которые вы не хотите повторять, повторять не нужно ... Вы может назначить значение по умолчанию, чтобы метод получения не нуждался в нем каждый раз, хотя есть опция для переопределения значения по умолчанию по умолчанию, и есть другая опция, чтобы метод получения возвращал необработанное сохраненное значение путем переопределения возвратов по умолчанию (примечание: этот метод означает, что необработанное значение присваивается только при назначении значения, в противном случае оно равно None - когда значением является Reset, оно присваивает None и т. д.)
Также есть много вспомогательных функций - первое добавленное свойство добавляет в класс примерно 2 помощника для ссылки на значения экземпляра ... Это повторяемые переменные ResetAccessors (_key, ..) (все можно повторить, используя первые именованные аргументы ) и SetAccessors (_key, _value) с возможностью добавления большего числа в основной класс для повышения эффективности - планируется: способ группировать средства доступа вместе, так что если вы склонны сбрасывать несколько одновременно, каждый раз Вы можете назначить их группе и сбросить группу вместо повторения именованных ключей каждый раз, и многое другое.
Сохраненное значение экземпляра / raw хранится в классе. , класс. ссылается на класс Accessor, который содержит статические переменные / значения / функции для свойства. _класс. это свойство, которое вызывается при доступе через класс экземпляра во время установки / получения и т. д.
Accessor _class .__ указывает на класс, но, поскольку он является внутренним, его необходимо назначить в классе, поэтому я решил использовать __Name = AccessorFunc (...) для его присвоения, по одной строке на свойство со многими необязательными аргументы для использования (используя ключевые переменные, потому что их проще и эффективнее идентифицировать и поддерживать) ...
Как я уже упоминал, я также создаю много функций, некоторые из которых используют информацию о функциях доступа, поэтому их не нужно вызывать (поскольку в данный момент это немного неудобно - сейчас вам нужно использовать _class. .FunctionName (_class_instance) , args) - я нашел способ использовать стек / трассировку для получения ссылки на экземпляр, чтобы получить значение, добавив функции, которые либо запускают этот битовый марафон, либо добавив методы доступа к объекту и используя self (названный this, чтобы указать, что они для экземпляра и чтобы сохранить доступ к себе, ссылку на класс AccessorFunc и другую информацию в определениях функций).
Это не совсем сделано, но это фантастическая нога. Примечание. Если вы не используете __Name = AccessorFunc (...) для создания свойств, у вас не будет доступа к клавише __, даже если я определю ее в функции init. Если вы делаете, то нет никаких проблем.
Также: Обратите внимание, что Имя и Ключ разные ... Имя является «формальным», используется при создании имени функции, а ключ предназначен для хранения и доступа к данным. то есть _class.x, где строчная буква x - это ключ, имя будет прописной буквой X, так что GetX () - это функция вместо Getx (), которая выглядит немного странно. это позволяет self.x работать и выглядеть соответствующим образом, но также позволяет GetX () и выглядеть соответствующим образом.
У меня есть пример класса с ключом / именем, идентичным, и другим, чтобы показать. Для вывода данных создано множество вспомогательных функций (Примечание: не все это завершено), чтобы вы могли видеть, что происходит.
Текущий список функций, использующих key: x, name: 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
Некоторые из выводимых данных:
Это для совершенно нового класса, созданного с использованием демо-класса без каких-либо данных, назначенных, кроме имени (чтобы его можно было выводить), то есть _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 не сделана (которая будет использоваться для обновления Print Getters и помощника GetKeyOutput функции вместе с изменением на функцию Instance, возможно, помещенную в одну функцию и переименованную - ищите ее ..)
Далее: не все требуется для его запуска - большая часть комментариев внизу предназначена для дополнительной информации, используемой для отладки - ее может не быть при загрузке. Если это так, вы сможете раскомментировать и перекомпилировать, чтобы получить больше информации.
Я ищу обходной путь к необходимости 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 / data-type / value принудительного применения и т. Д.
На данный момент ссылка на (Эта ссылка должна отражать изменения в документе.): 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/ (сначала добавьте репо в диспетчере пакетов, затем установите плагин - когда версия 1.0.0 будет готова, я добавлю это к основному списку плагинов ...)
Я надеюсь, что это решение поможет ... и, как всегда:
Просто потому, что это работает, не делает это правильно - Джош 'Acecool' Мозер
:
и__init__
ссылкиself.fn_readyonly
.