Dans Python 3.4+, pourquoi devrais-je utiliser namedtuple sur SimpleNamespace lorsque vous n'utilisez pas dict, ils semblent très similaires

11

À un moment ou à un autre, vous pourriez rencontrer des fonctions avec beaucoup d'arguments. Parfois, il est logique de combiner certains des arguments en super-arguments. J'ai souvent fait cela avec des dict, mais maintenant je cherche de meilleures façons de le faire.

J'aimerais tourner ...

def do_something(ax, ay, az, bu, bv, c):
    # Do something

... dans ...

def do_something(a, b, c):
    # Do something

... où aet bcontiennent leurs sous-variations.

Une façon de procéder consiste à:

A = namedtuple('A', 'x, y, z')
a = A(ax, ay, az)
B = namedtuple('B', 'u, v')
b = B(bu, bv)

Cependant, cela semble plus simple:

a = SimpleNamespace(x=ax, y=ay, z=az)
b = SimpleNamespace(u=bu, v=bv)

Quel est l'inconvénient? Le fait que aet bne sont pas bien tapés? Ce ne sont pas des objets A et B?

(Btw, ne vous inquiétez pas pour les noms de variables. Je ne les utilise pas normalement comme noms de variables courts.)

André Christoffer Andersen
la source
1
Il n'y a pas d'inconvénients en soi, ce sont juste des choses différentes. Pour les démarreurs nommés, les couples sont immuables tandis que les espaces de noms sont mutables. Le mutable est-il meilleur ou pire qu'inmutable? Cela dépend de ce dont vous avez besoin ou de ce que vous voulez, dans de nombreux cas, cela n'a pas d'importance. Votre fonction fonctionnerait probablement avec n'importe quel objet avec les attributs requis, la façon de le construire dépend de l'appelant.
Arrêtez de nuire à Monica
@Goyo Merci. L'inconvénient était une façon maladroite de le dire. Je ne voulais pas laisser entendre que l'un est intrinsèquement meilleur que l'autre. Je voulais juste les avantages et les inconvénients. Merci encore.
André Christoffer Andersen
1
la 4ème ligne ne devrait-elle pas ressembler à "b = B (bu, bv)"?
Alen Siljak
@AlenSiljak Oui, cela devrait. Je vais le réparer maintenant.
André Christoffer Andersen

Réponses:

21

SimpleNamespaceest fondamentalement juste une belle façade au-dessus d'un dictionnaire. Il vous permet d'utiliser des propriétés au lieu de clés d'index. C'est bien car il est super flexible et facile à manipuler.

L'inconvénient de cette flexibilité est qu'elle ne fournit aucune structure. Il n'y a rien pour empêcher quelqu'un d'appeler SimpleNamespace(x=ax, y=ay)(et del a.zà un moment donné plus tard). Si cette instance est transmise à votre fonction, l'exception se produit lorsque vous essayez d'accéder au champ.

En revanche, namedtuplevous permet de créer un type structuré. Le type aura un nom et saura quels champs il est censé avoir. Vous ne pourrez pas créer d'instance sans chacun de ces champs et ils ne pourront pas être supprimés ultérieurement. De plus, l'instance est immuable, vous saurez donc que la valeur de a.xsera toujours la même.

C'est à vous de décider si vous avez besoin de la flexibilité qui SimpleNamespacevous donne, ou si vous préférez avoir la structure et les garanties fournies par namedtuple.

unholysampler
la source
2

J'aime vraiment la réponse sur structuré par opposition à non, donc je fournis juste un exemple concret ci-dessous.

SimpleNamespaceacceptera les clés commençant par _. Si vous cherchez un moyen rapide et facile de transformer, disons, JSON que vous ne contrôlez pas en objets avec des noms de champ, c'est très pratique:

d = {"_id": 2342122, "text": "hi there!"} # Elasticsearch gives this id!
e = SimpleNamespace(**d) # works
Name = namedtuple("Name", sorted(d)) # ValueError so we can't do Name(**d)

Notez ci-dessus que vous pouvez voir que cela namedtuplenous donne un objet supplémentaire entier qui SimpleNamespacene le sera jamais. Chacun SimpleNamespaceest vraiment un "flocon de neige unique", alors qu'il namedtupleexiste sans jamais être instancié avec des valeurs concrètes. Partout où vous avez besoin d'abstractions généralisant des valeurs concrètes, vous devriez probablement la préférer.

Alex Moore-Niemi
la source
1

Résumé de SimpleNamespace

Il permet d'initialiser des attributs lors de la construction de l'objet:

sn = SimpleNamespace(a=1, b=2)

Il fournit un

repr(): eval(repr(sn)) == sn

Il remplace la comparaison par défaut. Au lieu de comparer par id(), il compare les valeurs d'attribut à la place.

Vlad Bezden
la source