回答此问题可获得 20 贡献值,回答如果被采纳可获得 50 分。
<p>所以我发现自己需要在Python字典中添加前缀。在</p>
<p>基本上我想要的是这个字典的用户能够在字典实例化时添加一个前缀,在这种情况下,字典保存前缀,每次添加一个新的键,它都会在前缀前面加上前缀。但是,如果由于某种原因前缀没有提供或更改,我也希望对字典进行变异,这意味着旧字典键需要在保留各自值的同时为其添加前缀。在</p>
<p>使用案例:</p>
<p>基本上,我正在完成<a href="https://github.com/czpython/python-amazon-mws" rel="noreferrer">MWS API</a>的最后一个api。
我构建api的想法是每次调用都需要使用特定的参数,
比如:</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>不幸的是,最后两个api很难用这种方式实现,因为它们使用了Amazon引入的一个新的“特性”<code>Datatypes</code>。在</p>
<p>这些“<code>Datatypes</code>”是嵌套结构。
例如:</p>
<p>我想从<code>InboundShipmentAPI</code>调用<code>CreateInboundShipment</code>操作</p>
<p>该操作采用以下参数:</p>
^{pr2}$
<p>问题的发生是因为InboundShipmentHeader是一个以另一个数据类型作为参数的数据类型。
最终,亚马逊期望:</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>所以我想让某人更简单地打电话,而不必担心每个参数的名称。
我的解决方案是创建一个基本数据类型类,然后创建单独的数据类型
作为班级。在</p>
<p>到目前为止,我得到的是:</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>而不是去做</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>我想传球</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>在后台,<code>call_amazon</code>方法执行以下操作:</p>
<pre><code>ShipmentHeader.prefix = InboundShipmentHeader
</code></pre>