¿Cómo agregar propiedad a una clase dinámicamente?

El objective es crear una clase simulada que se comporte como un conjunto de resultados de db.

Por ejemplo, si una consulta de base de datos devuelve, usando una expresión de dict, {'ab':100, 'cd':200} , me gustaría ver:

 >>> dummy.ab 100 

Al principio pensé que tal vez podría hacerlo de esta manera:

 ks = ['ab', 'cd'] vs = [12, 34] class C(dict): def __init__(self, ks, vs): for i, k in enumerate(ks): self[k] = vs[i] setattr(self, k, property(lambda x: vs[i], self.fn_readyonly)) def fn_readonly(self, v) raise "It is ready only" if __name__ == "__main__": c = C(ks, vs) print c.ab 

pero c.ab devuelve un objeto de propiedad en su lugar.

Reemplazar la línea setattr con k = property(lambda x: vs[i]) no sirve para nada.

Entonces, ¿cuál es la forma correcta de crear una propiedad de instancia en tiempo de ejecución?

PS Estoy al tanto de una alternativa presentada en ¿Cómo se __getattribute__ método __getattribute__ ?

Supongo que debería ampliar esta respuesta, ahora que soy mayor y más sabio y sé lo que está pasando. Mejor tarde que nunca.

Puede agregar una propiedad a una clase dinámicamente. Pero ese es el problema: hay que agregarlo a la clase .

 >>> class Foo(object): ... pass ... >>> foo = Foo() >>> foo.a = 3 >>> Foo.b = property(lambda self: self.a + 1) >>> foo.b 4 

Una property es en realidad una implementación simple de una cosa llamada descriptor . Es un objeto que proporciona manejo personalizado para un atributo dado, en una clase dada . Un poco como una forma de factorizar un enorme árbol de __getattribute__ .

Cuando pido foo.b en el ejemplo anterior, Python ve que la b definida en la clase implementa el protocolo descriptor, lo que significa que es un objeto con un __get__ , __set__ o __delete__ . El descriptor se responsabiliza por el manejo de ese atributo, por lo que Python llama a Foo.b.__get__(foo, Foo) , y el valor devuelto se le devuelve como el valor del atributo. En el caso de la property , cada uno de estos métodos simplemente llama al fget , fset o fdel usted pasó al constructor de la property .

Los descriptores son realmente la forma de Python de exponer la plomería de toda su implementación OO. De hecho, hay otro tipo de descriptor aún más común que la property .

 >>> class Foo(object): ... def bar(self): ... pass ... >>> Foo().bar > >>> Foo().bar.__get__  

El método humilde es simplemente otro tipo de descriptor. Sus __get__ tacks en la instancia de llamada como el primer argumento; en efecto, hace esto:

 def __get__(self, instance, owner): return functools.partial(self.function, instance) 

De todos modos, sospecho que es por eso que los descriptores solo funcionan en las clases: son una formalización de las cosas que impulsan las clases en primer lugar. Incluso son la excepción a la regla: ¡obviamente puede asignar descriptores a una clase, y las clases son en sí mismas instancias de type ! De hecho, al intentar leer Foo.b aún se llama la property.__get__ ; es simplemente idiomático para que los descriptores se devuelvan cuando se accede a ellos como atributos de clase.

Creo que es genial que prácticamente todo el sistema OO de Python se pueda express en Python. 🙂

Ah, y hace un tiempo escribí una publicación en el blog sobre descriptores si está interesado.

El objective es crear una clase simulada que se comporte como un conjunto de resultados de db.

Entonces, ¿lo que quieres es un diccionario donde puedas deletrear una [‘b’] como ab?

Eso es fácil:

 class atdict(dict): __getattr__= dict.__getitem__ __setattr__= dict.__setitem__ __delattr__= dict.__delitem__ 

Parece que podría resolver este problema mucho más simplemente con un namedtuple con namedtuple , ya que conoce la lista completa de campos antes de tiempo.

 from collections import namedtuple Foo = namedtuple('Foo', ['bar', 'quux']) foo = Foo(bar=13, quux=74) print foo.bar, foo.quux foo2 = Foo() # error 

