web-dev-qa-db-fra.com

Boucle dans la liste des fonctions d'une fonction en Python dynamiquement

J'aimerais voir s'il est possible de parcourir une liste de fonctions dans une fonction. La chose la plus proche que je puisse trouver est de parcourir tout un module. Je veux seulement utiliser une liste de fonctions présélectionnée.

Voici mon problème d'origine:

  1. Étant donné une chaîne, vérifiez chaque lettre pour voir si l'un des 5 tests remplit.
  2. Si au moins 1 lettre réussit un chèque, retournez True.
  3. Si toutes les lettres de la chaîne échouent à la vérification, renvoyez False.
  4. Pour chaque lettre de la chaîne, nous allons vérifier les fonctions suivantes: isalnum (), isalpha (), isdigit (), islower (), isupper ()
  5. Le résultat de chaque test doit être imprimé sur différentes lignes. 

Exemple de saisie

    qA2

Exemple de sortie (doit être imprimé sur des lignes séparées, True si au moins une lettre est réussie ou false si toutes les lettres échouent à chaque test):

    True
    True
    True
    True
    True

J'ai écrit ceci pour un test. Bien sûr, je pourrais simplement écrire 5 ensembles de code différents, mais cela semble moche. Ensuite, j'ai commencé à me demander si je pouvais simplement passer en revue tous les tests demandés. 

Code pour un seul test:

    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

Ma tentative d’échec pour exécuter une boucle avec tous les tests:

    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

Alors, comment puis-je corriger ce code pour respecter toutes les règles là-haut?


Utilisation des informations de tous les commentaires - ce code respecte les règles énoncées ci-dessus, en passant en revue chaque méthode de manière dynamique.

    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)

Approche getattr (je pense qu’on appelle cela une méthode d’introspection?)

    raw = 'ABC'

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

Approche de compréhension de liste:

    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]
8
jhub1

La façon dont vous parcourez une liste de fonctions est légèrement différente. Ce serait un moyen valable de le faire. Les fonctions que vous devez stocker dans la liste sont les fonctions de chaîne génériques données par str.funcname. Une fois que vous avez cette liste de fonctions, vous pouvez les parcourir en utilisant une boucle for, et la traiter comme une fonction normale!

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

Exemples de sortie:

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

De plus, je remarque que vous semblez utiliser l'indexation pour l'itération, ce qui me donne l'impression que vous venez peut-être d'un langage comme le C/C++. La construction de la boucle in est vraiment puissante en python, je la lirais donc (y).

Ci-dessus est une manière plus pythonique de le faire, mais juste comme outil d’apprentissage, j’ai écrit une version de travail qui correspond à la façon dont vous avez essayé de le faire autant que possible pour vous montrer précisément où vous vous êtes trompé. La voici avec des commentaires:

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

D'accord, la première question est assez simple. La façon simple de le faire est juste faire

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

Ne négligez jamais la chose la plus simple qui puisse fonctionner.

Maintenant, si vous voulez le faire dynamiquement - qui est le mot clé magique dont vous avez probablement besoin, vous voulez appliquer quelque chose comme ceci (cribbed à partir de une autre question ):

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

Attention, ce code non testé a pour but de vous donner une idée. La notion clé ici est que les méthodes d'un objet sont des attributs comme toute autre chose, ainsi, par exemple, getattr("a", "isalpha")() fait ce qui suit:

  • Utilise getattr pour rechercher dans le dictionnaire d'attributs de "a" une méthode nommée isalpha
  • Renvoie cette méthode elle-même - <function isalpha>
  • appelle ensuite cette méthode à l'aide de () qui est l'opérateur d'application de la fonction en Python.

Voir cet exemple:

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

Pour répondre à la question initiale:

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

Toutes les autres réponses sont correctes, mais comme vous êtes débutant, je tiens à signaler le problème dans votre code:

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

Premièrement: vous ne savez pas quelle valeur i a actuellement été coupée dans votre code, mais elle semble pointer quelque part dans la chaîne, ce qui entraîne l'évaluation de caractères uniques et non de la chaîne entière raw .

Deuxièmement: lorsque vous construisez votre liste, vous appelez déjà les méthodes que vous souhaitez insérer, ce qui a pour effet que ce ne sont pas les fonctions elles-mêmes qui sont insérées, mais leurs valeurs de retour (c'est pourquoi vous voyez toutes ces True valeurs dans votre relevé d'impression).

Essayez de changer votre code comme suit:

lst = [raw.isalnum, raw.isalpha, raw.isdigit, raw.islower, raw.isupper]
2
andreas-hofmann

Je vais deviner que vous validez la complexité du mot de passe, et je vais aussi dire que le logiciel prend une entrée et dit "Faux" et qu'il n'y a aucune indication pourquoi est hostile à l'utilisateur, donc La chose la plus importante n’est pas de savoir "faire une boucle sur la magie du code de la fonction char imbriquée (*)" mais de "donner un bon retour", et de suggérer quelque chose de plus semblable à:

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('[a-z]', password):
        print("Error: password must include at least one lowercase letter")
        return False

    Elif not re.search('[A-Z]', password):
        print("Error: password must include at least one uppercase letter")
        return False

    print("Password is OK")
    return True

validate_password(raw)

Essayez en ligne sur repl.it

Et la recherche regex vérifie les plages de caractères et de chiffres dans un appel, ce qui est plus pratique qu'une boucle sur des caractères.

(PS. Vos fonctions se chevauchent; une chaîne dont les caractères correspondent à "isupper", "islower" et "isnumeric" est déjà couverte par "isadigit" et "isalnum". Plus intéressant serait de traiter des caractères comme ! qui ne sont pas supérieur, inférieur , chiffres ou alnum).


(*) la magie des fonctions comme les autres réponses correspond normalement à ce que je répondrais, mais il y a tellement de réponses que j'ai déjà répondu que je pourrais aussi bien répondre à l'inverse: P

2
TessellatingHeckler

Puisque vous parcourez une liste d’items simples et que vous essayez de trouver si all des fonctions a any résultats valides, vous pouvez simplement définir la liste des fonctions que vous souhaitez appeler et le renvoyer. . Voici un exemple plutôt pythonique de ce que vous essayez d’atteindre:

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

Testez-le:

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

Vous pouvez utiliser introspection pour parcourir en boucle tous les attributs d’un objet, qu’il s’agisse de fonctions ou d’un autre type.

Cependant, vous ne voulez probablement pas faire cela ici, parce que str a lots d'attributs de fonction et que cinq d'entre eux ne vous intéressent. Il vaut probablement mieux faire ce que vous avez fait et dressez une liste des cinq que vous voulez.

En outre, vous n'avez pas besoin de passer en boucle sur chaque caractère de la chaîne si vous ne le souhaitez pas; ces fonctions regardent déjà toute la chaîne.

1
John Gordon

Découvrez cette solution en une ligne pour votre problème. Ce problème vient de HackerRank. Je parcours une liste de fonctions à l’aide de la fonction getattr intégrée.

s='qA2'
[print(bool(list(filter(lambda x : getattr(x, func)(),s)))) for func in ['isalnum','isalpha','isdigit','islower','isupper']]
0
Rajesh Samui