Pregunta

El objetivo es crear una clase simulada que se comporta como un conjunto de resultados db.

Así, por ejemplo, si una consulta de base de datos devuelve, utilizando una expresión dict, {'ab':100, 'cd':200}, entonces 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

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

Sustitución de la línea setattr con k = property(lambda x: vs[i]) es de ninguna utilidad en absoluto.

Entonces, ¿cuál es el camino correcto para crear una propiedad de instancia en tiempo de ejecución?

P.S. Soy consciente de una alternativa que se presenta en ¿Cómo se utiliza el método __getattribute__?

¿Fue útil?

Solución

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

puede añadir una propiedad a una clase dinámicamente. Pero eso está la trampa: hay que añadirlo a la class

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

A property es en realidad una aplicación simple de una cosa que se llama un descriptor . Es un objeto que proporciona la costumbre de manipulación para un atributo dado, en una clase dada . Un poco como una manera de factorizar un enorme árbol if de __getattribute__.

Cuando pido foo.b en el ejemplo anterior, Python ve que el b definido en la clase implementa la protocolo descriptor -que simplemente significa que es un objeto con un __get__, __set__, o método __delete__. El descriptor se atribuye la responsabilidad para el manejo de ese atributo, lo que Python llama Foo.b.__get__(foo, Foo), y el valor de retorno se pasa de nuevo a usted como el valor del atributo. En el caso de property, cada uno de estos métodos sólo llama a la fget, fset o fdel se pasa al constructor property.

Los descriptores son realmente manera de exponer las cañerías de la totalidad de su aplicación OO de Python. De hecho, hay otro tipo de descriptor incluso más común que property.

>>> class Foo(object):
...     def bar(self):
...         pass
... 
>>> Foo().bar
<bound method Foo.bar of <__main__.Foo object at 0x7f2a439d5dd0>>
>>> Foo().bar.__get__
<method-wrapper '__get__' of instancemethod object at 0x7f2a43a8a5a0>

El método humilde es más que otro tipo de descriptor. Sus tachuelas __get__ en la instancia llamando como primer argumento; en efecto, se hace lo siguiente:

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

De todos modos, sospecho que esta es la razón por descriptores sólo funcionan en las clases: son una formalización de las cosas que las clases de poderes en el primer lugar. Son aún la excepción a la regla: es obvio que puede asignar descriptores a una clase, y las clases son a su vez los casos de type! De hecho, tratando de leer Foo.b todavía llama property.__get__; es sólo idiomática para los descriptores para volver a sí mismos cuando se accede como atributos de clase.

Creo que es muy bueno que prácticamente todos los sistemas OO de Python se puede expresar en Python. :)

Ah, y escribí un blog prolijo acerca de los descriptores hace un tiempo si está interesado.

Otros consejos

  

El objetivo es crear una clase simulada que se comporta como un conjunto de resultados db.

Así que lo que quiere es un diccionario donde se puede deletrear una [ 'b'] como a.b?

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 simple con un namedtuple , ya que usted sabe toda la lista 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 es absolutamente necesario escribir su propio organismo, que tendrá que hacer el metaprogramming a nivel de clase; property() no funciona en los casos.

No es necesario utilizar una propiedad para eso. Sólo anular __setattr__ para que sean de sólo 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])
>>> c.a
1
>>> c.b
2
>>> c.c
3
>>> c.d
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute 'd'
>>> c.d = 42
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __setattr__
Exception: It is read only!
>>> c.a = 'blah'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __setattr__
Exception: It is read only!
  

Cómo añadir una propiedad a una clase dinámicamente pitón?

Digamos que tienes un objeto que desea agregar una propiedad a. Por lo general, quiero usar propiedades cuando necesito para comenzar a gestionar el acceso a un atributo de código que tiene el uso de aguas abajo, de modo que pueda mantener una API consistente. Ahora voy a típicamente añadirlas al código fuente donde se define el objeto, pero vamos a suponer que usted no tiene que el acceso, o tiene que elegir verdaderamente dinámicamente sus funciones mediante programación.

Crea una clase

