Avec Python 2.7, un outil appelé les “views” (les “vues”) est apparu. Une vue est juste un enrobage qui permet de voir un objet d’une certaine façon, et de le manipuler d’une certaine façon (avec une autre API), sans changer cet objet.
Les vues ont surtout été notables pour leur apparition dans les dictionnaires avec Python 2.7:
>>> scores = {"sam": 1, "max": 0} >>> scores.items() # retourne une lsite [('max', 0), ('sam', 1)] >>> scores.iteritems() # retourne un générateur <dictionary-itemiterator object at 0x7f8782a26628> >>> list(scores.iteritems()) # sans views [('max', 0), ('sam', 1)] >>> scores.viewsitems() # avec views Traceback (most recent call last): File "<ipython-input-12-dc0b08011047>", line 1, in <module> scores.viewsitems() # avec views AttributeError: 'dict' object has no attribute 'viewsitems' >>> scores.viewitems() # retourne une vue dict_items([('max', 0), ('sam', 1)]) |
Néanmoins personne ne les a vraiment utilisé, et c’est un tort. Elles sont en effet très performantes, et pour cette raison sont retournées par défaut avec items()
en Python 3.
En effet, les vues ne sont qu’un enrobage : elles ne contiennent rien, et donc ne prennent pas beaucoup mémoire, tout comme les générateurs.
Mais contrairement aux générateurs, les vues ne se vident pas et peuvent exposer une API plus complète que les générateurs, comme par exemple déclarer une taille :
>>> items = scores.iteritems() >>> list(items) [('max', 0), ('sam', 1)] >>> list(items) # woops [] >>> items = scores.viewitems() >>> list(items) [('max', 0), ('sam', 1)] >>> list(items) [('max', 0), ('sam', 1)] >>> len(scores.iteritems()) # nope Traceback (most recent call last): File "<ipython-input-21-9c7f250da51d>", line 1, in <module> len(scores.iteritems()) TypeError: object of type 'dictionary-itemiterator' has no len() >>> len(scores.viewitems()) 2 |
Alors certes, on ne peut pas mettre des vues partout, et les générateurs restent utiles. Mais quand il est possible de les utiliser, et à moins d’avoir besoin d’une liste afin de modifier les valeurs in place, il n’y pas de raison de ne pas le faire : c’est le meilleur des deux mondes.
Un autre avantage très pratique des vues est qu’elles restent à jour en gardant une référence sur le dict
Bon ok, on a des views dans les dicos. La question que je me pose, c’est: «est-ce qu’on peut implémenter une view sur un objet quelconque ?».
En fait c’est juste un pattern “façade”, donc techniquement tu code ta fascade, tu l’appele “vue” et pouf :)
Pour info, numpy utilise beaucoup les vues pour ses tableaux, ce qui rend certaines opérations ultra-rapides (une transposition, par exemple).
donc iterXXX renvoie un iterator et viewXXX renvoie un iterable qui implémente len ?
@ZZelle: c’est l’idée, mais l’itérable implémente plus que \_\len\_\_ : il est par exemple comparable avec == avec un objet du même type.