Muchas de las respuestas proporcionadas requieren tantas líneas por propiedad, es decir, / y / o lo que yo consideraría una implementación fea o tediosa debido a la repetitividad requerida para múltiples propiedades, etc. Prefiero mantener las cosas en ebullición / simplificarlas hasta que ya no se puede simplificar o hasta que no tenga mucho propósito hacerlo.
En resumen: en trabajos completos, si repito 2 líneas de código, normalmente lo convierto en una función auxiliar de una sola línea, y así sucesivamente ... Simplifico argumentos matemáticos o extraños como (start_x, start_y, end_x, end_y) a (x, y, w, h) es decir, x, y, x + w, y + h (a veces requiere min / max o si w / h es negativo y la implementación no le gusta, restaré de x / y y abs w / h. etc.).
Anular los getters / setters internos es una buena manera de hacerlo, pero el problema es que debes hacer eso para cada clase, o poner a la clase en esa base ... Esto no funciona para mí, ya que preferiría ser libre de elegir los hijos / padres para herencia, nodos hijos, etc.
He creado una solución que responde a la pregunta sin utilizar un tipo de datos Dict para proporcionar los datos, ya que considero que es tedioso ingresar los datos, etc.
Mi solución requiere que agregue 2 líneas adicionales sobre su clase para crear una clase base para la clase a la que desea agregar las propiedades, luego 1 línea por y tiene la opción de agregar devoluciones de llamada para controlar los datos, informarle cuando los datos cambien , restrinja los datos que se pueden establecer en función del valor y / o tipo de datos, y mucho más.
También tiene la opción de usar _object.x, _object.x = value, _object.GetX (), _object.SetX (value) y se manejan de manera equivalente.
Además, los valores son los únicos datos no estáticos que se asignan a la instancia de clase, pero la propiedad real se asigna a la clase, lo que significa que las cosas que no desea repetir no necesitan repetirse ... Usted puede asignar un valor predeterminado para que el getter no lo necesite cada vez, aunque hay una opción para anular el valor predeterminado predeterminado, y hay otra opción para que el getter devuelva el valor almacenado en bruto anulando los retornos predeterminados (nota: este método significa que el valor bruto solo se asigna cuando se asigna un valor; de lo contrario, es Ninguno; cuando el valor es Restablecer, no se asigna Ninguno, etc.)
También hay muchas funciones auxiliares: la primera propiedad que se agrega agrega 2 o más ayudantes a la clase para hacer referencia a los valores de instancia ... Son varargs ResetAccessors (_key, ..) repetidos (todos pueden repetirse usando los primeros args nombrados ) y SetAccessors (_key, _value) con la opción de agregar más a la clase principal para ayudar en la eficiencia: los planificados son: una forma de agrupar los accesores, por lo que si tiende a restablecer algunos a la vez, cada vez , puede asignarlos a un grupo y restablecer el grupo en lugar de repetir las teclas con nombre cada vez, y más.
La instancia / valor almacenado sin procesar se almacena en clase. , la clase. hace referencia a la clase Accessor que contiene vars / valores / funciones estáticos para la propiedad. _clase. es la propiedad en sí que se llama cuando se accede a través de la clase de instancia durante la configuración / obtención, etc.
Accessor _class .__ apunta a la clase, pero debido a que es interna, debe asignarse en la clase, por eso opté por usar __Name = AccessorFunc (...) para asignarla, una sola línea por propiedad con muchas opciones opcionales. argumentos para usar (usando varargs con clave porque son más fáciles y más eficientes de identificar y mantener) ...
También creo muchas funciones, como se mencionó, algunas de las cuales usan información de función de acceso para que no sea necesario llamarla (ya que es un poco incómodo en este momento, ahora necesita usar _class. .FunctionName (_class_instance , args) - Utilicé la pila / traza para tomar la referencia de instancia para tomar el valor agregando las funciones que ejecutan este maratón de bits o agregando los accesores al objeto y usando self (llamado esto para señalar que son para la instancia y para conservar el acceso a uno mismo, la referencia de clase AccessorFunc y otra información desde dentro de las definiciones de funciones).
No está hecho del todo, pero es un apoyo fantástico para los pies. Nota: Si no usa __Name = AccessorFunc (...) para crear las propiedades, no tendrá acceso a la tecla __ aunque la defina dentro de la función init. Si lo hace, entonces no hay problemas.
Además: tenga en cuenta que Nombre y Clave son diferentes ... El nombre es 'formal', se usa en la Creación de nombres de funciones, y la clave es para el almacenamiento y acceso de datos. es decir, _class.x donde x minúscula es la clave, el nombre sería X mayúscula para que GetX () sea la función en lugar de Getx (), lo que parece un poco extraño. esto permite que self.x funcione y se vea apropiado, pero también permite que GetX () se vea apropiado.
Tengo una clase de ejemplo configurada con clave / nombre idéntico y diferente para mostrar. muchas funciones auxiliares creadas para generar los datos (Nota: no todo esto está completo) para que pueda ver lo que está sucediendo.
La lista actual de funciones que usa la tecla: x, nombre: X se muestra como:
De ninguna manera se trata de una lista exhaustiva: hay algunas que no lo han hecho al momento de publicar ...
_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
Algunos de los datos que se emiten son:
Esto es para una nueva clase creada usando la clase Demo sin ningún dato asignado que no sea el nombre (por lo que se puede generar) que es _foo, el nombre de la variable que utilicé ...
_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)
Y esto es después de asignar todas las propiedades _foo (excepto el nombre) los siguientes valores en el mismo orden: 'cadena', 1.0, Verdadero, 9, 10, Falso
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) |
Tenga en cuenta que debido a tipos de datos restringidos o restricciones de valor, algunos datos no fueron asignados, esto es por diseño. El configurador prohíbe que se asignen valores o tipos de datos incorrectos, incluso si se asignan como un valor predeterminado (a menos que anule el comportamiento de protección del valor predeterminado)
El código no se ha publicado aquí porque no tuve espacio después de los ejemplos y explicaciones ... También porque va a cambiar.
Tenga en cuenta: al momento de esta publicación, el archivo está desordenado, esto cambiará. Pero, si lo ejecuta en Sublime Text y lo compila, o lo ejecuta desde Python, compilará y escupirá una gran cantidad de información: la parte de AccessorDB no se realiza (que se utilizará para actualizar el Asistente de impresión Getters y GetKeyOutput funciones junto con el cambio a una función de instancia, probablemente puesta en una sola función y renombrada - búscala ..)
A continuación: no se requiere todo para que se ejecute; muchas de las cosas comentadas en la parte inferior son para obtener más información utilizada para la depuración; puede que no esté allí cuando la descargue. Si es así, debería poder descomentar y volver a compilar para obtener más información.
Estoy buscando una solución alternativa para necesitar MyClassBase: pass, MyClass (MyClassBase): ... - si conoce una solución, publíquela.
Lo único necesario en la clase son las líneas __: el str es para la depuración como el init ; se pueden eliminar de la Clase de demostración, pero deberá comentar o eliminar algunas de las líneas a continuación (_foo / 2/3 ) ..
Las clases String, Dict y Util en la parte superior son parte de mi biblioteca Python, no están completas. Copié algunas cosas que necesitaba de la biblioteca, y creé algunas nuevas. El código completo se vinculará a la biblioteca completa y lo incluirá junto con el suministro de llamadas actualizadas y la eliminación del código (en realidad, el único código restante será la Clase Demo y las declaraciones impresas; el sistema AccessorFunc se moverá a la biblioteca). ..
Parte del archivo:
##
## 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 = { } )
Esta belleza hace que sea increíblemente fácil crear nuevas clases con propiedades agregadas dinámicamente con AccessorFuncs / callbacks / data-type / valueforcement, etc.
Por ahora, el enlace está en (Este enlace debe reflejar los cambios en el documento): https://www.dropbox.com/s/6gzi44i7dh58v61/dynamic_properties_accessorfuncs_and_more.py?dl=0
Además: si no usa Sublime Text, lo recomiendo sobre Notepad ++, Atom, Visual Code y otros debido a las implementaciones de subprocesos adecuadas que lo hacen mucho, mucho más rápido de usar ... También estoy trabajando en un código similar a IDE sistema de mapeo para ello: eche un vistazo a: https://bitbucket.org/Acecool/acecoolcodemappingsystem/src/master/ (Primero agregue Repo en el Administrador de paquetes, luego instale el complemento; cuando la versión 1.0.0 esté lista, agregaré a la lista principal de complementos ...)
Espero que esta solución ayude ... y, como siempre:
Solo porque funciona, no lo hace bien - Josh 'Acecool' Moser
:
y__init__
referenciasself.fn_readyonly
.