Set attributes from dictionary in python

后端 未结 7 1628
南旧
南旧 2020-11-27 10:50

Is it possible to create an object from a dictionary in python in such a way that each key is an attribute of that object?

Something like this:

 d =          


        
相关标签:
7条回答
  • 2020-11-27 10:58

    Why not just use attribute names as keys to a dictionary?

    class StructMyDict(dict):
    
         def __getattr__(self, name):
             try:
                 return self[name]
             except KeyError as e:
                 raise AttributeError(e)
    
         def __setattr__(self, name, value):
             self[name] = value
    

    You can initialize with named arguments, a list of tuples, or a dictionary, or individual attribute assignments, e.g.:

    nautical = StructMyDict(left = "Port", right = "Starboard") # named args
    
    nautical2 = StructMyDict({"left":"Port","right":"Starboard"}) # dictionary
    
    nautical3 = StructMyDict([("left","Port"),("right","Starboard")]) # tuples list
    
    nautical4 = StructMyDict()  # fields TBD
    nautical4.left = "Port"
    nautical4.right = "Starboard"
    
    for x in [nautical, nautical2, nautical3, nautical4]:
        print "%s <--> %s" % (x.left,x.right)
    

    Alternatively, instead of raising the attribute error, you can return None for unknown values. (A trick used in the web2py storage class)

    0 讨论(0)
  • 2020-11-27 11:03

    Setting attributes in this way is almost certainly not the best way to solve a problem. Either:

    1. You know what all the fields should be ahead of time. In that case, you can set all the attributes explicitly. This would look like

      class Employee(object):
          def __init__(self, name, last_name, age):
              self.name = name
              self.last_name = last_name
              self.age = age
      
      d = {'name': 'Oscar', 'last_name': 'Reyes', 'age':32 }
      e = Employee(**d) 
      
      print e.name # Oscar 
      print e.age + 10 # 42 
      

      or

    2. You don't know what all the fields should be ahead of time. In this case, you should store the data as a dict instead of polluting an objects namespace. Attributes are for static access. This case would look like

      class Employee(object):
          def __init__(self, data):
              self.data = data
      
      d = {'name': 'Oscar', 'last_name': 'Reyes', 'age':32 }
      e = Employee(d) 
      
      print e.data['name'] # Oscar 
      print e.data['age'] + 10 # 42 
      

    Another solution that is basically equivalent to case 1 is to use a collections.namedtuple. See van's answer for how to implement that.

    0 讨论(0)
  • 2020-11-27 11:08

    Sure, something like this:

    class Employee(object):
        def __init__(self, initial_data):
            for key in initial_data:
                setattr(self, key, initial_data[key])
    

    Update

    As Brent Nash suggests, you can make this more flexible by allowing keyword arguments as well:

    class Employee(object):
        def __init__(self, *initial_data, **kwargs):
            for dictionary in initial_data:
                for key in dictionary:
                    setattr(self, key, dictionary[key])
            for key in kwargs:
                setattr(self, key, kwargs[key])
    

    Then you can call it like this:

    e = Employee({"name": "abc", "age": 32})
    

    or like this:

    e = Employee(name="abc", age=32)
    

    or even like this:

    employee_template = {"role": "minion"}
    e = Employee(employee_template, name="abc", age=32)
    
    0 讨论(0)
  • 2020-11-27 11:08

    You can access the attributes of an object with __dict__, and call the update method on it:

    >>> class Employee(object):
    ...     def __init__(self, _dict):
    ...         self.__dict__.update(_dict)
    ... 
    
    
    >>> dict = { 'name': 'Oscar', 'lastName': 'Reyes', 'age':32 }
    
    >>> e = Employee(dict)
    
    >>> e.name
    'Oscar'
    
    >>> e.age
    32
    
    0 讨论(0)
  • 2020-11-27 11:10

    I think that answer using settattr are the way to go if you really need to support dict.

    But if Employee object is just a structure which you can access with dot syntax (.name) instead of dict syntax (['name']), you can use namedtuple like this:

    from collections import namedtuple
    
    Employee = namedtuple('Employee', 'name age')
    e = Employee('noname01', 6)
    print e
    #>> Employee(name='noname01', age=6)
    
    # create Employee from dictionary
    d = {'name': 'noname02', 'age': 7}
    e = Employee(**d)
    print e
    #>> Employee(name='noname02', age=7)
    print e._asdict()
    #>> {'age': 7, 'name': 'noname02'}
    

    You do have _asdict() method to access all properties as dictionary, but you cannot add additional attributes later, only during the construction.

    0 讨论(0)
  • 2020-11-27 11:18

    say for example

    class A():
        def __init__(self):
            self.x=7
            self.y=8
            self.z="name"
    

    if you want to set the attributes at once

    d = {'x':100,'y':300,'z':"blah"}
    a = A()
    a.__dict__.update(d)
    
    0 讨论(0)
提交回复
热议问题