如果您将流程分解为合乎逻辑的、可重复使用的部分,这会有所帮助。
for new_product in products_and_articles['products']:
for old_product in products_for_update:
if new_product.article == old_product.article:
…
例如,您在这里所做的是查找与特定article 匹配的产品。由于article 是唯一的,我们可以这样写:
def find_products_by_article(products, article):
'''Find all products that match the given article. Returns
either a product or 'None' if it doesn't exist.'''
for products in products:
return product
然后调用它:
for old_product in products_for_update:
new_products = find_products_by_article(
products_and_articles['products'],
old_product.article)
…
但是如果我们可以利用为查找优化的数据结构,即dict(常量而不是线性复杂度)。所以我们可以做的是:
# build a dictionary that stores products indexed by article
products_by_article = dict(product.article, product for product in
products_and_articles['products'])
for old_product in products_for_update:
try:
# look up product in the dictionary
new_product = products_by_article[old_product.article]
except KeyError:
# silently ignore products that don't exist
continue
…
如果您经常进行此类查找,最好在其他地方重用products_by_article 字典,而不是每次都从头开始构建一个。 请注意:如果您使用产品记录的多个表示,则需要使它们始终保持同步!
对于内部循环,请注意这里的new_field 仅用于检查字段是否存在:
…
for old_field in old_product._meta.get_all_field_names():
for new_field in new_product._meta.get_all_field_names():
if old_field == new_field and old_field != 'id' and old_field != 'slug':
setattr(old_product, old_field, getattr(new_product, old_field))
(请注意,这有点可疑:old_product 中尚不存在的任何新字段都会被静默丢弃:这是故意的吗?)
这可以重新包装如下:
def transfer_fields(old, new, exclusions=('id', 'slug')):
'''Update all pre-existing fields in the old record to have
the same values as the new record. The 'exclusions' parameter
can be used to exclude certain fields from being updated.'''
# use a set here for efficiency reasons
fields = frozenset(old._meta.get_all_field_names())
fields.difference_update(new._meta.get_all_field_names())
fields.difference_update(exclusions)
for field in fields:
setattr(old, field, getattr(new, field))
将所有这些放在一起:
# dictionary of products indexed by article
products_by_article = dict(product.article, product for product in
products_and_articles['products'])
for old_product in products_for_update:
try:
new_product = products_by_article[old_product.article]
except KeyError:
continue # ignore non-existent products
transfer_fields(old_product, new_product)
这个最终代码的时间复杂度为O(n × k),其中n 是产品数,k 是字段数。