El uso de un ejemplo basado en la documentación rel="noreferrer"> property , vamos a crear una clase de objeto con un atributo "oculto" y crear una instancia del mismo:

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 maneras: con la notación decorador, y desde fuera. En primer lugar, sin notación decorador. Esto puede ser más útil para la asignación dinámica de getters, organismos, o eliminadores.

Dinámica (también conocido como mono de parches)

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 asignamos estos a la propiedad. Tenga en cuenta que podríamos elegir nuestras funciones mediante programación aquí, responder a la pregunta dinámica:

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

Y uso:

>>> o.x = 'foo'
>>> o.x
'foo'
>>> del o.x
>>> print(o.x)
None
>>> help(C.x)
Help on property:

    I'm the 'x' property.

decoradores

Podríamos hacer lo mismo que lo hicimos anteriormente con la notación decorador, pero en este caso, que el nombre de los métodos, todos ellos del mismo nombre (y recomiendo mantenerlo lo mismo que el atributo ), misiones de manera programática no es tan trivial, ya que 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 asignar el objeto de propiedad con su setter aprovisionados y eliminadores a la clase:

C.x = x

Y uso:

>>> help(C.x)
Help on property:

    I'm the 'x' property.

>>> o.x
>>> o.x = 'foo'
>>> o.x
'foo'
>>> del o.x
>>> print(o.x)
None

Le pregunté a una pregunta similary en este desbordamiento de pila publicación para crear un generador de clases que creó tipos simples. El resultado fue esta respuesta la 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)
>>>

Usted podría utilizar alguna variación de esto para crear valores por defecto, que es su objetivo (también hay una respuesta en esa pregunta que se ocupa de esto).

No se puede agregar un nuevo property() a una instancia en tiempo de ejecución, ya que las propiedades son descriptores de datos. En su lugar debe crear dinámicamente una nueva clase, o __getattribute__ sobrecarga con el fin de procesar descriptores de datos sobre los casos.

No estoy seguro si entiendo muy bien la pregunta, pero se puede modificar propiedades de la instancia en tiempo de ejecución con la incorporada en el __dict__ de la 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 los que vienen de los motores de búsqueda, aquí son las dos cosas que estaba buscando cuando se habla de dinámicas propiedades:

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 usted quiere poner propiedades creadas dinámicamente. __getattr__ es bueno sólo para hacer algo cuando se necesita el valor, al igual que consulta una base de datos. El set / get combo es buena para simplificar el acceso a los datos almacenados en la clase (como en el ejemplo anterior).

Si sólo desea una propiedad dinámica, echar un vistazo a la href="https://docs.python.org/3/library/functions.html#property" rel="nofollow noreferrer"> propiedad función incorporada.

La mejor manera de lograr es mediante la definición de __slots__. De esa manera sus casos no puede 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'

Sólo 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 utilizar 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 véase 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, no dude en editar su respuesta.

editar

La siguiente probablemente sería más eficaz 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 central de su pregunta, usted quiere un atributo de sólo lectura de un diccionario como una fuente de datos inmutables:

  

El objetivo es crear una clase simulada que se comporta como un conjunto de resultados db.

     

Así, por ejemplo, si una consulta de base de datos devuelve, utilizando una expresión dict,   {'ab':100, 'cd':200}, entonces yo sería para ver

>>> dummy.ab
100

Voy a demostrar cómo utilizar un namedtuple del módulo collections a lograr precisamente 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

retornos 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.a.b[0].c)

Y la salida es:

>> 1

La extensión de la idea de 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:

<Event: user=pepe, cmd=77, arg1=None, arg2=None, date=1550051398.3651814>
<Event: user=pepe, cmd=77, arg1=None, arg2=None, date=1550051398.3651814>
Are equals
<Event: user=None, cmd=foo, arg1=None, arg2=None, date=1550051403.7938335>

A pesar de que se dan muchas respuestas, no pude encontrar uno que estoy feliz. Me di cuenta de mi propia solución que hace que el trabajo property para el caso dinámico. 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

Algo que funciona para mí es la siguiente:

