Performance: leverage dict comprehension in PEP-0274

merged from Ifb5cb05b9cc2b8758d5a8e34f7792470a73d7c40

PEP-0274 introduced dict comprehensions to replace dict constructor
with a sequence of length-2 sequences, these are benefits copied
from [1]:
  The dictionary constructor approach has two distinct disadvantages
  from the proposed syntax though.  First, it isn't as legible as a
  dict comprehension.  Second, it forces the programmer to create an
  in-core list object first, which could be expensive.
Nova dropped python 2.6 support, we can leverage this now.
There is deep dive about PEP-0274[2] and basic tests about
performance[3].
Note: This commit doesn't handle dict constructor with kwagrs.
This commit also adds a hacking rule.

[1]http://legacy.python.org/dev/peps/pep-0274/
[2]http://doughellmann.com/2012/11/12/the-performance-impact-of-using-dict-instead-of-in-cpython-2-7-2.html
[3]http://paste.openstack.org/show/154798/

Change-Id: I1bc53e335b6c291da5c54f067f9fdfd5da6b2902
This commit is contained in:
Andrey Pavlov 2015-04-02 15:17:36 +03:00
parent 85365faf16
commit 97e72e40d0
10 changed files with 36 additions and 41 deletions

View File

@ -339,7 +339,7 @@ class UniversalDescriber(object):
self.os_items = self.get_os_items()
formatted_items = []
self.items_dict = dict((i['os_id'], i) for i in (self.items or []))
self.items_dict = {i['os_id']: i for i in (self.items or [])}
paired_items_ids = set()
for os_item in self.os_items:
os_item_name = self.get_name(os_item)

View File