Si absolutamente necesita escribir su propio setter, tendrá que hacer la metaprogtwigción a nivel de clase; property() no funciona en instancias.

No necesitas usar una propiedad para eso. Simplemente anule __setattr__ para que sean de solo lectura.

 class C(object): def __init__(self, keys, values): for (key, value) in zip(keys, values): self.__dict__[key] = value def __setattr__(self, name, value): raise Exception("It is read only!") 

Tada

 >>> c = C('abc', [1,2,3]) >>> ca 1 >>> cb 2 >>> cc 3 >>> cd Traceback (most recent call last): File "", line 1, in  AttributeError: 'C' object has no attribute 'd' >>> cd = 42 Traceback (most recent call last): File "", line 1, in  File "", line 6, in __setattr__ Exception: It is read only! >>> ca = 'blah' Traceback (most recent call last): File "", line 1, in  File "", line 6, in __setattr__ Exception: It is read only! 

Hice una pregunta similar en esta publicación de desbordamiento de stack para crear una fábrica de clases que creara tipos simples. El resultado fue esta respuesta que tenía una versión de trabajo de la fábrica de clase. Aquí hay un fragmento de la respuesta:

 def Struct(*args, **kwargs): def init(self, *iargs, **ikwargs): for k,v in kwargs.items(): setattr(self, k, v) for i in range(len(iargs)): setattr(self, args[i], iargs[i]) for k,v in ikwargs.items(): setattr(self, k, v) name = kwargs.pop("name", "MyStruct") kwargs.update(dict((k, None) for k in args)) return type(name, (object,), {'__init__': init, '__slots__': kwargs.keys()}) >>> Person = Struct('fname', 'age') >>> person1 = Person('Kevin', 25) >>> person2 = Person(age=42, fname='Terry') >>> person1.age += 10 >>> person2.age -= 10 >>> person1.fname, person1.age, person2.fname, person2.age ('Kevin', 35, 'Terry', 32) >>> 

Podría usar alguna variación de esto para crear valores predeterminados, que es su objective (también hay una respuesta en esa pregunta que se ocupa de esto).

¿Cómo agregar propiedades a una clase de python dinámicamente?

Digamos que tiene un objeto al que desea agregar una propiedad. Por lo general, quiero usar las propiedades cuando necesito comenzar a administrar el acceso a un atributo en el código que tiene un uso descendente, para poder mantener una API consistente. Ahora normalmente los agregaré al código fuente donde se define el objeto, pero supongamos que no tiene ese acceso, o que necesita elegir sus funciones de forma dinámica y real mediante progtwigción.

Crear una clase

Usando un ejemplo basado en la documentación para la property , creemos una clase de objeto con un atributo “oculto” y creamos una instancia de él:

 class C(object): '''basic class''' _x = None o = C() 

En Python, esperamos que haya una manera obvia de hacer las cosas. Sin embargo, en este caso, voy a mostrar dos formas: con notación de decorador y sin. Primero, sin notación decoradora. Esto puede ser más útil para la asignación dinámica de captadores, configuradores o eliminadores.

Dinámico (también conocido como Monkey Patching)

Vamos a crear algunos para nuestra clase:

 def getx(self): return self._x def setx(self, value): self._x = value def delx(self): del self._x 

Y ahora les asignamos estos a la propiedad. Tenga en cuenta que podríamos elegir nuestras funciones programáticamente aquí, respondiendo a la pregunta dinámica:

 Cx = property(getx, setx, delx, "I'm the 'x' property.") 

Y uso:

 >>> ox = 'foo' >>> ox 'foo' >>> del ox >>> print(ox) None >>> help(Cx) Help on property: I'm the 'x' property. 

Decoradores

Podríamos hacer lo mismo que hicimos anteriormente con la notación de decorador, pero en este caso, debemos nombrar a los métodos con el mismo nombre (y recomendaría mantenerlo igual que el atributo), por lo que la asignación programática no es tan trivial como está utilizando el método anterior:

 @property def x(self): '''I'm the 'x' property.''' return self._x @x.setter def x(self, value): self._x = value @x.deleter def x(self): del self._x 