class C:
    def __init__(self):
        self._x=None

    def g(self):
        return self._x

    def s(self, x):
        self._x = x

    def d(self):
        del self._x

    def s2(self,x):
        self._x=x+x

    x=property(g,s,d)


c = C()
c.x="a"
print(c.x)

C.x=property(C.g, C.s2)
C.x=C.x.deleter(C.d)
c2 = C()
c2.x="a"
print(c2.x)

salida

a
aa

Esto es un poco diferente de lo que quería OP, pero me sacudió mi cerebro hasta que llegué a una solución de trabajo, por lo que estoy poniendo aquí para el siguiente tipo / gal

que necesitaba una manera de especificar los emisores y los captadores dinámicos.

class X:
    def __init__(self, a=0, b=0, c=0):
        self.a = a
        self.b = b
        self.c = c

    @classmethod
    def _make_properties(cls, field_name, inc):
        _inc = inc

        def _get_properties(self):
            if not hasattr(self, '_%s_inc' % field_name):
                setattr(self, '_%s_inc' % field_name, _inc)
                inc = _inc
            else:
                inc = getattr(self, '_%s_inc' % field_name)

            return getattr(self, field_name) + inc

        def _set_properties(self, value):
            setattr(self, '_%s_inc' % field_name, value)

        return property(_get_properties, _set_properties)

Sé que mis campos antes de tiempo tan im va a crear mis propiedades. NOTA: no se puede hacer esto por instancia, estas propiedades existirán en la clase !!!

for inc, field in enumerate(['a', 'b', 'c']):
    setattr(X, '%s_summed' % field, X._make_properties(field, inc))

Vamos a probar todo ahora ..

x = X()
assert x.a == 0
assert x.b == 0
assert x.c == 0

assert x.a_summed == 0  # enumerate() set inc to 0 + 0 = 0
assert x.b_summed == 1  # enumerate() set inc to 1 + 0 = 1
assert x.c_summed == 2  # enumerate() set inc to 2 + 0 = 2

# we set the variables to something
x.a = 1
x.b = 2
x.c = 3

assert x.a_summed == 1  # enumerate() set inc to 0 + 1 = 1
assert x.b_summed == 3  # enumerate() set inc to 1 + 2 = 3
assert x.c_summed == 5  # enumerate() set inc to 2 + 3 = 5

# we're changing the inc now
x.a_summed = 1 
x.b_summed = 3 
x.c_summed = 5

assert x.a_summed == 2  # we set inc to 1 + the property was 1 = 2
assert x.b_summed == 5  # we set inc to 3 + the property was 2 = 5
assert x.c_summed == 8  # we set inc to 5 + the property was 3 = 8

¿Es confuso? Sí, lo siento, no pude encontrar ningún ejemplo del mundo real significativas. Además, esto no es para la luz de corazón.

Sólo manera de unir dinámicamente una propiedad es crear una nueva clase y su ejemplo, con su nueva propiedad.

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

Hace poco me encontré con un problema similar, la solución que se me ocurrió usos __getattr__ y __setattr__ de las propiedades que quiero que le permite manejar, todo lo demás se transmite 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 c.a == 1
    assert c.existing == "Still Here"
    c.b = 10
    assert c.properties['b'] == 10

Muchas de las respuestas suministradas requiere tantas líneas por propiedad, es decir, / y / o - lo que yo considero una implementación feo o aburrido, debido a la repetitividad requerida para múltiples propiedades, etc. Yo prefiero dejar hervir las cosas / simplificando hasta que no se pueden simplificar más, o hasta que no ayuda demasiado para hacerlo.

En resumen: en obras terminadas, si repito 2 líneas de código, normalmente convertirlo en una función auxiliar sola línea, y así sucesivamente ... simplifico matemáticas o impares argumentos tales como (start_x, start_y, end_x, end_y) a (x, y, w, h), es decir x, y, x + w, y + h (a veces requieren min / max o si w / h son negativos y la aplicación no le gusta, voy a restar de x / y y abs w / h. etc ..).

