Перечисление через список функций в функции в Python динамически

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

Вот моя оригинальная проблема:

  1. С учетом строки проверьте каждую букву, чтобы проверить, не выполнено ли какое-либо из 5 тестов.
  2. Если минимум 1 письмо проходит проверку, верните True.
  3. Если все буквы в строке не пройдут проверку, верните False.
  4. Для каждой буквы в строке мы будем проверять эти функции: isalnum (), isalpha (), isdigit (), islower (), isupper ()
  5. Результат каждого теста должен печататься по разным строкам.

Пример ввода

qA2 

Образец вывода (должен печатать для отдельных строк, True, если хотя бы одна буква проходит, или false – все буквы не проходят каждый тест):

  True True True True True 

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

Код только для одного теста:

  raw = 'asdfaa3fa' counter = 0 for i in xrange(len(raw)): if raw[i].isdigit() == True: ## This line is where I'd loop in diff func's counter = 1 print True break if counter == 0: print False 

Моя неудачная попытка запустить цикл со всеми тестами:

  raw = 'asdfaa3fa' lst = [raw[i].isalnum(),raw[i].isalpha(),raw[i].isdigit(),raw[i].islower(),raw[i].isupper()] counter = 0 for f in range(0,5): for i in xrange(len(raw)): if lst[f] == True: ## loop through f, which then loops through i print lst[f] counter = 1 print True break if counter == 0: print False 

Итак, как я могу исправить этот код, чтобы выполнить все правила там?


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

  raw = 'ABC' functions = [str.isalnum, str.isalpha, str.isdigit, str.islower, str.isupper] for func in functions: print any(func(letter) for letter in raw) 

getattr (я думаю, это называется методом интроспекции?)

  raw = 'ABC' meths = ['isalnum', 'isalpha', 'isdigit', 'islower', 'isupper'] for m in meths: print any(getattr(c,m)() for c in raw) 

Подход к пониманию списка:

  from __future__ import print_function ## Changing to Python 3 to use print in list comp raw = 'ABC' functions = [str.isalnum, str.isalpha, str.isdigit, str.islower, str.isupper] solution = [print(func(raw)) for func in functions] 

То, как вы перебираете список функций, слегка отключается. Это было бы правильным способом сделать это. Функции, которые необходимо сохранить в списке, – это общие строковые функции, заданные str.funcname. Когда у вас есть список функций, вы можете пропустить их через цикл for и просто рассматривать его как обычную функцию!

 raw = 'asdfaa3fa' functions = [str.isalnum, str.isalpha, str.isdigit, str.islower, str.isupper] # list of functions for fn in functions: # iterate over list of functions, where the current function in the list is referred to as fn for ch in raw: # for each character in the string raw if fn(ch): print(True) break 

Примеры выходов:

 Input Output =================================== "qA2" -----> True True True True True "asdfaa3fa" -----> True True True True 

Также я замечаю, что вы, похоже, используете индексирование для итерации, что заставляет меня чувствовать, что вы можете исходить из такого языка, как C / C ++. Конструкция for in loop действительно мощна в python, поэтому я буду читать ее (y).

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

 raw = 'asdfaa3fa' lst = [str.isalnum, str.isalpha, str.isdigit, str.islower, str.isupper] # notice youre treating the functions just like variables and aren't actually calling them. That is, you're writing str.isalpha instead of str.isalpha() for f in range(0,5): counter = 0 for i in xrange(len(raw)): if lst[f](raw[i]) == True: # In your attempt, you were checking if lst[f]==True; lst[f] is a function so you are checking if a function == True. Instead, you need to pass an argument to lst[f](), in this case the ith character of raw, and check whether what that function evaluates to is true print lst[f] counter = 1 print True break if counter == 0: print False 

Хорошо, поэтому первый вопрос достаточно прост. Простой способ сделать это просто сделать

 def foo(raw): for c in raw: if c.isalpha(): return True if c.isdigit(): return True # the other cases return False 

