Как передать много переменных в и из функции в Python? - PullRequest
5 голосов
/ 27 мая 2009

Я занимаюсь научным программированием и часто хочу показать пользователям подсказки и пары переменных, позволить им редактировать переменные, а затем выполнять вычисления с новыми переменными. Я делаю это так часто, что я написал класс wxPython для перемещения этого кода из основной программы. Вы создаете список для каждой переменной с типом переменной (string, float, int), приглашением и текущим значением переменной. Затем вы помещаете все эти списки в один большой список, и моя утилита создает аккуратно отформатированную панель wxPython с подсказками и текущими значениями, которые можно редактировать.

Когда я начинал, у меня было всего несколько переменных, поэтому я выписывал каждую переменную.

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

Теперь я хочу использовать эту процедуру для многих переменных (10-30), и этот подход не работает. Я могу создать входной список для функции в несколько строк, используя операторы list.append (). Когда код возвращается из функции, я получаю этот огромный список, который нужно распаковать в нужные переменные. С этим трудно справиться, и, похоже, будет легко вывести список ввода и список вывода из синхронизации. И что еще хуже, это выглядит глупо.

Каков наилучший способ передать множество переменных в функцию в Python с дополнительной информацией, чтобы их можно было редактировать, а затем вернуть переменные, чтобы я мог использовать их в остальной части программы?

Если бы я мог передать переменные по ссылке в функцию, то пользователи могли бы изменить их или нет, и я бы использовал значения, как только программа вернулась из функции. Мне нужно будет только построить список ввода из нескольких строк, и не будет никакой возможности, чтобы список ввода не синхронизировался со списком вывода. Но Python этого не позволяет.

Стоит ли разбивать большие списки на меньшие списки, которые затем объединяются в большие списки для передачи в функции и из них? Или это просто добавляет больше мест для ошибок?

Ответы [ 6 ]

16 голосов
/ 27 мая 2009

Самое простое, что нужно сделать - создать класс. Вместо того, чтобы иметь дело со списком переменных, у класса будут атрибуты. Тогда вы просто используете один экземпляр класса.

9 голосов
/ 27 мая 2009

На ум приходят два достойных варианта.

Во-первых, используйте словарь, чтобы собрать все переменные в одном месте:

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

Второй - использовать класс для объединения всех аргументов. Это может быть что-то простое, как:

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

В этом случае я бы предпочел класс над словарем, просто потому, что вы могли бы в конечном итоге предоставить определение для класса, чтобы сделать его использование более понятным или предоставить методы, которые обрабатывают часть работы по упаковке и распаковке.

2 голосов
/ 27 мая 2009

Для меня идеальным решением является использование такого класса:

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

Вы также можете создать словарь и передать его так:

>>> 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

Затем вы можете получить данные или изменить их при необходимости, передавая их функции:

>>> def foo(some_vars):
...     some_vars.z = 3 #note that we're creating the member z
...
>>> foo(x)
>>> x.z
3
1 голос
/ 27 мая 2009

Если бы я мог передать переменные по ссылке в функцию, то пользователи могли бы изменить их или нет, и я бы использовал значения, как только программа вернулась из функции.

Вы можете получить почти такой же эффект, как и «передача по ссылке», передав dict (или для синтаксического удобства Bunch см. http://code.activestate.com/recipes/52308/).

0 голосов
/ 27 мая 2009
  1. Я бы порекомендовал использовать словарь или класс, чтобы накапливать все детали о ваших переменных
    • значение
    • подсказка
  2. Список для хранения порядка, в котором вы хотите, чтобы они отображались
  3. Затем используйте старую старую итерацию для подготовки ввода и сбора вывода

Таким образом, вы будете изменять только небольшой управляемый фрагмент кода снова и снова. Конечно, вы должны заключить все это в класс, если вам удобно работать с классами.

"""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 голосов
/ 27 мая 2009

если у вас есть конечный набор этих случаев, вы можете написать конкретные функции-оболочки для каждого из них. Каждая обертка будет выполнять работу по созданию и распаковке списков, которые передаются внутренней функции.

...