Anulación de los getters / setters internos es una manera bien para ir, pero el problema es que hay que hacer que para cada clase, o los padres de la clase a esa base ... Esto no funciona para mí ya que había prefieren tener libertad para elegir los niños / padres por herencia, los nodos secundarios, etc.

He creado una solución que responde a la pregunta sin necesidad de utilizar un tipo de datos Dict para suministrar los datos ya que me parece que para ser tedioso para introducir los datos, etc ...

Mi solución requiere que se agregue 2 líneas adicionales por encima de su clase para crear una clase base para la clase que desea agregar las propiedades a, a continuación, 1 línea por y usted tiene la opción de añadir devoluciones de llamada para controlar los datos, se informará cuando los cambios de datos, restringir los datos que pueden ajustarse basa en el valor y / o de tipo de datos, y mucho más.

También tiene la opción de utilizar _object.x, _object.x = valor, _object.GetX (), _object.SetX (valor) y que se manejan de forma equivalente.

Además, los valores son los únicos datos no estática que se asigna a la instancia de clase, pero la propiedad real se asignan a la clase que significa que las cosas que no desea repetir, no es necesario repetir. .. se puede asignar un valor por defecto por lo que el comprador no cada vez que necesita, aunque no es una opción para anular el valor por defecto por defecto, y no hay otra opción por lo que el comprador devuelve el valor almacenado en bruto anulando vuelve por defecto (nota : este método significa el valor en bruto solamente se asigna cuando se asigna un valor, de lo contrario es Ninguno - cuando el valor se pone a cero, entonces se asigna Ninguno, etc ..)

Hay muchas funciones de ayuda también - la primera propiedad que se agrega agrega 2 o más ayudantes de la clase para hacer referencia a los valores de instancia ... Son ResetAccessors (_key, ..) varargs repetida (todo se puede repetir utilizando el args primer nombre) y SetAccessors (_key, _value) con la opción de más que se añade a la clase principal para ayudar en la eficiencia - los previstos son: una forma de descriptores de acceso de grupo juntos, así que si usted tiende a restablecer unos pocos a la vez , cada vez, puede asignarlos a un grupo y restablecer el grupo en lugar de repetir los nombres de clave cada vez, y más.

El / valor almacenado en bruto ejemplo se almacena a clase. , la __CLASS. referencia a la clase de acceso cuyo sostiene Vars / valores / funciones estáticas para la propiedad. _clase. es la propiedad en sí, que es llamado cuando se accede a través de la clase ejemplo, durante el fraguado / conseguir, etc.

El descriptor de acceso _class .__ puntos a la clase, sino porque es interna tiene que ser asignado en la clase por lo que he optado por utilizar __Name = AccessorFunc (...) para asignarlo, una sola línea por propiedad con muchos argumentos opcionales para usarlos (usando varargs con llave porque son más fáciles y más eficientes para identificar y mantener) ...

También se crea una gran cantidad de funciones, como se ha mencionado, algunos de los cuales utilizan información de la función de acceso por lo que no necesita ser llamado (ya que es un poco incómodo en el momento - en este momento es necesario utilizar _class .FunctionName (_class_instance, args) -. me torno al uso de la pila / trace para agarrar la referencia de instancia para tomar el valor añadiendo elfunciones que, o bien se ejecutan este maratón poco, o mediante la adición de los descriptores de acceso al objeto y el uso de uno mismo (llamado esta señalar que son para la instancia y para mantener el acceso a la libre, la referencia de clase AccessorFunc, y otra información desde dentro de la función definiciones).

Es todavía no están hechos, pero es un fantástico punto de apoyo. Nota: Si usted no usa __Name = AccessorFunc (...) para crear las propiedades, que no tendrá acceso a la clave __ a pesar de que yo lo defino dentro de la función init. Si lo hace, entonces no hay problemas.

También: Tenga en cuenta que Nombre y Clave son diferentes ... Nombre es 'formal', que se utiliza en la creación Nombre de función, y la clave es que el almacenamiento de datos y acceso. es decir _class.x donde minúscula x es la clave, el nombre sería mayúscula X de modo que GetX () es la función en lugar de getX () que se parece un poco extraño. esto permite self.x a trabajar y cuidar adecuada, sino que también permiten GetX () y mirar apropiado.

Tengo una clase de ejemplo creado con llave / nombre idéntico, y diferente para mostrar. una gran cantidad de funciones de ayuda creados con el fin de dar salida a los datos. (Nota: No todo esto es completa) para que pueda ver lo que está pasando

La lista actual de funciones utilizando clave: x, nombre: salidas X como:

Esto es de ninguna manera una lista exhaustiva - hay unos pocos que no lo han hecho en este en el momento de la publicación ...

_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 siendo de datos de salida es:

Esto es para una nueva clase marca creada usando la clase de demostración sin ningún tipo de datos asignados, aparte del nombre (por lo que puede ser la salida) que es _foo, el nombre de la variable 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 todos _foo propiedades (excepto el nombre) los siguientes valores en el mismo orden: 'cadena', 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)                                                                                                                                                                                                   |