Y asigne el objeto de propiedad con sus definidores y eliminadores aprovisionados a la clase:

 Cx = x 

Y uso:

 >>> help(Cx) Help on property: I'm the 'x' property. >>> ox >>> ox = 'foo' >>> ox 'foo' >>> del ox >>> print(ox) None 

No puede agregar una nueva property() a una instancia en tiempo de ejecución, porque las propiedades son descriptores de datos. En su lugar, debe crear dinámicamente una nueva clase, o sobrecargar __getattribute__ para procesar los descriptores de datos en las instancias.

No estoy seguro si entiendo completamente la pregunta, pero puede modificar las propiedades de la instancia en tiempo de ejecución con el __dict__ de su clase:

 class C(object): def __init__(self, ks, vs): self.__dict__ = dict(zip(ks, vs)) if __name__ == "__main__": ks = ['ab', 'cd'] vs = [12, 34] c = C(ks, vs) print(c.ab) # 12 

Para aquellos que vienen de los motores de búsqueda, aquí están las dos cosas que estaba buscando al hablar de propiedades dinámicas :

 class Foo: def __init__(self): # we can dynamically have access to the properties dict using __dict__ self.__dict__['foo'] = 'bar' assert Foo().foo == 'bar' # or we can use __getattr__ and __setattr__ to execute code on set/get class Bar: def __init__(self): self._data = {} def __getattr__(self, key): return self._data[key] def __setattr__(self, key, value): self._data[key] = value bar = Bar() bar.foo = 'bar' assert bar.foo == 'bar' 

__dict__ es bueno si quieres poner propiedades creadas dinámicamente. __getattr__ es bueno hacer solo algo cuando se necesita el valor, como consultar una base de datos. El combo set / get es bueno para simplificar el acceso a los datos almacenados en la clase (como en el ejemplo anterior).

Si solo desea una propiedad dinámica, eche un vistazo a la función incorporada property () .

La mejor manera de lograrlo es definiendo __slots__ . De esa manera sus instancias no pueden tener nuevos atributos.

 ks = ['ab', 'cd'] vs = [12, 34] class C(dict): __slots__ = [] def __init__(self, ks, vs): self.update(zip(ks, vs)) def __getattr__(self, key): return self[key] if __name__ == "__main__": c = C(ks, vs) print c.ab 

Que imprime 12

  c.ab = 33 

Eso da: AttributeError: 'C' object has no attribute 'ab'

Solo otro ejemplo de cómo lograr el efecto deseado.

 class Foo(object): _bar = None @property def bar(self): return self._bar @bar.setter def bar(self, value): self._bar = value def __init__(self, dyn_property_name): setattr(Foo, dyn_property_name, Foo.bar) 

Así que ahora podemos hacer cosas como:

 >>> foo = Foo('baz') >>> foo.baz = 5 >>> foo.bar 5 >>> foo.baz 5 

Puede usar el siguiente código para actualizar los atributos de clase utilizando un objeto de diccionario:

 class ExampleClass(): def __init__(self, argv): for key, val in argv.items(): self.__dict__[key] = val if __name__ == '__main__': argv = {'intro': 'Hello World!'} instance = ExampleClass(argv) print instance.intro 

Esto parece funcionar (pero ver más abajo):

 class data(dict,object): def __init__(self,*args,**argd): dict.__init__(self,*args,**argd) self.__dict__.update(self) def __setattr__(self,name,value): raise AttributeError,"Attribute '%s' of '%s' object cannot be set"%(name,self.__class__.__name__) def __delattr__(self,name): raise AttributeError,"Attribute '%s' of '%s' object cannot be deleted"%(name,self.__class__.__name__) 

Si necesita un comportamiento más complejo, siéntase libre de editar su respuesta.

editar

Lo siguiente probablemente sería más eficiente en memoria para grandes conjuntos de datos:

 class data(dict,object): def __init__(self,*args,**argd): dict.__init__(self,*args,**argd) def __getattr__(self,name): return self[name] def __setattr__(self,name,value): raise AttributeError,"Attribute '%s' of '%s' object cannot be set"%(name,self.__class__.__name__) def __delattr__(self,name): raise AttributeError,"Attribute '%s' of '%s' object cannot be deleted"%(name,self.__class__.__name__) 

