[英]pythonic way to write this code
I have this ugly piece of code.. 我有这段丑陋的代码。
orders = got_something_from_db()
if orders:
for order in orders:
#print order
event_id = order["event_id"]
if event_id in event_id_dict: # something i grabbed earlier
product_id = order["product_id"] # products in an event
qty = order["qty"]
if product_id in product_sku_dict:
sku_id =product_sku_dict[product_id]
for i in range(qty):
sku_ids.append(sku_id)
How do I made this more pythonic (and terse) 我该如何使它变得更pythonic(更简洁)
First, the code is not exactly bad - it is clear enough to read and understand and so you have definitely passed more than the first hurdle of maintainability. 首先,代码并不是很糟糕-足够清晰易读和理解,因此您肯定已经超越了可维护性的第一个障碍。
If there is a problem it is the deep nesting. 如果有问题,那就是深层嵌套。 I would break this up by making a number of functions, each with a distinct business purpose expressed in their name:
我将通过创建多个函数来分解这些函数,每个函数都以其名称表示了不同的业务目的:
def order_has_valid_event(order):
"""Returns True if the order was raised by an event
in event_id_dict"""
event_id = order["event_id"]
return event_id in event_id_dict # something i grabbed earlier
def get_sku_from_order(order):
"""Return the SKU of the product in an order"""
product_id = order['product_id']
try:
return product_sku_dict[product_id]
except KeyError:
raise KeyError("Product {0} is not in SKU dictionary".format(product_id))
def get_order_skus(order):
"""Returns a list of SKUs in an order"""
sku_id = get_sku_from_order(order)
qty = order["qty"]
return [sku_id] * qty
# Modify got_something_from_db to always return a list, even if empty
orders = got_something_from_db()
for order in orders:
#print order
if order_has_valid_event(order):
try:
sku_ids.extend(get_order_skus(order))
except KeyError:
continue
Please forgive this attempt if the names don't quite match your intent - just rename them appropriately. 如果名称与您的意图不符,请原谅此尝试-只需适当地重命名即可。
My attempted improvements: 我尝试的改进:
qty
times appending, you can create a list of qty
elements with the list multiply: ['a'] * 3 = ['a', 'a', 'a'] qty
倍追加,您可以创建的列表qty
与列表乘元素:[“一”] * 3 = [“一”,“一”,“一”] KeyError
in get_sku_from_order
and thrown a more explicit exception message. KeyError
的get_sku_from_order
并抛出一个更明确的异常信息。 With limited context, here's the best I can do. 在有限的上下文中,这是我能做的最好的事情。
orders = got_something_from_db()
for order in orders: #make got something return empty iterable on failure
if order["event_id"] in event_id_dict:
product_id = order["product_id"]
try:
sku_id = product_sku_dict[product_id]
#Change sku_ids to a collections.Counter (assuming order is unimportant)
sku_ids[sku_id] += order["qty"]
except KeyError:
pass
Also, consider changing event_id, product_id, etc to attributes. 另外,请考虑将event_id,product_id等更改为属性。 You probably want a namedtuple here, not a dict.
您可能在这里想要一个namedtuple,而不是字典。
I'd structure it something like the following: 我将其结构如下所示:
def add_product_to_skus(product_id, qty):
if product_id in product_sku_dict:
sku_id = product_sku_dict[product_id]
sku_ids.extend(qty*[sku_id])
# ...
orders = got_something_from_db()
if not orders:
return
valid_orders = (o for o in orders if o['event_id'] in event_id_dict)
for o in valid_orders:
add_product_to_skus(o['product_id'], o['qty'])
Some golfing of the above would give you: 上面的打高尔夫球会给你:
orders = got_something_from_db()
if not orders:
return
add_products_to_skus((o['product_id'], o['qty']) for o in orders
if o['event_id'] in event_id_dict
if o['product_id'] in product_sku_dict)
# ...
def add_product_to_skus(product_qtys):
for product_id, qty in product_qtys:
sku_id = product_sku_dict[product_id]
sku_ids.extend(qty*[sku_id])
But the transformation from your original to this form isn't necessarily clear (or even correct), and the list comprehension would probably deserve a comment explaining the filtering. 但是从原始格式到此格式的转换不一定很清楚(甚至正确),并且列表理解可能值得注释以解释过滤条件。
sku_ids = []
event_ids = get_event_id_dict()
orders = got_something_from_db()
for order in orders:
if order["event_id"] in event_ids:
try:
sku_id = product_sku_dict[order["product_id"]]
except KeyError:
continue
sku_ids.extend([sku_id] * order["qty"])
You'll probably want to raise an exception rather than silently ignore a missing SKU item. 您可能想提出一个异常,而不是默默地忽略丢失的SKU项目。 This is how to be the most modular and elegant, not necessary pythonic:
这是如何成为最模块化和最优雅的Pythonic:
database = ...
productId_to_sku = {...}
def productIdToSku(product_id):
try:
return productId_to_sku[product_id]
except IndexError:
raise Exception('product id #{} not in SKU database; have a manager add it'.format(product_id))
def getSkusFromEvent(event_id):
orders = database.fetch(event_id=event_id)
for order in orders:
yield (productIdToSku(order.PRODUCT_ID), order.QTY)
collections.Counter(getSkusFromEvent(YOUR_EVENT_ID))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.