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.
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 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.
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.
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