Tenga en cuenta que debido a tipos de datos restringidas o restricciones de valor, algunos datos no se le asignó - esto es por diseño. El colocador prohíbe malos tipos de datos o valores de ser asignado, incluso de ser asignado como valor por defecto (a menos que redefinir el comportamiento de protección de valor por defecto)

El código no se ha publicado aquí porque yo no tenía habitación después de los ejemplos y explicaciones ... También porque va a cambiar.

Nota: en el momento de este anuncio, el archivo es desordenado - esto va a cambiar. Sin embargo, si se ejecuta en Sublime Text y compila o ejecuta desde Python, se compilará y escupir un montón de información - la parte AccessorDB no se hace (que se utiliza para actualizar los captadores de impresión y ayudante GetKeyOutput funciones además de ser cambiados a una función Instancia, probablemente, poner en una sola función y renombrado - buscarlo ..)

A continuación: No todo lo que se requiere para que se ejecute - un montón de las cosas comentado en la parte inferior es para obtener más información utilizada para la depuración - puede no estar presente cuando se descarga. Si es así, usted debe ser capaz de eliminar el comentario y volver a compilar para obtener más información.

Busco un trabajo en torno a la necesidad de MyClassBase: pasar, MiClase (MyClassBase.): ... - si usted sabe de una solución - que lo ponga

La única cosa necesaria en la clase son las líneas __ - la str es para la depuración como es el init - que se puede retirar de la clase de demostración, pero se quiere necesitará comentar o eliminar algunas de las líneas de abajo (_foo / 2/3) ..

La Cuerda, Dict clases, y Util en la parte superior son una parte de mi biblioteca de Python - no son completas. Copié sobre algunas cosas que necesitaba de la biblioteca, y he creado algunos nuevos. El código completo se vinculará a la biblioteca completa y lo incluirá además de proporcionar llamadas actualizadas y eliminar el código (en realidad, el único código de la izquierda será la clase de demostración y las declaraciones de impresión - el sistema AccessorFunc se moverá a la biblioteca). ..

Parte de 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 muy fácil crear nuevas clasescon propiedades añadidas de forma dinámica con AccessorFuncs / devoluciones de llamada / de tipo de datos / aplicación de valor, etc.

Por ahora, el enlace es al (Este enlace debe reflejar cambios en el documento.): https://www.dropbox.com/s/6gzi44i7dh58v61/dynamic_properties_accessorfuncs_and_more.py?dl=0

También: Si no se utiliza Sublime Text, lo recomiendo sobre Notepad ++, Atom, código de Visual, y otros a causa de las implementaciones de roscado adecuados por lo que es mucho, mucho más rápido de usar ... También estoy trabajando en un IDE sistema de mapeo de código -como por ello - echar un vistazo a: https://bitbucket.org/ ACECOOL / acecoolcodemappingsystem / src / maestro / (Añadir Repo en Administrador de paquetes primero, y luego instalar el plugin - cuando la versión 1.0.0 está listo, voy a añadir a la lista principal complemento ...)

Espero que esta solución ayuda ... y, como siempre:

El hecho de que funciona, no significa que sea correcto - Josh 'ACECOOL' Moser

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top