2012-10-02 1 views
1

je peux utiliser YAML pour vider une hiérarchie d'objets de python, donc:sélectif de vidage des attributs d'objet avec PyYAML

import yaml 

class C(): 
    def __init__(self, x, y): 
     self.x = x 
     self.y = y 

class D(): 
    def __init__(self, c, d): 
     self.c = c 
     self.d = d 

d = D(c=C(x=1, y='hi'), 
     d='bye') 

print yaml.dump(d) 

produit la sortie:

!!python/object:__main__.D 
c: !!python/object:__main__.C {x: 1, y: hi} 
d: bye 

Mais je veux me cacher de manière sélective certains attributs. supposons que j'ai donc une fonction attribs_to_dump(obj) qui pour tout objet retourne la liste des noms d'attributs que je veux jeter, par exemple:

def attribs_to_dump(obj): 
    if obj.__class__ == C: return ['x'] 
    if obj.__class__ == D: return ['c'] 

Ma question est, comment puis-je le crochet attribs_to_dump dans yaml.dump pour que je reçois la sortie suivante ?

!!python/object:__main__.D 
c: !!python/object:__main__.C {x: 1} 

Il y a un facteur de complication: Je veux obtenir l'effet en accrochant dans YAML comme il se traîne sur la hiérarchie des objets plutôt que par pré-traitement de la hiérarchie d'objets moi-même. La raison en est que tous les objets de la hiérarchie sont facilement prête à l'introspection en raison de setattr/getattr/__dict__ magique qui est présent dans certaines bibliothèques, je me sers: - (...

Toutes aide a beaucoup apprécié

Répondre

1

C'est un! question intéressante, j'ai beaucoup apprécié le résoudre, merci :)

from copy import deepcopy 


class C(object): 
    def __init__(self, x, y): 
     self.x = x 
     self.y = y 

class D(object): 
    def __init__(self, c, d): 
     self.c = c 
     self.d = d 

d = D(
    c=C(x=1, y='hi'), 
    d='bye' 
) 


FILTER_PARAMS = (
    #(class_reference, process_recursively, ['attributes', 'on', 'whitelist']) 
    (D, True, ['c']), 
    (C, False, ['x']), 
) 

def attr_filter(obj, filter_params): 
    for attr in dir(obj): 
     if attr.startswith('__'): 
      # ignore builtins 
      continue 

     attr_val = obj.__getattribute__(attr) 
     # loop through filter params 
     for (cls, do_recursive, whitelist) in filter_params: 
      if isinstance(obj, cls) and attr in whitelist: 
       # filter class matches the current obj's class and 
       # current attribute is on the whitelist 
       if do_recursive: 
        # must process this attribute the same way as the parent 
        setattr(obj, attr, attr_filter(attr_val, filter_params))     
       # break will avoid the execution of the else clause meaning 
       # the attribute was on the white list so don't delete it 
       break 
     else: 
      # delete the current attribute of the instance as it was 
      # not on the whitelist 
      delattr(obj, attr) 

    return obj 


# do a deepcopy of the object you pass in, so the original will be preserved 
filtered_instance = attr_filter(deepcopy(d), FILTER_PARAMS) 
print dir(filtered_instance) 
print dir(filtered_instance.c) 

# now pass filtered_instance to yaml's dump function 
+0

Vous avez en effet fourni une réponse à ma question, mais dans mon cas deepcopy ne fonctionnera pas parce que les objets que je suis sérialisation sont très magique - la magie et métaclasse getattr/setattr très ésotériques. Je dois ajouter quelques règles au jeu dans la question. – SimonD