8
votes

Python récursive SETATTR () - Fonction similaire pour travailler avec des dictionnaires imbriqués

Il y a beaucoup de bonnes fonctionnalités de getattr () - comme pour analyser les structures de dictionnaire imbriquées, telles que:

  • Trouver une clé récursive dans un dictionnaire li>
  • Supposons que j'ai un dictionnaire python, de nombreux nids li>
  • https://gist.github.com/mittenchops/5664038 Li> ul>

    Je voudrais faire un parallèle setattr (). Essentiellement, donné: p> xxx pré>

    J'aimerais produire une fonction de telle sorte que je puisse attribuer: p> xxx pré>

    plus ou Moins, cela fonctionnerait de la même manière que: p> xxx pré>

    à donner: p> xxx pré>

    Je l'appelle actuellement setbydot () code>: p> xxx pré>

    Un problème avec ceci est que si une clé au milieu n'existe pas, vous devez vérifier et faire un Touche intermédiaire si elle n'existe pas --- c'est-à-dire pour ce qui précède: p> xxx pré>

    donc, vous devez d'abord faire: p> xxx PRE>

    Un autre est que la saisie du moment où l'élément suivant est une liste différente de la saisie lorsque l'élément suivant est une chaîne, c'est-à-dire: p>

    def setByDot(obj,ref,newval):
        ref = ref.replace("[",".[")
        cmd = ref.split('.')
        numkeys = len(cmd)
        count = 0
        for c in cmd:
            count = count+1
            while count < numkeys:
                if c.find("["):
                    idstart = c.find("[")
                    numend = c.find("]")
                    try:
                        deep = obj[int(idstart+1:numend-1)]
                    except:
                        obj[int(idstart+1:numend-1)] = []
                        deep = obj[int(idstart+1:numend-1)]
                else:
                    try:
                        deep = obj[c]
                    except:
                        if obj[c] isinstance(dict):
                            obj[c] = {}
                        else:
                            obj[c] = ''
                        deep = obj[c]
            setByDot(deep,c,newval)
    


0 commentaires

4 Réponses :


2
votes
>>> class D(dict):
...     def __missing__(self, k):
...         ret = self[k] = D()
...         return ret
... 
>>> x=D()
>>> x['f'][0]['a'] = 'whatever'
>>> x
{'f': {0: {'a': 'whatever'}}}

3 commentaires

Hmm, j'aime bien c'est / beaucoup / plus simple, et il est proche, mais X aurait besoin de retourner {"F": [{"A": "Peu importe"}]} au lieu de {'F': {0: {'A': 'Quel que soit'}}} où l'intermédiaire est la 0ème d'une liste, au lieu d'une valeur touchée à 0. Je pense que je peux travailler avec ceci, ou Peut-être que l'approche générale de prendre un analyseur dict-à-objet ou quelque chose de ...


Quel devrait x = d (); x ['f'] [100] ['a'] = 'whatevs' faire, si c'est une liste au lieu d'une dictionnaire?


Ouais, bon point, mais je suppose que cela nécessiterait de créer des mannequins pour les articles 0 à 99. Aussi bon point que cela pourrait signifier si vous les avez attribués dans la commande x ['F'] ['A'] ['A'] 'whatevs', x ['F'] [99] ['A'] = 'Plus'] = "Plus", vous pouvez écraser toutes les valeurs que vous avez fabriquées pour 99, si vous avez rempli une chaîne vide ou une liste vide, ou vide la dicte vide.



2
votes

Vous pouvez pirater quelque chose ensemble en fixant deux problèmes:

  1. Liste qui se développe automatiquement lorsqu'il est accessible en dehors des limites (paddedlist)
  2. Un moyen de retarder la décision de créer (liste de dict) jusqu'à ce que vous l'avez accessible avant la première fois (dictorlist)

    Donc, le code ressemblera à ceci: xxx

    et la sortie de x et y sera: xxx

    L'astuce consiste à créer une radiographie par défaut d'objets pouvant être un dict ou une liste en fonction de la façon dont vous y accédez. Donc, lorsque vous avez l'assidation x ['f'] [10] ['A'] = 'Quelque chose' il fonctionnera la manière suivante:

    1. Obtenez X ['F']. Il n'existera pas pour que cela rendra un objet dictorlist pour l'index 'f'
    2. Obtenez X ['F'] [10]. Dictorlist. GetItem sera appelé avec un indice entier. L'objet dictorlist se remplacera dans la collection parent par une liste de patins
    3. Accédez au 11ème élément de la liste PADDEDLIST le poussera par 11 éléments et retournera l'élément mydict dans cette position
    4. assignez "tout ce qui est" à x ['f'] [10] ['A']

      Les deux pavés et la dictorlist sont un peu hacky, mais après toutes les tâches, vous n'avez plus de magie, vous avez une structure de dict et de listes.


