Использование password_hash
- рекомендуемый способ хранения паролей. Не разделяйте их на БД и файлы.
Допустим, у нас есть следующий ввод:
$password = $_POST['password'];
Я не проверяю ввод только ради понимания концепции .
Сначала вы вводите пароль:
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
Затем см. вывод:
var_dump($hashed_password);
Как вы видите, это хешировано. (Я предполагаю, что вы сделали эти шаги).
Теперь вы храните этот hashed_password в своей базе данных, а затем скажем, когда пользователь просит их войти в систему. Вы проверяете ввод пароля с этим значением хэша в базе данных , сделав это:
// Query the database for username and password
// ...
if(password_verify($password, $hashed_password)) {
// If the password inputs matched the hashed password in the database
// Do something, you know... log them in.
}
// Else, Redirect them back to the login page.
Циклы for должны быть такими же, как если бы вы записали их «нормальным» способом:
for row in table:
for cell in row:
print(cell)
Поэтому, когда вы включаете это в понимание списка, вы оставляете циклы как есть ( за исключением удаления ":") и просто вытянуть окончательное выражение в начало:
# you can actually "abuse" list comprehensions to have short
# loops like this, even if you don't care about the list being
# generated. It's generally not a great practice though
[print(cell) for row in table for cell in row]
Я признаю, что это немного сбивает с толку, когда вы просто читаете код слева направо. Вы просто должны помнить, чтобы сначала прочитать циклы, а затем оператор начала идет в конце. Я полагаю, что это могло быть реализовано как
[for row in table for cell in row cell]
, но я думаю, что это выглядит еще более запутанным; Труднее сказать, где заканчивается второй цикл и начинается оператор внутри него. В конце концов, это дизайнерское решение, хотя я уверен, что некоторые люди сочтут тот или иной подход более интуитивным.
Синтаксические правила для таких выражений в python называются «дисплеями». Вы можете найти определение здесь .
comprehension ::= expression comp_for
comp_for ::= ["async"] "for" target_list "in" or_test [comp_iter]
comp_iter ::= comp_for | comp_if
comp_if ::= "if" expression_nocond [comp_iter]
элементы нового контейнера - это те элементы, которые будут получены при рассмотрении каждого из предложений for или if в блоке, вложенности слева направо и оценке выражения для производить элемент каждый раз, когда достигается самый внутренний блок.
Повторяемое выражение в крайнем левом предложении for вычисляется непосредственно во включающей области, а затем передается в качестве аргумента для имплицитно вложенной области. Последующие для предложений и любое условие фильтра в крайнем левом для предложения не могут быть оценены во включающей области видимости, поскольку они могут зависеть от значений, полученных из крайнего левого итерируемого.
blockquote>Возьмем ваш пример:
[cell for row in table for cell in row]
Интерпретатор разобьет его следующим образом:
expression = "cell" comp_for1 = "for row in table" + comp_for2 comp_for2 = "for cell in row"
Затем интерпретатор восстановит вложенный цикл в иерархии
. ]comp_for1: comp_for2: expression
Я согласен, что ваша первая попытка в целом более интуитивна, так как она более близко имитирует то, как я и, вероятно, большинство людей думаем о переборе вещей от более специфического к менее конкретному.
Понятие вложенного списка Python адаптировано из вложенного цикла for
:
for row in table:
for cell in row:
cell
Объединить строки:
for row in table: for cell in row: cell
Обернуть его в скобки списка, удалить :
и переместите повторяющееся выражение вперед:
[cell for row in table for cell in row]
Вы можете подумать, что понимание - это внутренняя версия цикла for. По крайней мере, я сделал сначала. Но самый простой способ понять это - заметить, что вы вызовете переменную до ее определения в первой попытке. row
вызывается до его определения. Логично, что вы получите ошибку.
[cell for cell in row ...]
row
не определено
[cell for row in table for cell in row]
Здесь нет проблем