@ -530,8 +530,7 @@ def _cloud_format_block_device_mapping(context, bdm, root_device_name=None,
"""Construct BlockDeviceMappingItemType."""
keys = (('deviceName', 'device_name'),
('virtualName', 'virtual_name'))
item = dict((name, bdm[k]) for name, k in keys
if k in bdm)
item = {name: bdm[k] for name, k in keys if k in bdm}
if bdm.get('no_device'):
item['noDevice'] = True
if bdm.get('boot_index') == 0 and root_device_name:
@ -539,8 +538,7 @@ def _cloud_format_block_device_mapping(context, bdm, root_device_name=None,
if ('snapshot_id' in bdm) or ('volume_id' in bdm):
ebs_keys = (('volumeSize', 'volume_size'),
('deleteOnTermination', 'delete_on_termination'))
ebs = dict((name, bdm[k]) for name, k in ebs_keys
if bdm.get(k) is not None)
ebs = {name: bdm[k] for name, k in ebs_keys if bdm.get(k) is not None}
if bdm.get('snapshot_id'):
ebs['snapshotId'] = ec2utils.os_id_to_ec2_id(
context, 'snap', bdm['snapshot_id'], ids_by_os_id=snapshot_ids)

View File

@ -305,13 +305,12 @@ class InstanceDescriber(common.TaggableItemsDescriber):
self.ec2_network_interfaces = (
instance_engine.get_ec2_network_interfaces(
self.context, self.ids))
self.volumes = dict((v['os_id'], v)
for v in db_api.get_items(self.context, 'vol'))
self.image_ids = dict((i['os_id'], i['id'])
for i in itertools.chain(
db_api.get_items(self.context, 'ami'),
db_api.get_public_items(self.context,
'ami')))
self.volumes = {v['os_id']: v
for v in db_api.get_items(self.context, 'vol')}
self.image_ids = {i['os_id']: i['id']
for i in itertools.chain(
db_api.get_items(self.context, 'ami'),
db_api.get_public_items(self.context, 'ami'))}
return instances
def get_os_items(self):
@ -1343,10 +1342,9 @@ _NAME_TO_CODE = {
inst_state_SUSPEND: inst_state_STOPPED_CODE,
inst_state_RESCUE: inst_state_RUNNING_CODE,
}
_CODE_TO_NAMES = dict([(code,
[item[0] for item in _NAME_TO_CODE.iteritems()
if item[1] == code])
for code in set(_NAME_TO_CODE.itervalues())])
_CODE_TO_NAMES = {code: [item[0] for item in _NAME_TO_CODE.iteritems()
if item[1] == code]
for code in set(_NAME_TO_CODE.itervalues())}
def inst_state_name_to_code(name):

View File

@ -235,14 +235,14 @@ class RouteTableDescriber(common.TaggableItemsDescriber,
associations[subnet['route_table_id']].append(subnet['id'])
self.associations = associations
vpcs = db_api.get_items(self.context, 'vpc')
self.vpcs = dict((vpc['id'], vpc) for vpc in vpcs)
self.vpcs = {vpc['id']: vpc for vpc in vpcs}
gateways = db_api.get_items(self.context, 'igw')
self.gateways = dict((igw['id'], igw) for igw in gateways)
self.gateways = {igw['id']: igw for igw in gateways}
# TODO(ft): scan route tables to get only used instances and
# network interfaces to reduce DB and Nova throughput
network_interfaces = db_api.get_items(self.context, 'eni')
self.network_interfaces = dict((eni['id'], eni)
for eni in network_interfaces)
self.network_interfaces = {eni['id']: eni
for eni in network_interfaces}
return super(RouteTableDescriber, self).get_db_items()

View File

@ -83,8 +83,8 @@ class SnapshotDescriber(common.TaggableItemsDescriber):
self.volumes)
def get_db_items(self):
self.volumes = dict((vol['os_id'], vol)
for vol in db_api.get_items(self.context, 'vol'))
self.volumes = {vol['os_id']: vol
for vol in db_api.get_items(self.context, 'vol')}
return super(SnapshotDescriber, self).get_db_items()
def get_os_items(self):

View File

@ -124,10 +124,10 @@ class VolumeDescriber(common.TaggableItemsDescriber):
self.instances, self.snapshots)
def get_db_items(self):
self.instances = dict((i['os_id'], i)
for i in db_api.get_items(self.context, 'i'))
self.snapshots = dict((s['os_id'], s)
for s in db_api.get_items(self.context, 'snap'))
self.instances = {i['os_id']: i
for i in db_api.get_items(self.context, 'i')}
self.snapshots = {s['os_id']: s
for s in db_api.get_items(self.context, 'snap')}
return super(VolumeDescriber, self).get_db_items()
def get_os_items(self):

View File

@ -206,8 +206,8 @@ def _build_block_device_mappings(context, ec2_instance, os_instance_id):
ebs_devices = [ebs['deviceName']
for ebs in ec2_instance['blockDeviceMapping']]
ebs_devices.sort()
ebs_devices = dict(('ebs%d' % num, ebs)
for num, ebs in enumerate(ebs_devices))
ebs_devices = {'ebs%d' % num: ebs
for num, ebs in enumerate(ebs_devices)}
mappings.update(ebs_devices)
# TODO(ft): extend Nova API to get ephemerals and swap
@ -218,11 +218,10 @@ def _cut_down_to_version(metadata, version):
version_number = VERSIONS.index(version) + 1
if version_number == len(VERSIONS):
return metadata
return dict((attr, metadata[attr])
for attr in itertools.chain(
*(VERSION_DATA[ver]
for ver in VERSIONS[:version_number]))
if attr in metadata)
return {attr: metadata[attr]
for attr in itertools.chain(
*(VERSION_DATA[ver] for ver in VERSIONS[:version_number]))
if attr in metadata}
def _format_metadata_item(data):

View File

@ -844,11 +844,11 @@ class InstanceTestCase(base.ApiTestCase):
fakes.OSInstance_full({
'id': os_id,
'flavor': {'id': 'fakeFlavorId'},
'addresses': dict((subnet_name,
[{'addr': addr,
'version': 4,
'OS-EXT-IPS:type': 'fixed'}])
for subnet_name, addr in ips),
'addresses': {subnet_name:
[{'addr': addr,
'version': 4,
'OS-EXT-IPS:type': 'fixed'}]
for subnet_name, addr in ips},
'root_device_name': '/dev/vda',
'hostname': '%s-%s' % (fakes.ID_EC2_RESERVATION_1, l_i)})
for l_i, (os_id, ips) in enumerate(zip(

View File

@ -60,8 +60,8 @@ class TagTestCase(base.ApiTestCase):
'vol', 'vpc']]
self.assertEqual(len(resource_ids), len(tag_api.RESOURCE_TYPES))
params = dict(('ResourceId.%s' % num, r_id)
for num, r_id in enumerate(resource_ids))
params = {'ResourceId.%s' % num: r_id
for num, r_id in enumerate(resource_ids)}
params.update({'Tag.1.Key': 'tag',
'Tag.1.Value': 'value'})
resp = self.execute('CreateTags', params)

View File

@ -1,6 +1,6 @@
[tox]
minversion = 1.6
envlist = py26,py27,py33,py34,pep8
envlist = py27,py33,py34,pep8
skipsdist = True
[testenv]