Para responder a la idea principal de su pregunta, desea un atributo de solo lectura de un dict como fuente de datos inmutable:

El objective es crear una clase simulada que se comporte como un conjunto de resultados de db.

Entonces, por ejemplo, si una consulta de base de datos devuelve, usando una expresión dict, {'ab':100, 'cd':200} , entonces vería

 >>> dummy.ab 100 

Demostraré cómo usar una namedtuple del módulo de collections para lograr esto:

 import collections data = {'ab':100, 'cd':200} def maketuple(d): '''given a dict, return a namedtuple''' Tup = collections.namedtuple('TupName', d.keys()) # iterkeys in Python2 return Tup(**d) dummy = maketuple(data) dummy.ab 

devuelve 100

 class atdict(dict): def __init__(self, value, **kwargs): super().__init__(**kwargs) self.__dict = value def __getattr__(self, name): for key in self.__dict: if type(self.__dict[key]) is list: for idx, item in enumerate(self.__dict[key]): if type(item) is dict: self.__dict[key][idx] = atdict(item) if type(self.__dict[key]) is dict: self.__dict[key] = atdict(self.__dict[key]) return self.__dict[name] d1 = atdict({'a' : {'b': [{'c': 1}, 2]}}) print(d1.ab[0].c) 

Y la salida es:

 >> 1 

Extendiendo la idea desde kjfletch

 # This is my humble contribution, extending the idea to serialize # data from and to tuples, comparison operations and allowing functions # as default values. def Struct(*args, **kwargs): FUNCTIONS = (types.BuiltinFunctionType, types.BuiltinMethodType, \ types.FunctionType, types.MethodType) def init(self, *iargs, **ikwargs): """Asume that unamed args are placed in the same order than astuple() yields (currently alphabetic order) """ kw = list(self.__slots__) # set the unnamed args for i in range(len(iargs)): k = kw.pop(0) setattr(self, k, iargs[i]) # set the named args for k, v in ikwargs.items(): setattr(self, k, v) kw.remove(k) # set default values for k in kw: v = kwargs[k] if isinstance(v, FUNCTIONS): v = v() setattr(self, k, v) def astuple(self): return tuple([getattr(self, k) for k in self.__slots__]) def __str__(self): data = ['{}={}'.format(k, getattr(self, k)) for k in self.__slots__] return '<{}: {}>'.format(self.__class__.__name__, ', '.join(data)) def __repr__(self): return str(self) def __eq__(self, other): return self.astuple() == other.astuple() name = kwargs.pop("__name__", "MyStruct") slots = list(args) slots.extend(kwargs.keys()) # set non-specific default values to None kwargs.update(dict((k, None) for k in args)) return type(name, (object,), { '__init__': init, '__slots__': tuple(slots), 'astuple': astuple, '__str__': __str__, '__repr__': __repr__, '__eq__': __eq__, }) Event = Struct('user', 'cmd', \ 'arg1', 'arg2', \ date=time.time, \ __name__='Event') aa = Event('pepe', 77) print(aa) raw = aa.astuple() bb = Event(*raw) print(bb) if aa == bb: print('Are equals') cc = Event(cmd='foo') print(cc) 

Salida:

   Are equals  

Aunque se dan muchas respuestas, no pude encontrar una con la que estuviera contento. Descubrí mi propia solución que hace que la property funcione para el caso dynamic. La fuente para responder a la pregunta original:

 #!/usr/local/bin/python3 INITS = { 'ab': 100, 'cd': 200 } class DP(dict): def __init__(self): super().__init__() for k,v in INITS.items(): self[k] = v def _dict_set(dp, key, value): dp[key] = value for item in INITS.keys(): setattr( DP, item, lambda key: property( lambda self: self[key], lambda self, value: _dict_set(self, key, value) )(item) ) a = DP() print(a) # {'ab': 100, 'cd': 200} a.ab = 'ab100' a.cd = False print(a.ab, a.cd) # ab100 False 

