2012-03-31 4 views
5

Soy nuevo en Python: lo siento si mi terminología es incorrecta. Tengo una clase que hereda el Enthought Traits attributes. Aquí es una versión simplificada:Cambiar el parámetro de propiedad desde dentro del constructor de clase [Python/Rasgos]

from enthought.traits.api import HasTraits, Range 
from enthought.traits.ui.api import View, Item 

class GUIThing(HasTraits): 

    my_slider = Range(0.0, 0.6, 0.1) 
    my_slider._high = 0.7 # works; not what I need 'coz not instance-dependent 

    view = View(Item('my_slider')) 

    def __init__(self, arg1): 
     # Call the parent's __init__ 
     HasTraits.__init__(self) 

     self.my_slider._high = arg1 # what I need; doesn't work 

# -- Main program ----- 

top_range = 0.9 

my_gui = GUIThing(top_range) 
my_gui.configure_traits() 

Esto simplemente crea una ventana con una slider en ella, originalmente iba 0,0-0,6 con valor inicial de 0,1. Al crear una instancia de GUIThing, deseo variar el valor máximo para el control deslizante según el valor actual de top_range. Sin embargo la línea

self.my_slider._high = arg1

resultados en

AttributeError: 'float' object has no attribute '_high'

Cuando dentro __init__(), self.my_slider rendimientos no objeto Slider, pero el valor actual del control deslizante.

¿Qué estoy haciendo mal? ¡Gracias!

Editar:

Lo siguiente también no funciona:

class GUIThing(HasTraits): 

    def __init__(self, arg1): 
     # Call the parent's __init__ 
     HasTraits.__init__(self) 

     self.my_slider = Range(0.0, arg1, 0.0) 

    view = View(Item('my_slider')) 

Esa sería la forma más directa de hacer lo que estoy tratando de hacer, sino que se traduce en una interfaz gráfica de usuario, donde en lugar de un control deslizante, hay un cuadro de texto que dice "objeto enthought.traits.trait_types.Range en 0xa61946c". Entonces, el problema es que cuando se crea my_slider dentro de __init__(), entonces "my_slider" viene a significar el objeto mismo (que no se muestra correctamente a través de View); pero si se crea my_slider fuera de __init__(), entonces "my_slider" viene a significar el valor actual (un flotante, que impide el acceso a las propiedades del objeto).

No estoy seguro de si esto es peculiar de los rasgos o simplemente no sé cómo inicializar los objetos correctamente.

+3

general, el guión prefijado en '' _high'' implica que es privado y no se debe estar accediéndolo así. –

+0

Derecha, gracias. Pero no puedo encontrar en los documentos cómo uno podría acceder a él en su lugar. E incluso si no es la forma correcta, funciona fuera de '__init__'. Por lo tanto, no entiendo por qué es diferente * dentro de '' __init__' (vea también editar para OP). – Pteridium

+0

Mi suposición (no estoy familiarizado con la biblioteca) es que la '' __init__() '' de la superclase utiliza el '' Rango'', pero no mantiene referencia a ella. Si eso es cierto, ¿ha intentado colocar la línea '' self.my_slider = Range (0.0, arg1, 0.0) '' before '' HasTraits .__ init __ (self) '' dentro de '' __init __() ''? –

Respuesta

0

My Gut Feeling es que no necesita modificar esa clase sino ampliar la clase Range y agregar la lógica extra que necesita para manejar su caso específico.

+0

