2
votes

Pourquoi dict1.items () <= dict2.items () et dict1.viewitems () <= dict2.viewitems () renvoient des résultats différents?

Je ne comprends pas pourquoi .items () renvoie un résultat différent de .viewitems () lors de la comparaison de deux dictionnaires sous forme de liste.

# python 2.7
d1 = {'1': '10', '2': '20'}  # two key-value pairs
d2 = {'3': '30', '4': '40', '5': '50'}  # three key-value pairs
print d1 <= d2  # True
print d1.items() <= d2.items()  # True
print d1.viewitems() <= d2.viewitems()  # False
print d1.items()  # [('1', '10'), ('2', '20')]
print d1.viewitems()  # dict_items([('1', '10'), ('2', '20')])

Cela semble être la principale différence entre .items ( ) et .viewitems () est que .items () renvoie une liste et viewitems () renvoie un truc dict_items.

Est-il recommandé d'utiliser simplement d1

Aussi, comment rendre cela compatible avec Python 3?


3 Réponses :


0
votes

Votre objectif déclaré est de comparer les tailles de dictionnaires ... ce que vous n'avez pas fait du tout. Vous devez utiliser len pour cela.

Ce que vous avez fait, c'est de comparer des éléments de deux types très différents. items renvoie une liste de tuples, qui sont facilement comparés par les algorithmes bien connus: vérifiez les éléments dans l'ordre donné pour la valeur relative. La comparaison de tuple est familière à la plupart d'entre nous.

Cependant, un dict_view est un objet de vue dynamique, pas une simple liste de valeurs. Vous comparez un objet plus complexe, pas simplement une liste évidente de valeurs. La définition de l'ordre et de la comparaison ne sont pas facilement visibles pour nous, simples mortels.


1 commentaires

La définition de classement et de comparaison est visible; la définition des objets de vue dict spécifie qu'ils implémentent l'ABC collections.abc.Set , et alors que l'ABC lui-même ne dit pas réellement ce que __le__ / < = devrait faire, tout réalisateur raisonnable suivrait les règles que set suit, à savoir, renvoyer True si le côté gauche est un sous-ensemble de, ou égal à , le côté droit.



5
votes
d1.viewitems() <= d2.viewitems()  # False

4 commentaires

Attendez, donc les résultats Vrai et Faux sont-ils fiables? Nous migrons de python 2 vers 3, et un linter a remplacé viewitems () par items (), puis a provoqué l'échec d'un test unitaire. Si .items () et .viewitems () font quelque chose de différent que de simplement comparer les tailles de dictionnaires, que dois-je faire?


Cela dépend, avez-vous besoin d'un code compatible croisé ou simplement d'un code compatible Python 3? Le test unitaire a-t-il échoué sur Py 2 ou Py 3?


Code compatible croisé. Le test unitaire a échoué sur python 2, mais la logique était un peu vague, qu'ils comparent les clés, les sous-ensembles ou la longueur des dictionnaires.


Votre linter a fait la bonne chose (en remplaçant les éléments d'affichage par des éléments) pour convertir le code py2 -> py3. Mais ce n'est pas un code de compatibilité croisée. Pour cela, vous devrez utiliser six.viewitems ou similaire, comme la réponse mentionnée.



1
votes

J'ai répondu à une question similaire ici: Comportement incohérent entre l'égalité dict.values ​​() et dict.keys () en Python 3.x et Python 2.7

La chose clé à noter est que dict.viewitems ( ) est un objet Set-like . Ce qui signifie que lorsque vous faites d1.viewitems () vous comparez en vérifiant si d1.viewitems () est un sous-ensemble em> de d2.viewitems () , pas la comparaison de longueur attendue. Consultez la documentation ici: https://docs.python.org/2.7 /library/sets.html#set-objects

>>> d1 = {'a': 0}
>>> d2 = {'a': 1}
>>> d3 = {'a': 0, 'b': 1}
>>> d1.viewitems() <= d3.viewitems()
True     # because [('a', 0)] is a subset of [('a', 0), ('b', 1)]
>>> d2.viewitems() <= d3.viewitems()
False    # because [('a', 1)] is not a subset of [('a', 0), ('b', 1)]

Remarque: comme dict.viewitem () est un objet collections.Set , il n'a pas .issubset ou .issuperset comme le fait set .

Observez ce qui suit:

Operation         Equivalent  Result
s.issubset(t)     s <= t      test whether every element in s is in t
s.issuperset(t)   s >= t      test whether every element in t is in s


0 commentaires