La única forma de adjuntar dinámicamente una propiedad es crear una nueva clase y su instancia con su nueva propiedad.

 class Holder: p = property(lambda x: vs[i], self.fn_readonly) setattr(self, k, Holder().p) 

Recientemente me encontré con un problema similar, la solución que encontré usa __getattr__ y __setattr__ para las propiedades que quiero que maneje, todo lo demás pasa a los originales.

 class C(object): def __init__(self, properties): self.existing = "Still Here" self.properties = properties def __getattr__(self, name): if "properties" in self.__dict__ and name in self.properties: return self.properties[name] # Or call a function, etc return self.__dict__[name] def __setattr__(self, name, value): if "properties" in self.__dict__ and name in self.properties: self.properties[name] = value else: self.__dict__[name] = value if __name__ == "__main__": my_properties = {'a':1, 'b':2, 'c':3} c = C(my_properties) assert ca == 1 assert c.existing == "Still Here" cb = 10 assert c.properties['b'] == 10 

Muchas de las respuestas proporcionadas requieren tantas líneas por propiedad, es decir, y / o, lo que 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 No se puede simplificar más o hasta que no sirva de mucho propósito hacerlo.

En resumen: en trabajos terminados, 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 los argumentos matemáticos o impares como (start_x, start_y, end_x, end_y) para (x, y, w, h) es decir, x, y, x + w, y + h (a veces se requieren min / max o si w / h son negativos y no le gusta a la implementación, restaré de x / y y abs w / h. etc.).

Reemplazar a los captadores / setters internos es una buena forma de proceder, pero el problema es que debes hacer eso para cada clase, o asignar la clase a esa base … Esto no funciona para mí, ya que prefiero serlo. 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 suministrar los datos, ya que me parece 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 cambian , restrinja los datos que se pueden establecer en función del valor y / o el 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 la clase, pero la propiedad real se asigna a la clase, es decir, las cosas que no desea repetir, no es necesario repetirlas … puede asignar un valor predeterminado para que el captador no lo necesite cada vez, aunque hay una opción para anular el valor predeterminado predeterminado, y hay otra opción para que el captador devuelva el valor almacenado en bruto al reemplazar 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 asigna ninguno, etc.)

También hay muchas funciones de ayuda: la primera propiedad que se agrega agrega más o menos ayudantes a la clase para hacer referencia a los valores de instancia … Son ResetAccessors (_key, ..) varargs repetidos (todos se pueden repetir usando los primeros argumentos con nombre) ) y SetAccessors (_key, _value) con la opción de agregar más a la clase principal para ayudar en la eficiencia, las planeadas son: una forma de agrupar los accesores juntos, así 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 nombradas cada vez, y más.

La instancia / valor almacenado sin procesar se almacena en la clase. , la clase. hace referencia a la Clase de accesores que contiene valores / funciones / funciones estáticas para la propiedad. _clase. es la propiedad en sí misma a la que se llama cuando se accede a través de la clase de instancia durante la configuración / obtención, etc.

El Accessor _class .__ apunta a la clase, pero como es interno, debe asignarse en la clase, por lo que opté por usar __Name = AccessorFunc (…) para asignarlo, una sola línea por propiedad con muchos opcionales. argumentos a usar (usando varargs codificados porque son más fáciles y eficientes de identificar y mantener) …

