【问题标题】:Dictionary of dictionaries vs dictionary of class instances字典字典与类实例字典
【发布时间】:2017-02-05 04:07:20
【问题描述】:

我了解什么是类,即一组存储在一个对象中的属性和方法。然而,我认为我从来没有真正掌握过他们的全部力量。我自学通过使用“字典中的字典”数据结构来处理大量数据。我现在在想,如果我想融入世界其他地方,那么我需要在我的代码中实现类,但我就是不知道如何进行转换。

我有一个脚本,它从 SQL 查询中获取有关销售订单的信息,对数据执行操作,并将其输出到 csv。

1)(我目前的做法,将所有订单存储在字典中)

cursor.execute(querystring)

# create empty dictionary to hold orders
orders = {}

# define list of columns returned by query
columns = [col[0] for col in cursor.description]

for row in cursor:
    # create dictionary of dictionaries where key is order_id
    # this allows easy access of attributes given the order_id
    orders[row.order_id] = {}
    for i, v in enumerate(columns):
        # add each field to each order
        orders[row.order_id][v] = row[i]

# example operation
for order, fields in orders.iteritems():
    fields['long'], fields['lat'] = getLongLat(fields['post_code'])

# example of another operation
cancelled_orders = getCancelledOrders()
for order_id in cancelled_orders:
    orders[order_id]['status'] = 'cancelled'

# Other similar operations go here...

# write to file here...

2) (如果我使用类,我认为我会这样做)

class salesOrder():


    def __init__(self, cursor_row):
        for i, v in enumerate(columns):
            setattr(self, v, cursor_row[i])


    def getLongLat(self, long_lat_dict):
        self.long, self.lat = long_lat_dict[self.post_code]['long'], long_lat_dict[self.post_code]['lat']


    def cancelOrder(self):
        self.status = 'cancelled'


    # more methods here


cursor.execute(querystring)

# create empty dictionary to hold orders
orders = {}

# define list of columns returned by query
columns = [col[0] for col in cursor.description]

for row in cursor:
    orders[row.order_id] = salesOrder(row)
    orders[row.order_id].getLongLat()

# example of another operation
cancelled_orders = getCancelledOrders()
for order_id in cancelled_orders:
    orders[order_id].cancelOrder()

# other similar operations go here

# write to file here

我只是觉得我不太了解使用类的最佳方式。我对如何使用类有完全错误的想法吗?我在做什么有什么意义,但它需要重构吗?还是我试图将类用于错误的目的?

【问题讨论】:

  • 将一个类视为具有自定义方法的字典。
  • (a) 您的row 似乎是一个类对象,就像您在第一个示例中呈现它的方式一样(例如row.order_id)。 (b) row.column 不起作用。 (c) 让我们稍微备份一下,我认为您将数据放入字典的原因是为了方便查找,然后更新。但是,这就是你的数据库的用途,为什么不直接查询数据库并更新呢?
  • @HaiVu (a) 该行是一个类对象,但它只是光标返回的一行,我了解如何使用现有的类(大部分),我更关心最好的方法实现我自己的类 (b) 在 row.column 上的好位置,我的错,这就是为什么我在第二个示例中使用 enumerate(columns) 来解决这个问题,我现在将编辑问题 (c) 那将是在给定情况下有更好的方法,但出于问题的目的,我已经通过问题进行了简化,纯数据库解决方案不一定适合我更广泛的项目(希望有意义)
  • 嗯,部分原因是您可以将您的 dbcol-attrib 映射放在 DBInst 类的方法 dbset 中。然后 SalesOrder 可以是它的子类并从 init 调用 dbsetb。 Presto,贯穿始终的 db-aware 类。

标签: python class dictionary


【解决方案1】:

类主要用于将数据耦合到行为以及提供结构(例如,命名和记录某些属性的关联)。

你在这里没有做任何一个 - 你的班级没有真正的行为(它对数据没有任何事情),所有的结构都是外部提供的。类实例仅用于它们的属性字典,因此它们只是旧字典的精美包装。

如果你添加一些真实的行为(在getLongLatcancelOrder之上),或者一些真实的结构(除了从外部传入的任意列名和字段值的列表),那么使用类是有意义的。

【讨论】:

    【解决方案2】:

    我试图猜测您要做什么,因为我不知道您的“行”是什么样的。我假设你有变量columns,它是一个列名列表。如果是这种情况,请考虑这个代码sn-p:

    class SalesOrder(object):
        def __init__(self, columns, row):
            """ Transfer all the columns from row to this object """
            for name in columns:
                value = getattr(row, name)
                setattr(self, name, value)
            self.long, self.lat = getLongLat(self.post_code)
    
        def cancel(self):
            self.status = 'cancelled'
    
        def as_row(self):
            return [getattr(self, name) for name in columns]
    
        def __repr__(self):
            return repr(self.as_row())
    
    # Create the dictionary of class
    orders = {row.order_id: SalesOrder(columns, row) for row in cursor}
    
    # Cancel
    cancelled_orders = getCancelledOrders()
    for order_id in cancelled_orders:
        orders[order_id].cancel()
    
    # Print all sales orders
    for sales_order in orders.itervalues():
        print(sales_order)
    

    在最低级别,我们需要能够通过复制columns 中列出的所有属性,从row 对象创建一个新的SalesOrder 对象。在初始化SalesOrder对象时,我们也计算了经度和纬度。

    这样,创建类对象字典的任务就变得更容易了:

    orders = {row.order_id: SalesOrder(columns, row) for row in cursor}
    

    我们的orders 是一个字典,其中order_id 作为键,SalesOrder 作为值。最后,取消订单的任务和你的代码一样。

    除了您所拥有的之外,我还创建了一个名为 as_row() 的方法,如果您以后希望将 SalesOrder 对象写入 CSV 或数据库,它会很方便。现在,我用它来显示“原始”行。通常,print 语句/函数会调用__str__() 方法来获取对象的字符串表示,如果找不到,它将尝试调用__repr__() 方法,这就是我们这里的方法。

    【讨论】:

    • 嗨,这很有帮助。它给了我一些关于如何更好地构造我的代码的想法,它还向我保证,我尝试使用同一类的多个实例的方式是对类的“有效”使用。顺便说一句,“列”变量只是我在 sql 查询中选择的字段列表
    • 如果您想保留通过连续括号引用嵌套项的能力,请参阅stackoverflow.com/questions/4014621/…
    猜你喜欢
    • 2014-03-17
    • 1970-01-01
    • 2015-07-18
    • 1970-01-01
    • 2013-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多