Maîtriser le module lowref en Python

Le module lowref est un module pratique et très puissant. Peut-être qu'aucun autre module n'a été traité aussi mal que ce module en termes d'équilibre entre l'aspect pratique et la reconnaissance du nom. Dans cet article, je vais vous montrer à quel point le module lowref est utile.

problème

Supposons que vous ayez un grand nombre d'objets avec des informations d'identité (ou des informations hachables uniques). Un dictionnaire pour la gestion des objets est préparé afin qu'un grand nombre d'objets puisse être recherché en utilisant l'ID comme clé.

class Member:
    def __init__(self, id, name):
        self.id = id
        self.name = name

#Gérez les objets avec un dictionnaire basé sur l'ID
members_dict = {
    x.id: x for x in [
        Member(1, "tim"),
        Member(2, "matthew"),
        Member(3, "Jack"),
        # ...
    ]
}

members_dict[1].name
>>> 'tim'

Ici, il y avait une demande de recherche non seulement par «id» mais aussi par «nom», donc créons un dictionnaire en utilisant le nom comme clé. (Ici, par souci de simplicité, nom est également une information unique sans duplication.)

#Créer un dictionnaire en utilisant le nom comme clé
names_dict = {x.name: x for x in members_dict.values()}

names_dict["tim"].id
>>> 1

Depuis que le membre tim s'est retiré ici, les données ont été supprimées.

# ID:Supprimer les données de temps qui sont 1
del members_dict[1]

Il est souhaitable que les données d'objet de tim soient collectées par GC (garbage collection) et que la mémoire soit libérée. Mais la réalité ne l'est pas.

L'objet est référencé par le names_dict ajouté dans le sens d'une table de recherche, et l'objet tim n'est pas collecté par le GC et continue d'exister dans la mémoire.

# names_GC fuit sans relâcher car il reste des références dans le dict!
names_dict['tim']
>>> <__main__.Member at 0x1744e889ba8>

Si vous répétez la création et la suppression des membres, la mémoire ne sera pas libérée et s'accumulera, vous devez donc continuer à gérer names_dict ainsi que members_dict en même temps. À mesure que les types de tables de recherche augmentent, le nombre de dictionnaires gérés en même temps augmente, ce qui est un tourbillon.

Si vous avez une structure de données simple comme cet exemple, vous pouvez faire quelque chose avec une conception orientée objet. Lorsqu'il s'agit d'une structure de données compliquée dans laquelle les objets se réfèrent les uns aux autres, un compteur de référence est nécessaire pour déterminer si l'objet est vivant ou mort, et le code philosophique d'implémentation d'une chose de type GC sur le langage dans lequel le GC est répertorié. Est terminé.

Le module lowref qui y apparaît fringant!

Le module lowref peut vous aider dans cette situation, remplacez simplement names_dict par lowref.WeakValuDictionary et il résoudra le problème.

from weakref import WeakValueDictionary

names_dict = WeakValueDictionary(
    {_.name: _ for _ in members_dict.values()}
)

names_dict['tim'].id
>>> 1

# ID:Supprimer les données de temps qui sont 1
del members_dict[1]

names_dict['tim']
>>> KeyError: 'tim'

WeakValuDictionary est un objet de type dictionnaire dont la valeur est une référence faible. Les références faibles sont des références qui n'interfèrent pas avec la récupération de GC et sont automatiquement supprimées du dictionnaire lorsqu'il n'y a pas de références fortes autres que WeakValuDictionary.

Il existe de nombreuses situations dans lesquelles vous souhaitez accéder à un grand nombre d'objets à l'aide d'un cache / table de recherche rapide pour améliorer les performances. Dans de tels moments, le «dictionnaire des valeurs faibles» peut être considéré comme un élément essentiel.

Bien sûr, il existe également un dictionnaire de clé faible

S'il y a un WeakValuDictionary, bien sûr il y a aussi unWeakKeyDictionary dont la clé est une référence faible.

Le WeakKeyDictionary peut également être utilisé pour contenir des références et référencé.

from weakref import WeakKeyDictionary


