Оператор запятой объединяет два выражения с обеих сторон в один, оценивая их как в порядке слева направо. Значение правой части возвращается как значение всего выражения. (expr1, expr2)
походит на { expr1; expr2; }
, но вы можете использовать результат expr2
в вызове функции или присваивании.
Часто в циклах for
можно инициализировать или поддерживать несколько переменных:
for (low = 0, high = MAXSIZE; low < high; low = newlow, high = newhigh)
{
/* do something with low and high and put new values
in newlow and newhigh */
}
Кроме этого, я использовал его только «в гневе» в одном другом случае, когда вы завершаете две операции, которые всегда должны совпадать в макросе. У нас был код, который копировал различные двоичные значения в байтовый буфер для отправки по сети, и указатель поддерживался там, где мы вставали:
unsigned char outbuff[BUFFSIZE];
unsigned char *ptr = outbuff;
*ptr++ = first_byte_value;
*ptr++ = second_byte_value;
send_buff(outbuff, (int)(ptr - outbuff));
Где значения были short
s или int
s мы сделали это:
*((short *)ptr)++ = short_value;
*((int *)ptr)++ = int_value;
Позже мы читаем, что это не было действительно действительным C, потому что (short *)ptr
больше не является l-значением и не может быть увеличено, хотя наш компилятор на время не против. Чтобы исправить это, мы разделили это выражение на два:
*(short *)ptr = short_value;
ptr += sizeof(short);
. Однако этот подход основывался на том, что все разработчики помнят, что оба оператора все время заставляют. Нам нужна функция, в которой вы могли бы передать указатель на выход, значение и тип значения. Это C, а не C ++ с шаблонами, мы не могли бы иметь функцию произвольного типа, поэтому мы остановились на макросе:
#define ASSIGN_INCR(p, val, type) ((*((type) *)(p) = (val)), (p) += sizeof(type))
Используя оператор запятой, мы смогли использовать это в выражения или как заявления, которые мы хотели:
if (need_to_output_short)
ASSIGN_INCR(ptr, short_value, short);
latest_pos = ASSIGN_INCR(ptr, int_value, int);
send_buff(outbuff, (int)(ASSIGN_INCR(ptr, last_value, int) - outbuff));
Я не предлагаю, чтобы какой-либо из этих примеров был хорошим стилем! Действительно, я, кажется, помню, что Code Complete Стив МакКоннелл предупреждал даже использовать запятые в цикле for
: для удобочитаемости и ремонтопригодности цикл должен управляться только одной переменной, а выражения в for
сама строка должна содержать только код управления контуром, а не другие дополнительные биты инициализации или обслуживания цикла.
Я лично предложил бы использовать объект сеанса для передачи данных из одной формы в другую. Если у вас есть небольшой объем данных, вы можете уйти, просто используя реализацию куки-файлов, которые есть в колбе. В противном случае, вы можете переопределить объект сеансов по умолчанию для хранения сеансов сервера данных с помощью Redis. Это позволяет использовать объекты сеанса, не платя цену хранения большого количества данных в файлах cookie. Это означает, что вы можете сделать что-то вроде
@app.route('/form/step1', methods=['GET', 'POST'])
def form_step1():
form1 = form_step_1(request.POST)
user_id = current_user.user_id # If you're using flask-login
...validate()...
# dictionary that holds form1, form2, etch
form_data = {"form1": form1, "form2": None, "Form3"=None}
flask.session[user_id] = form_data
redirct_to(url_for("form_step2"))
return render_template('register.html', {'form':form1})
@app.route('/form/step2', methods=['GET', 'POST'])
def form_step2():
form1 = session[user_id][form1]
# A simpler way than passing the whole form is just the data
# you want but for this answer I'm just specifying the whole form.
form = form_step_2(form1)
user_id = current_user.user_id # If you're using flask-login
...validate()...
# dictionary that holds form1, form2, etch
flask.session[user_id]["form2"] = form2
redirct_to(url_for("form_step3"))
return render_template('register.html', form=form)
Если у вас нет причин беспокоиться об удержании POST ваших данных формы, вы можете использовать скрытые поля форм во втором и третьем представлениях для передачи данных. Подумайте об этих строках ...
forms.py
# override EACH form's init to change the widget for each field to a hidden widget if is_hidden kwarg passed.
class form_step_1(forms.Form):
def __init__(self, *args, **kwargs):
is_hidden = kwargs.pop('is_hidden', None)
super(FormName, self).__init__(*args, **kwargs)
if is_hidden:
for field in self.fields:
self.fields[field].widget = forms.HiddenInput()
# Be sure to do this for each form with hidden input needed
views.py
@app.route('/form/step1', methods=['GET', 'POST'])
def form_step1():
form1 = form_step_1(request.POST)
...validate()...
return render_template('register.html', {'form':form1})
@app.route('/form/step2', methods=['GET', 'POST'])
def form_step2():
form1 = form_step_1(request.POST, is_hidden=True)
hidden_forms =[form1]
form2 = form_step_2(request.POST)
...validate()...
return render_template('register.html', {'form':form2, 'hidden_forms':hidden_forms})
@app.route('/form/step3', methods=['GET', 'POST'])
def form_step3():
form1 = form_step_1(request.POST, is_hidden=True)
form2 = form_step_2(request.POST, is_hidden=True)
hidden_forms =[form1, form2]
form = form_step_3(request.form)
...validate()...
if form.is_valid():
# do stuff, save to DB
form1.save()
form2.save()
form3.save()
return HttpReturnRedirect('/success_page/') # Always Redirect after posting form
# if not valid, show again.
return render_template('register.html', {'form':form, 'hidden_forms':hidden_forms })
template.html (assuming you are using a single template for each page
<form action="." etc>
{% csrf_token %}
{{ form }}
{% for each_form in hidden_forms %}
{{ each_form }}
<!-- your submit button -->
</form>
Теперь, когда ваша форма переходит к POST на шаге 3, если она действительна, доступны данные каждой формы из предыдущих шагов.
Если вы хотите найти безрассудное решение (требуется немного больше работы), посмотрите на Django FormWizard