title: Most efficient way to add prefix to Python dictionary keys
body: <p>So I find myself needing to add a prefix to a Python dictionary.</p>
  
  <p>Basically what I want is for the user of this dictionary to be able to add a prefix on instantiation of the dictionary, in which case the dictionary holds the prefix and everytime a new key is added, it prepends the prefix. But I also want mutate the dictionary if for some reason the prefix is not provided or changed, this means that the old dictionary keys need to have the prefix prepended to them while keeping their respective values.</p>
  
  <p>Use case:</p>
  
  <p>Basically I'm finishing up the last apis of the <a href="https://github.com/czpython/python-amazon-mws" rel="noreferrer">MWS API</a>.
  I built the api around the idea that every call needed to take specific parameters,
  like :</p>
  
  <pre><code>def get_report(self, marketplaceids):
      # Here I process marketplaceids which is a python list
      # and send the following to Amazon:
  
      MarketplaceIdList.Id.1: 123,
      MarketplaceIdList.Id.2: 345,
      MarketplaceIdList.Id.3: 4343
  
      # By doing this I eliminate the complexity of the arguments Amazon expects
  </code></pre>
  
  <p>Unfortunately the last two apis are harder to implement this way because they make use of a new "feature" Amazon introduced called <code>Datatypes</code>.</p>
  
  <p>These "<code>Datatypes</code>" are nested structures.
  For example:</p>
  
  <p>I want to call the <code>CreateInboundShipment</code> action from the <code>InboundShipmentAPI</code>,</p>
  
  <p>The action takes the following arguments:</p>
  
  <pre><code>ShipmentId - String
  InboundShipmentHeader - InboundShipmentHeader datatype
  InboundShipmentItems - A list of InboundShipmentItem datatypes
  </code></pre>
  
  <p>the problem happens because InboundShipmentHeader is a datatype that takes another datatype as argument.
  In the end Amazon expects the following:</p>
  
  <pre><code>ShipmentId=102038383
  InboundShipmentHeader.ShipmentName': 'somevalue',
  InboundShipmentHeader.ShipFromAddress.Name': 'somevalue',
  InboundShipmentHeader.ShipFromAddress.AddressLine1': 'somevalue',
  InboundShipmentHeader.ShipFromAddress.City': 'somevalue',
  InboundShipmentHeader.ShipFromAddress.StateOrProvinceCode': 'somevalue',
  InboundShipmentHeader.ShipFromAddress.PostalCode': 'somevalue',
  InboundShipmentHeader.ShipFromAddress.CountryCode': 'somevalue',
  InboundShipmentHeader.DestinationFulfillmentCenterId': 'somevalue',
  InboundShipmentHeader.ShipmentStatus': 'somevalue',
  InboundShipmentHeader.LabelPrepPreference': 'somevalue',
  InboundShipmentItems.member.1.QuantityShipped': 'somevalue',
  InboundShipmentItems.member.2.QuantityShipped': 'somevalue',
  InboundShipmentItems.member.1.SellerSKU': 'somevalue',
  InboundShipmentItems.member.2.SellerSKU': 'somevalue',
  InboundShipmentHeader.ShipFromAddress.AddressLine2': 'somevalue',
  InboundShipmentHeader.ShipFromAddress.DistrictOrCounty': 'somevalue',
  </code></pre>
  
  <p>so I want to make it simple for someone to make this call without having to worry about the names of each argument.
  My solution is to create a base datatype class and then create the separate datatypes
  as classes. </p>
  
  <p>This is what I have so far:</p>
  
  <pre><code>class AmazonDataType(dict):
      """
      Base for all Amazon datatypes.
      """
  
      def __init__(self, *args, **kwargs):
          self._prefix = kwargs.pop('prefix', '')
          self.update(*args, **kwargs)
  
      @property
      def prefix(self):
          return self._prefix
  
      @prefix.setter
      def prefix(self, value):
          self._prefix = value
          newdict = {'%s.%s' % (value, key): dictvalue for key, dictvalue in self.iteritems()}
          self.clear()
          dict.update(self, newdict)
  
      def __setitem__(self, key, value):
          try:
              original_key = self.fields[key]
          except KeyError, e:
              raise e
          if isinstance(value, AmazonDataType):
              value.prefix = original_key
              dict.update(self, value)
          else:
              newkey = self.prefix + original_key if self.prefix else original_key
              dict.__setitem__(self, newkey, value)
  
      def update(self, *args, **kwargs):
          """
          Props to Matt Anderson (http://stackoverflow.com/a/2390997/389453)
          """
          for k, v in dict(*args, **kwargs).iteritems():
              self[k] = v
  
  
  class InboundShipmentHeader(AmazonDataType):
      fields = {
          'name': 'ShipmentName',
          'address': 'ShipFromAddress',
          'fulfillment_center_id': 'DestinationFulfillmentCenterId',
          'label_preference': 'LabelPrepPreference',
          'cases_required': 'AreCasesRequired',
          'shipment_status': 'ShipmentStatus',
      }
  </code></pre>
  
  <p>then instead of doing</p>
  
  <pre><code>somedict = {
      'InboundShipmentHeader.ShipmentName': 'somevalue',
      'InboundShipmentHeader.ShipFromAddress.Name': 'somevalue',
      'InboundShipmentHeader.ShipFromAddress.AddressLine1': 'somevalue',
      'InboundShipmentHeader.ShipFromAddress.City': 'somevalue',
      'InboundShipmentHeader.ShipFromAddress.StateOrProvinceCode': 'somevalue',
      'InboundShipmentHeader.ShipFromAddress.PostalCode': 'somevalue',
      'InboundShipmentHeader.ShipFromAddress.CountryCode': 'somevalue',
      'InboundShipmentHeader.DestinationFulfillmentCenterId': 'somevalue',
      'InboundShipmentHeader.ShipmentStatus': 'somevalue',
      'InboundShipmentHeader.LabelPrepPreference': 'somevalue',
  }
  
  call_amazon(somedict)
  </code></pre>
  
  <p>I want to pass something like</p>
  
  <pre><code>ShipmentHeader = InboundShipmentHeader()
  ShipmentHeader['name'] = 'somevalue'
  ShipmentHeader['address'] = address_datatype_instance
  ShipmentHeader['fulfillment_center_id'] = 'somevalue'
  ShipmentHeader['label_preference'] = 'somevalue'
  ShipmentHeader['cases_required'] = 'somevalue'
  ShipmentHeader['shipment_status'] = 'somevalue'
  
  call_amazon(ShipmentHeader, otherparams)
  </code></pre>
  
  <p>In the background, the <code>call_amazon</code> method does:</p>
  
  <pre><code>ShipmentHeader.prefix = InboundShipmentHeader
  </code></pre>