Hago programación científica y, a menudo, quiero mostrar las indicaciones de los usuarios y los pares de variables, permitirles editar las variables y luego hacer los cálculos con las nuevas variables. Hago esto tan a menudo que escribí una clase wxPython para mover este código fuera del programa principal. Configura una lista para cada variable con el tipo de variable (string, float, int), la solicitud y el valor actual de la variable. Luego, coloca todas estas listas en una gran lista, y mi utilidad crea un panel wxPython perfectamente formado con mensajes y los valores actuales que se pueden editar.

Cuando comencé, solo tenía unas pocas variables, por lo que escribiría cada variable.

s='this is a string'; i=1; f=3.14
my_list=[ ['s','your string here',s], ['i','your int here',i], ['f','your float here'],]
input_panel = Input(my_list)

 # the rest of the window is created, the input_panel is added to the window, the user is
 # allowed to make  choices, and control returns when the user hits the calculate button

s,i,f = input_panel.results()     # the .results() function returns the values in a list

Ahora quiero usar esta rutina para muchas variables (10-30), y este enfoque se está desmoronando. Puedo crear la lista de entrada a la función a través de varias líneas usando las declaraciones list.append (). Sin embargo, cuando el código regresa de la función, obtengo esta enorme lista que debe descomprimirse en las variables correctas. Esto es difícil de administrar, y parece que será fácil sincronizar la lista de entrada y la de salida. Y peor que eso, se ve torpe.

¿Cuál es la mejor manera de pasar muchas variables a una función en Python con información adicional para que se puedan editar y luego recuperar las variables para que pueda usarlas en el resto del programa?

Si pudiera pasar las variables por referencia a la función, los usuarios podrían cambiarlas o no, y usaría los valores una vez que el programa regresara de la función. Solo necesitaría construir la lista de entrada en varias líneas, y no habría ninguna posibilidad de que la lista de entrada no se sincronice con la lista de salida. Pero Python no permite esto.

¿Debo dividir las listas grandes en listas más pequeñas que luego se combinan en listas grandes para entrar y salir de las funciones? ¿O esto simplemente agrega más lugares para cometer errores?

5
Curt 27 may. 2009 a las 00:20

6 respuestas

La mejor respuesta

Lo más simple sería crear una clase. En lugar de tratar con una lista de variables, la clase tendrá atributos. Entonces solo usa una sola instancia de la clase.

16
Ned Batchelder 26 may. 2009 a las 20:25

Si pudiera pasar las variables por referencia a la función, los usuarios podrían cambiarlas o no, y usaría los valores una vez que el programa regresara de la función.

Puede obtener el mismo efecto que "pasar por referencia" pasando un dict (o por conveniencia sintáctica un Bunch, vea http://code.activestate.com/recipes/52308/).

1
Alex Martelli 26 may. 2009 a las 20:27

Si tiene un conjunto finito de estos casos, puede escribir funciones de contenedor específicas para cada uno. Cada contenedor haría el trabajo de construir y desempacar listas que se pasan a la función interna.

0
sean riley 26 may. 2009 a las 20:26

Para mí, la solución ideal es usar una clase como esta:

>>> class Vars(object):
...     def __init__(self, **argd):
...             self.__dict__.update(argd)
...
>>> x = Vars(x=1, y=2)
>>> x.x
1
>>> x.y
2

También puedes construir un diccionario y pasarlo así:

>>> some_dict = {'x' : 1, 'y' : 2}
>>> #the two stars below mean to pass the dict as keyword arguments
>>> x = Vars(**some_dict)  
>>> x.x
1
>>> x.y
2

Luego puede obtener datos o alterarlos según sea necesario al pasarlos a una función:

>>> def foo(some_vars):
...     some_vars.z = 3 #note that we're creating the member z
...
>>> foo(x)
>>> x.z
3
2
Jason Baker 26 may. 2009 a las 20:29
  1. Recomendaría usar un diccionario o una clase para acumular todos los detalles sobre sus variables
    • valor
    • texto de aviso
  2. Una lista para almacenar el orden en el que desea que se muestren
  3. Luego use una buena iteración antigua para preparar la entrada y recopilar la salida

De esta manera solo modificará una pequeña sección manejable del código una y otra vez. Por supuesto, debe encapsular todo esto en una clase si se siente cómodo trabajando con las clases.

"""Store all variables
"""
vars = {}
"""Store the order of display
"""
order = []

"""Define a function that will store details and order of the variable definitions
"""
def makeVar(parent, order, name, value, prompt):
    parent[name] = dict(zip(('value', 'prompt'), (value, prompt)))
    order.append(name)

"""Create your variable definitions in order
"""
makeVar(vars, order, 's', 'this is a string', 'your string here')
makeVar(vars, order, 'i', 1, 'your int here')
makeVar(vars, order, 'f', 3.14, 'your float here')

"""Use a list comprehension to prepare your input
"""
my_list = [[name, vars[name]['prompt'], vars[name]['value']] for name in order]
input_panel = Input(my_list)

out_list = input_panel.results();
"""Collect your output
"""
for i in range(0, len(order)):
    vars[order[i]]['value'] = out_list[i];
0
user112831 27 may. 2009 a las 01:18

Hay dos opciones decentes que vienen a la mente.

El primero es usar un diccionario para reunir todas las variables en un solo lugar:

d = {}
d['var1'] = [1,2,3]
d['var2'] = 'asdf'
foo(d)

El segundo es usar una clase para agrupar todos los argumentos. Esto podría ser algo tan simple como:

class Foo(object):
    pass
f = Foo()
f.var1 = [1,2,3]
f.var2 = 'asdf'
foo(f)

En este caso, preferiría la clase sobre el diccionario, simplemente porque eventualmente podría proporcionar una definición para que la clase aclare su uso o para proporcionar métodos que manejen parte del trabajo de empaque y desempaque.

9
Doug 26 may. 2009 a las 20:29