Никогда не пренебрегайте простейшей вещью, которая могла бы работать.

Теперь, если вы хотите сделать это динамически – это волшебное ключевое слово, которое вам, вероятно, нужно, вы хотите применить что-то вроде этого (вырезано из другого вопроса ):

 meths = [isalnum, isalpha, isdigit, islower, isupper] for c in raw: for m in meths: getattr(c, m)() 

Предупреждение, это непроверенный код, призванный дать вам эту идею. Ключевым понятием здесь является то, что методы объекта являются атрибутами, как и все остальное, так, например, getattr("a", "isalpha")() делает следующее:

  • Использует getattr для поиска словаря атрибутов "a" для метода с именем isalpha
  • Возвращает этот метод – <function isalpha>
  • затем вызывает этот метод, используя () который является оператором приложения функции в Python.

См. Этот пример:

 In [11]: getattr('a', 'isalpha')() Out[11]: True 

Я собираюсь догадаться, что вы проверяете сложность пароля, и я также скажу, что программное обеспечение, которое принимает ввод и говорит «False», и нет никаких указаний, почему пользователь-враждебный, поэтому самое главное не «Как перебирать вложенные символы кода функции (*)», но «давать хорошую обратную связь» и предлагать нечто большее:

 raw = 'asdfaa3fa' import re def validate_password(password): """ This function takes a password string, and validates it against the complexity requirements from {wherever} and returns True if it's complex enough, otherwise False """ if not re.search('\d', password): print("Error: password needs to include at least one number") return False elif not re.search('[az]', password): print("Error: password must include at least one lowercase letter") return False elif not re.search('[AZ]', password): print("Error: password must include at least one uppercase letter") return False print("Password is OK") return True validate_password(raw) 

Попробовать онлайн на repl.it

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

(PS. Ваши функции перекрываются, строка с символами, соответствующими «isupper», «islower» и «isnumeric», уже имеет «isadigit» и «isalnum». Более интересно было бы обрабатывать символы типа ! Которые не являются верхними, нижними , цифры или alnum).


(*), как и другие ответы, как раз то, что я бы ответил, но есть так много, что уже ответил, что я могу ответить иначе: P

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

 lst = [raw[i].isalnum(),raw[i].isalpha(),raw[i].isdigit(),raw[i].islower(),raw[i].isupper()] 

Во-первых: Не уверен, какое значение, которое я в настоящее время имеет в вашем коде, отрезало, но похоже, что оно находится где-то в строке, что приводит к вычислению одиночных символов, а не всей строки.

Во-вторых: когда вы создаете свой список, вы уже вызываете методы, которые хотите вставить, что приводит к тому, что сами функции не вставлены, а их возвращаемые значения (вот почему вы видите все эти значения True в своем заявлении на печать ).

Попробуйте изменить свой код следующим образом:

 lst = [raw.isalnum, raw.isalpha, raw.isdigit, raw.islower, raw.isupper] 

Чтобы ответить на исходный вопрос:

 raw = 'asdfa3fa' functions = [str.isalnum, str.isalpha, str.isdigit, str.islower, str.isupper] isanything = [func(raw) for func in functions] print repr(isanything) 

Поскольку вы перебираете список простых элементов и пытаетесь найти, имеют ли all функции any действительные результаты, вы можете просто определить список функций, которые вы хотите вызвать на входе, и вернуть их. Вот довольно питонический пример того, чего вы пытаетесь достичь:

 def checker(checks, value): return all(any(check(r) for r in value) for check in checks) 

Проверьте это:

 >>> def checker(checks, value): ... return all(any(check(r) for r in value) for check in checks) ... >>> checks = [str.isalnum, str.isalpha, str.isdigit, str.islower, str.isupper] >>> checker(checks, 'abcdef123ABC') True >>> checker(checks, 'abcdef123') False >>> 

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

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

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