4 commentaires

Désolé, je ne comprends pas --- Pouvez-vous me montrer comment cela fonctionne comme un setter, passant de la fonction (x, 'f [10] .a', val) à x ['F'] [10] ['A'] = Val = 'Quelque chose' ?


Vous pouvez également implémenter la liste matelle en tant que défaut_dict, en supposant que les indices seraient des INT et que __iter__ retournerait des iervalues ​​().


@DBW J'y ​​ai pensé, mais a préféré utiliser des listes car je ne sais pas comment ça va être utilisé (c'est-à-dire la coupe, le tri ...)


bon point. La notation de la tranche nécessiterait de prolonger la liste, plutôt que de faire une liste de plaide.



2
votes

Je l'ai séparé en deux étapes. Dans la première étape, la chaîne de requête est décomposée dans une série d'instructions. De cette façon, le problème est découplé, nous pouvons voir les instructions avant de les exécuter, et il n'est pas nécessaire d'appels récursifs. XXX PRE>

pour votre exemple P>

x = []
_setattr(x, "1.4", "asdf")
print x
[{}, {'4': 'asdf'}]  # A list, which isn't hashable

>>> y = {"a": "stuff"}
>>> _setattr(y, "f[1.4]", "test")  # We're indexing f with 1.4, which is a list!
>>> print y
{'a': 'stuff', 'f': [{}, {'4': 'test'}]}
>>> print _getattr(y, "f[1.4]")  # Works for _getattr too
"test"


3 commentaires

Cela avait l'air vraiment cool, mais ne semblait pas travailler pour moi. >>> x = {"A": "Stuff"} >>> _SetatTtr (x, "F [0] .a", "Test") >>> x {'A': 'Stuff'}


@Mitenchops Pour une raison quelconque, le build_instructions que j'ai sauvegardé est différent de ce qui se passe. Je l'ai mis à jour afin que cela fonctionne maintenant.


@MITENCHOPS haha, s'avère que j'avais commuté les arguments dans build_instructions par accident. Faites-moi savoir s'il y a toujours des problèmes!



2
votes

Il est possible de synthétiser des éléments de réglage de récursivement / des attributs en remplacement __ getItem __ code> pour renvoyer un proxy de retour un proxy pouvant définir une valeur dans la fonction d'origine.

Je travaille sur une bibliothèque Cela fait quelques choses similaires à cela, alors je travaillais sur une classe qui peut attribuer de manière dynamique ses propres sous-classes à l'instanciation. Cela facilite le travail avec ce type de chose, mais si ce type de piratage vous fait manifester, vous pouvez obtenir un comportement similaire en créant un proxyObject similaire à celui que je crée et en créant les classes individuelles utilisées par le proxyObject de manière dynamique dans la fonction A Fonction. . Quelque chose comme p> xxx pré>

Vous pouvez utiliser le dictionnaire comme que j'ai utilisé dans FlexibleObject ci-dessous rendrait cette implémentation de manière significative plus efficace si c'est ainsi que vous le mettez en œuvre. Le code que je fournirai utilise le flexibleObject cependant. À l'heure actuelle, il ne supporte que des cours qui, comme presque toutes les classes intégrées de Python sont capables d'être générés en prenant une instance d'eux-mêmes comme son seul argument à leur __ init __ code> / __ nouveau __ code>. Dans la semaine prochaine ou deux, j'ajouterai une assistance pour tout ce qui est piquant et un lien vers un référentiel GitHub qui le contient. Voici le code: p> xxx pré>

puis pour l'utiliser pour utiliser ceci pour synthétiser des attributs et des éléments d'un objet de dictionnaire, vous pouvez faire quelque chose comme ceci: P>

>>> qrd = QuickRecursiveDict
>>> qrd[0][13] # returns an instance of a subclass of KeyError
>>> qrd[0][13] = 9
>>> qrd[0][13] # 9
>>> qrd[0][13]['forever'] = 'young'
>>> qrd[0][13] # 9
>>> qrd[0][13]['forever'] # 'young'
>>> qrd[0] # returns an instance of a subclass of KeyError
>>> qrd[0] = 0
>>> qrd[0] # 0
>>> qrd[0][13]['forever'] # 'young'


0 commentaires