Gracias, un problema es que no puedo encontrar cómo Range funciona internamente; en realidad, no parece ser una clase, sino una función/'definición de tipo' ... ver [aquí] (http://code.enthought.com/projects/files/ets_api/enthought.traits.traits.html)? Estoy confundido. – Pteridium

+0

nah, no hay necesidad de meterse con Range - tiene toda la funcionalidad requerida por el OP – DrSAR

0

Debe usar el método add_trait que le permitirá crear dinámicamente nuevas características de rango con los valores que necesita.

Esto se toma de la Advanced page of the traits user manual

from traits.api import HasTraits, Range 

class GUISlider (HasTraits): 

def __init__(self, eval=None, label='Value', 
      trait=None, min=0.0, max=1.0, 
      initial=None, **traits): 
    HasTraits.__init__(self, **traits) 
    if trait is None: 
     if min > max: 
      min, max = max, min 
     if initial is None: 
      initial = min 
     elif not (min <= initial <= max): 
      initial = [min, max][ 
         abs(initial - min) > 
         abs(initial - max)] 
     trait = Range(min, max, value = initial) 
    self.add_trait(label, trait) 
+0

¡Gracias! No me había dado cuenta de eso. Y sí, funciona, si se agrega 'view = View (Item ('Value'))' a la clase. Sin embargo, eso no funcionaría si quisiera crear múltiples GUISliders con diferentes etiquetas. – Pteridium

4

Finalmente encontró la respuesta en a recent mailing list message.

El siguiente código funciona. Parece que el diablo está en los detalles de cómo se llama Range(): Range(my_slider_low, my_slider_hi, 0.1) does not work.

from enthought.traits.api import HasTraits, Range 
from enthought.traits.ui.api import View, Item 

class GUIThing(HasTraits): 

    my_slider_low = 0.0 
    my_slider_hi = 1.0 

    my_slider = Range(low='my_slider_low', high='my_slider_hi', value=0.1) 

    def __init__(self, arg1): 
     self.my_slider_hi = arg1 

    view = View(Item('my_slider')) 

top_range = 0.2 

my_gui = GUIThing(top_range) 
my_gui.configure_traits() 
0

En realidad, hay un problema en la respuesta de Pteridium. Funciona pero rompe dos reglas/recomendaciones.

En primer lugar, ha sobrescrito el constructor con su propio init.Si lo hace (y si no puede evitarlo de acuerdo con las recomendaciones de codificación para Rasgos), debe llamar al constructor padre con algo como super (GUISlider, self). init (self, ** kwargs)

En segundo lugar, la inicialización recomendada para los hijos de HasTraits se realiza durante la creación de instancias en el constructor que toma los argumentos de la palabra clave. En su caso, el código podría ser como

from enthought.traits.api import HasTraits, Range 
from enthought.traits.ui.api import View, Item 

class GUIThing(HasTraits): 

    my_slider_low = 0.0 
    my_slider_hi = 1.0 

    my_slider = Range(low='my_slider_low', high='my_slider_hi', value=0.1) 

    view = View(Item('my_slider')) 


my_gui = GUIThing(my_slider_hi=0.4) 
my_gui.configure_traits() 

hay que ir, hace lo que quiere (creo), menos código y sigue los rasgos. Si alguien puede explicar por qué no deberíamos usar constructores me gustaría saber. Robert Kern probablemente pueda decirnos.

+0

Esto no funcionó para mí, el control deslizante siempre muestra el valor inicial 1.0 – kezzos

0

me recortada por un buen ejemplo de un dynamic range from Jonathan March. Esto da toda la conducta que el PO quiere AFAICT:

# Imports: 
from traits.api import HasPrivateTraits, Float, Range, Int 

from traitsui.api import View, Group, Item, Label, RangeEditor 

class DynamicRangeEditor (HasPrivateTraits): 
    """ Defines an editor for dynamic ranges (i.e. ranges whose bounds can be 
     changed at run time). 
    """ 

    # The value with the dynamic range: 
    value = Float 

    # This determines the low end of the range: 
    low = Float(0.0) 

    # This determines the high end of the range: 
    high = Float(50) 

    # Traits view definitions: 
    traits_view = View(

     # Dynamic simple slider demo: 
     Group(
      Item('value', 
        editor = RangeEditor(low_name = 'low', 
             high_name = 'high', 
             format  = '%.1f', 
             label_width = 28, 
             mode  = 'auto') 
      ), 
      '_', 
      Item('low'), 
      Item('high'), 
      '_', 
     ), 

     title  = 'Dynamic Range Editor Demonstration', 
     buttons = [ 'OK' ], 
     resizable = True 
    ) 


# Create the demo: 
demo = DynamicRangeEditor() 

# Run the demo (if invoked from the command line): 
if __name__ == '__main__': 
    demo.configure_traits() 
Cuestiones relacionadas