También creo muchas funciones, como se mencionó, algunas de las cuales utilizan la información de la función de accesores, por lo que no es necesario invocarlas (ya que es un poco inconveniente en este momento; ahora mismo necesitas usar _class. .FunctionName (_class_instance , args) – Logré usar la stack / traza para tomar la referencia de la instancia para tomar el valor agregando las funciones que ejecutan este maratón de bits, o agregando los accesores al objeto y utilizando self (llamado así para señalar que para la instancia y para retener el acceso a uno mismo, a la referencia de la clase AccessorFunc y otra información dentro de las definiciones de funciones).

No está del todo terminado, pero es un fantástico estribo. Nota: Si no usa __Name = AccessorFunc (…) para crear las propiedades, no tendrá acceso a la tecla __ aunque lo defina dentro de la función init. Si lo haces, entonces no hay problemas.

Además: tenga en cuenta que el nombre y la clave son diferentes … El nombre es ‘formal’, se utiliza en la creación del nombre de la función, y la clave es para el acceso y almacenamiento de datos. es decir, _class.x donde x es minúscula, el nombre sería X en mayúscula, de modo que GetX () es la función en lugar de Getx () que se ve un poco extraño. esto permite que self.x funcione y se vea apropiado, pero también permita GetX () y se vea apropiado.

Tengo una clase de ejemplo configurada con clave / nombre idéntico, y diferente para mostrar. muchas funciones de ayuda creadas para generar los datos (Nota: no todo está completo) para que pueda ver lo que está sucediendo.

La lista actual de funciones mediante la tecla: x, nombre: X se muestra como:

Esto no es de ninguna manera una lista completa, hay algunos 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( _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() 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.__ ) [ AccessorFuncBase ] Key: x : Class ID: 2231452344344 : self ID: 2231448283848 Default: 1111 Allowed Types: {"": "", "": ""} Allowed Values: None this.GetXAllowedTypes( ) ALLOWED_TYPES: Returns Allowed Data-Types {"": "", "": ""} 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 __.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 están emitiendo son:

Esto es para una clase nueva creada con la clase Demo sin ningún otro tipo de datos asignado que no sea el nombre (para que pueda obtenerse) que es _foo, el nombre de variable que usé …

 _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( )  | __Name.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type | x: 1111 | _x: None | __x.DefaultValue( ): 1111 | __x.GetAllowedTypes( ) (, ) | __x.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type | y: 2222 | _y: None | __y.DefaultValue( ): 2222 | __y.GetAllowedTypes( ) (, ) | __y.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type | z: 3333 | _z: None | __z.DefaultValue( ): 3333 | __z.GetAllowedTypes( ) (, ) | __z.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type | Blah:  | _Blah: None | __Blah.DefaultValue( ):  | __Blah.GetAllowedTypes( )  | __Blah.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type | Width: 1 | _Width: None | __Width.DefaultValue( ): 1 | __Width.GetAllowedTypes( ) (, ) | __Width.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type | Height: 0 | _Height: None | __Height.DefaultValue( ): 0 | __Height.GetAllowedTypes( )  | __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( ):  this.GetNameGetterPrefix( ): None this.IsXSet( ): False this.GetX( ): 1111 this.GetXRaw( ): None this.GetXDefaultValue( ): 1111 this.GetXLen( ): 4 this.HasXGetterPrefix( ): (, ) this.GetXGetterPrefix( ): None this.IsYSet( ): False this.GetY( ): 2222 this.GetYRaw( ): None this.GetYDefaultValue( ): 2222 this.GetYLen( ): 4 this.HasYGetterPrefix( ): (, ) this.GetYGetterPrefix( ): None this.IsZSet( ): False this.GetZ( ): 3333 this.GetZRaw( ): None this.GetZDefaultValue( ): 3333 this.GetZLen( ): 4 this.HasZGetterPrefix( ): (, ) this.GetZGetterPrefix( ): None this.IsBlahSet( ): False this.GetBlah( ):  this.GetBlahRaw( ): None this.GetBlahDefaultValue( ):  this.GetBlahLen( ): 13 this.HasBlahGetterPrefix( ):  this.GetBlahGetterPrefix( ): None this.IsWidthSet( ): False this.GetWidth( ): 1 this.GetWidthRaw( ): None this.GetWidthDefaultValue( ): 1 this.GetWidthLen( ): 1 this.HasWidthGetterPrefix( ): (, ) 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( ):  this.GetHeightGetterPrefix( ): (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) 

Y esto es después de asignar a 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( ):  this.GetNameGetterPrefix( ): None this.IsXSet( ): True this.GetX( ): 10 this.GetXRaw( ): 10 this.GetXDefaultValue( ): 1111 this.GetXLen( ): 2 this.HasXGetterPrefix( ): (, ) this.GetXGetterPrefix( ): None this.IsYSet( ): True this.GetY( ): 10 this.GetYRaw( ): 10 this.GetYDefaultValue( ): 2222 this.GetYLen( ): 2 this.HasYGetterPrefix( ): (, ) this.GetYGetterPrefix( ): None this.IsZSet( ): True this.GetZ( ): 10 this.GetZRaw( ): 10 this.GetZDefaultValue( ): 3333 this.GetZLen( ): 2 this.HasZGetterPrefix( ): (, ) this.GetZGetterPrefix( ): None this.IsBlahSet( ): True this.GetBlah( ): string Blah this.GetBlahRaw( ): string Blah this.GetBlahDefaultValue( ):  this.GetBlahLen( ): 11 this.HasBlahGetterPrefix( ):  this.GetBlahGetterPrefix( ): None this.IsWidthSet( ): True this.GetWidth( ): False this.GetWidthRaw( ): False this.GetWidthDefaultValue( ): 1 this.GetWidthLen( ): 5 this.HasWidthGetterPrefix( ): (, ) 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( ):  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( )  | __Name.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type | x: 10 | _x: 10 | __x.DefaultValue( ): 1111 | __x.GetAllowedTypes( ) (, ) | __x.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type | y: 10 | _y: 10 | __y.DefaultValue( ): 2222 | __y.GetAllowedTypes( ) (, ) | __y.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type | z: 10 | _z: 10 | __z.DefaultValue( ): 3333 | __z.GetAllowedTypes( ) (, ) | __z.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type | Blah: string Blah | _Blah: string Blah | __Blah.DefaultValue( ):  | __Blah.GetAllowedTypes( )  | __Blah.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type | Width: False | _Width: False | __Width.DefaultValue( ): 1 | __Width.GetAllowedTypes( ) (, ) | __Width.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type | Height: 9 | _Height: 9 | __Height.DefaultValue( ): 0 | __Height.GetAllowedTypes( )  | __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) | 