class Member:
    def __init__(self, name, friend=None):
        self.name = name
        self._friend_dict = WeakKeyDictionary()
        self._referenced_dict = WeakKeyDictionary()
        if friend:
            self._friend_dict[friend] = None
            friend._referenced_dict[self] = None

    def referenced(self):
        referenced = list(self._referenced_dict.keys())
        return referenced[0] if referenced else None

    def friend(self):
        friends = list(self._friend_dict.keys())
        return friends[0] if friends else None

    def __str__(self):
        friend = self.friend()
        refer = self.referenced()
        return "{}: referenced={} friend={}".format(
            self.name,
            refer.name if refer else None,
            friend.name if friend else None
        )


tim = Member("tim")
matthew = Member("matthew", friend=tim)
jack = Member("jack", friend=matthew)

print(tim)
print(matthew)
print(jack)
# output:
#
# tim: referenced='matthew' friend='None'
# matthew: referenced='jack' friend='tim'
# jack: referenced='None' friend='matthew'

del matthew

print(tim)
print(jack)
# output:
#
# tim: referenced='None' friend='None'
# jack: referenced='None' friend='None'

Je l'ai utilisé comme dictionnaire qui met à jour automatiquement les références et références d'autres objets. Vous pouvez voir que le dictionnaire est mis à jour automatiquement en supprimant l'objet.

référence

Épilogue

Le module lowref est assez simple pour ne nécessiter que deux objets de dictionnaire, le WeakValuDictionary et le WeakKeyDictionary, mais c'est un module très puissant. Selon l'appareil, il y aura probablement de nombreuses autres utilisations.

C'est un module très discret, donc je pense que c'est très utile pour les gens qui ne le savent pas. Si vous trouvez une autre utilisation efficace, veuillez l'écrire dans l'article.

Recommended Posts

Maîtriser le module lowref en Python
Installez le module Python dans n'importe quel répertoire
Trouver des erreurs en Python
À propos du module Python venv
[python] Récupère la liste des classes définies dans le module
Obtenir l'API arXiv en Python
[Python] journalisation dans votre propre module
Python dans le navigateur: la recommandation de Brython
Frappez l'API Sesami en Python
Obtenez le chemin du bureau en Python
Mettez le module dans l'application Pepper
Obtenez le chemin du script en Python
Dans la commande python, python pointe vers python3.8
Implémenter le modèle Singleton en Python
Maîtrisez le type avec Python? (Quand faire la vérification de type)
Accédez à l'API Web en Python
Exécuter le module Python unittest dans vs2017
J'ai écrit la file d'attente en Python
Calculer le mois précédent en Python
Examiner la classe d'un objet avec python
Obtenez le chemin du bureau en Python
Essayez d'utiliser le module Python Cmd
Obtenez le nom d'hôte en Python
Accéder à l'API Twitter avec Python
La première étape de Python Matplotlib
J'ai écrit la pile en Python
Apprenez le modèle de conception "Prototype" avec Python
Charger le SDK Python distant avec IntelliJ
Essayez d'utiliser l'API Wunderlist en Python
[Blender x Python] Maîtrisons le matériel !!
Apprenez le modèle de conception "Flyweight" en Python
Essayez d'utiliser l'API Kraken avec Python
Apprenez le modèle de conception "Memento" avec Python
Apprenez le modèle de conception "Proxy" en Python
Ecrire le test dans la docstring python
Passez le chemin du module python importé
Module d'implémentation de file d'attente et Python "deque"
Apprenez le modèle de conception "Commande" en Python
Comparaison des modules de conversion japonais en Python3
Prenez la somme logique de List en Python (fonction zip)
Afficher Python 3 dans le navigateur avec MAMP
Tweet à l'aide de l'API Twitter en Python
Apprenez le modèle de conception "Visiteur" avec Python
Vérifiez si l'URL existe en Python
Apprenez le modèle de conception "Mediator" avec Python
Associez l'ensemble de tables dans les modèles de python.py
Apprenez le modèle de conception "Décorateur" avec Python
Exécuter l'interpréteur Python dans le script
Le résultat de l'installation de python sur Anaconda
Qu'est-ce que "mahjong" dans la bibliothèque Python? ??
Lisez le fichier ligne par ligne avec Python
Lisez le fichier ligne par ligne avec Python
[Python] Importez le module d'un niveau supérieur
Vérifiez le chemin du module importé Python
Module pour générer le mot N-gramme en Python
MongoDB avec Python pour la première fois
Apprenez le modèle de conception "Iterator" avec Python
Principes de base pour exécuter NoxPlayer en Python
Apprenez le modèle de conception «Stratégie» avec Python