Note Python efficace Item 15 Savoir comment les fermetures sont liées à la portée de la fonction

Il s'agit d'un mémo écrit du livre efficace python d'O'Reilly Japon. https://www.oreilly.co.jp/books/9784873117560/ P31~35

En connaissant la portée de la fermeture, vous pourrez écrire du beau code.

** Exemple de tri ** Triez les nombres dans l'ordre, mais supposons que vous ayez un nombre que vous souhaitez prioriser

def sort_priority(values, group):
    def helper(x):
        if x in group:
            return (0, x)
        return (1, x)
    values.sort(key=helper)

numbers = [8, 3, 1, 2, 5, 4, 7, 6]
group = {2, 3, 5, 7}
sort_priority(numbers, group)
print(numbers)

>>>
[2, 3, 5, 7, 1, 4, 6, 8]

Si vous ne connaissez pas le concept de fermeture, il est difficile d'imaginer comment cela fonctionne. Il y a trois points ici

  1. Le mécanisme de fermeture permet à la fonction d'assistance d'accéder au groupe qui est l'argument de la fonction sort_priority.
  2. La fonction python étant un objet de première classe, la fonction d'assistance peut être affectée comme argument clé de la méthode de tri.
  3. L'ordre de priorité est séparé en séparant le premier indice en 0 et 1 par le taple qui est la valeur de retour de la fonction d'assistance.

** Incorporer la détermination de son inclusion ou non dans la liste des priorités ** Sur la base du code ci-dessus, je souhaite implémenter une implémentation qui renvoie True lorsqu'elle est incluse dans la liste des priorités.

def sort_priority2(numbers, group):
    found = False
    def helper(x):
        if x in group:
            found = True #Cela devrait être vrai ici. .. ..
            return(0, x)
        return(1, x)
    numbers.sort(key=helper)
    return found

found = sort_priority2(numbers, group)
print('Found', found)
print(numbers)

>>>

Found False
[2, 3, 5, 7, 1, 4, 6, 8]

À l'origine, Found devrait être True dans le calcul, mais pour une raison quelconque, il renvoie False. La raison en est la ** portée ** de la fermeture.

Si vous ne comprenez pas la portée, vous souffrirez d'un comportement mystérieux

Le code ci-dessus ne renvoie pas False car la portée de Found reste en dehors de la fonction d'assistance. En d'autres termes

def sort_priority2(numbers, group):
    found = False        #Parce que found existe dans la portée ici. ..
    def helper(x):
        if x in group:
            found = True #N'allez pas à la portée ici
            return(0, x)
        return(1, x)
    numbers.sort(key=helper)
    return found

Par conséquent, False qui est une portée supérieure est renvoyé. Pour éviter cela, python3 fournit une fonction ** non locale **. nonlocal pousse la portée hors de la fermeture


def sort_priority3(numbers, group):
    found = False
    def helper(x):
        nonlocal found #Ici, la portée de found est hors de la fonction d'assistance
        if x in group:
            found =True
            return(0, x)
        return(1, x)
    numbers.sort(key=helper)
    return found

found = sort_priority3(numbers, group)
print('Found', found)
print(numbers)

>>>

Found True
[2, 3, 5, 7, 1, 4, 6, 8]

C'est le mouvement prévu.

Cependant, si vous utilisez non local dans une fonction à grande échelle, cela affectera la plage des pièces non souhaitées, alors soyez prudent. Si vous voulez être sûr, il vaut mieux l'envelopper dans une classe similaire au lieu de la fonction non locale.

class Sorter(object):
    def __init__(self, group):
        self.group = group
        self.found = False
        
    def __call__(self, x):
        if x in self.group:
            self.found = True
            return(0, x)
        return(1, x)

sorter = Sorter(group)
numbers.sort(key=sorter)
assert sorter.found is True

>>>
(Aucune exception en raison de l'affirmation)

Celui-ci peut être utilisé sans se soucier de la portée.

À propos, non local n'est pas pris en charge dans python2.

Conclusion

  1. Connaître la portée de la fermeture vous permet d'écrire un code concis
  2. Un comportement involontaire se produit si vous ne comprenez pas la plage de portée
  3. python3 peut être étendu en dehors de la fermeture en utilisant non local (mais il est préférable de le limiter uniquement aux fonctions simples)

Recommended Posts

Note Python efficace Item 15 Savoir comment les fermetures sont liées à la portée de la fonction
Comment utiliser la fonction zip de python
[Python] Comment utiliser la fonction de hachage et taple.
EP 15 Savoir comment les fermetures interagissent avec une portée variable
Comment installer Python
[Introduction à Python] Comment itérer avec la fonction range?
Comment connaître le répertoire actuel en Python dans Blender
Comment installer python
Remarque pour faire de python un démon
Exécuter la fonction Python à partir de Powershell (comment passer des arguments)
Élément de mémo Python efficace 3
[Python] Comment appeler une fonction de c depuis python (édition ctypes)
Comment transloquer un tableau à deux dimensions en utilisant uniquement python [Note]
Élément de mémo Python efficace 19 Donner un comportement facultatif aux arguments de mot-clé
Comment échantillonner à partir de n'importe quelle fonction de densité de probabilité en Python
Je ne savais pas comment utiliser l'instruction [python] for
Élément de note Python efficace 16 Envisagez de renvoyer un générateur sans renvoyer une liste
[Introduction à Python] Comment obtenir des données avec la fonction listdir
[2020.8 dernière] Comment installer Python
Comment installer Python [Windows]
python3: Comment utiliser la bouteille (2)
[Python] Comment utiliser la liste 1
Comment appeler une fonction
Comment mettre à jour Tkinter de Python vers la version 8.6
Comment utiliser Python Argparse
[Note] Comment utiliser virtualenv
Python: comment utiliser pydub
[Python] Comment utiliser checkio
Comment exécuter Notepad ++ Python
Comment changer la version de Python
Comment développer en Python
[python] Comment juger scalaire
[Python] Comment utiliser input ()
Comment utiliser Python lambda
[Python] Comment utiliser virtualenv
python3: Comment utiliser la bouteille (3)
python3: Comment utiliser la bouteille
Comment utiliser les octets Python
Élément de mémo Python efficace 11 Utilisez zip pour traiter les itérateurs en parallèle
Comment connaître la structure interne d'un objet en Python
[Introduction à Python] Comment fractionner une chaîne de caractères avec la fonction split
[Python 3.8 ~] Comment définir intelligemment des fonctions récursives avec des expressions lambda
Point 17 de la note Python efficace Respect de la certitude lors de l'utilisation d'itérateurs pour les arguments
Grammaire de base du système Python3 (comment utiliser les fonctions, la fermeture, la fonction lambda)
[Python] Explique comment utiliser la fonction format avec un exemple
Comment installer Python à l'aide d'Anaconda
[Python] Comment FFT des données mp3
[Python] Comment faire PCA avec Python
Python: comment utiliser async avec
Comment utiliser la fonction zip
EP5 Savoir comment découper des séquences
[Python] Comment dériver nCk (ABC156-D)
[Python] Comment utiliser la série Pandas
Comment collecter des images en Python
Comment utiliser les requêtes (bibliothèque Python)
Comment utiliser SQLite en Python
[Introduction à Python] Comment analyser JSON
Comment obtenir la version Python
Comment créer une fonction récursive
Comment démarrer avec Python