Note that because of restricted data-types or value restrictions, some data wasn’t assigned – this is by design. The setter prohibits bad data-types or values from being assigned, even from being assigned as a default value ( unless you override the default value protection behavior )

The code hasn’t been posted here because I didn’t have room after the examples and explanations… Also because it will change.

Please Note: at the time of this posting, the file is messy – this will change. But, if you run it in Sublime Text and compile it, or run it from Python, it will compile and spit out a ton of information – the AccessorDB portion isn’t done ( which will be used to update the Print Getters and GetKeyOutput helper functions along with being changed to an Instance function, probably put into a single function and renamed – look for it.. )

Next: Not everything is required for it to run – a lot of the commented stuff at the bottom is for more information used for debugging – it may not be there when you download it. If it is, you should be able to uncomment and recompile to get more information.

I am looking for a work-around to needing MyClassBase: pass, MyClass( MyClassBase ): … – if you know of a solution – post it.

The only thing necessary in the class are the __ lines – the str is for debugging as is the init – they can be removed from the Demo Class but you will need to comment out or remove some of the lines below ( _foo / 2 / 3 )..

The String, Dict, and Util classes at the top are a part of my Python library – they are not complete. I copied over a few things I needed from the library, and I created a few new ones. The full code will link to the complete library and will include it along with providing updated calls and removing the code ( actually, the only code left will be the Demo Class and the print statements – the AccessorFunc system will be moved to the library )…

Part of 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 = { } ) 

This beauty makes it incredibly easy to create new classes with dynamically added properties with AccessorFuncs / callbacks / data-type / value enforcement, etc.

For now, the link is at ( This link should reflect changes to the document. ): https://www.dropbox.com/s/6gzi44i7dh58v61/dynamic_properties_accessorfuncs_and_more.py?dl=0

Also: If you don’t use Sublime Text, I recommend it over Notepad++, Atom, Visual Code, and others because of proper threading implementations making it much, much faster to use… I am also working on an IDE-like code mapping system for it – take a look at: https://bitbucket.org/Acecool/acecoolcodemappingsystem/src/master/ ( Add Repo in Package Manager first, then Install Plugin – when version 1.0.0 is ready, I’ll add it to the main plugin list… )

I hope this solution helps… and, as always:

Just because it works, doesn’t make it right – Josh ‘Acecool’ Moser