字典的字典 VS 类实例的字典

3
我理解类是一种将属性和方法捆绑在一个对象中的结构。然而,我认为我从未真正掌握它们的全部功能。我通过使用“字典嵌套字典”数据结构来自学处理大量数据。现在我在考虑,如果我想与世界其他人一样,那么我需要在我的代码中实现类,但我不知道如何进行过渡。
我有一个脚本,从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

我只是感觉我还没有完全理解如何最好地使用类。我是否对如何使用类有了完全错误的想法?我所做的是否有道理,但需要重构?或者我试图用类来达到错误的目的?


2
把类看作是一个带有自定义方法的字典即可。 - Bryan Oakley
(a) 从你在第一个例子中的呈现方式来看,row似乎是一个类对象(例如row.order_id)。 (b) row.column不起作用。 (c) 让我们回到一点,我认为你将数据放入字典的原因是为了方便查找和更新。然而,这就是你的数据库所用的,为什么不直接查询数据库并进行更新呢? - Hai Vu
@aivu (a) 该行是类对象,但它只是游标返回的一行,我知道如何使用现有的类(大多数情况下),我更关注如何最好地实现自己的类 (b) 在row.column上发现了问题,我的错,这就是为什么在第二个示例中我使用了enumerate(columns)来绕过此问题,我现在将编辑问题 (c) 在给定的情况下,那将是更好的方法,但我为了问题而简化了我的问题,并不一定适用于我更广泛的项目纯db解决方案(希望这是有意义的) - teebagz
好的,其中一部分是你可以将dbcol-attrib映射放在DBInst类的say方法dbset中。然后SalesOrder可以是该类的子类,并从init调用dbsetb。完成,整个类都具有db感知功能。 - JL Peyret
2个回答

2

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

在这里,您没有做到这两点-类中没有真正的行为(它不会对数据进行任何操作),所有结构都是外部提供的。类实例仅用于其属性字典,因此它们只是围绕旧字典的精美包装。

如果您添加一些真正的行为(在getLongLatcancelOrder之上),或一些真正的结构(而不仅仅是从外部传递的任意列名和字段值列表),那么使用类就有意义。


1

我正在猜测您想要做什么,因为我不知道您的“行”长什么样。 我假设您有变量columns,它是列名称的列表。 如果是这种情况,请考虑使用以下代码片段:

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)

在最底层,我们需要能够通过复制列出的所有属性,从行对象创建一个新的SalesOrder对象。初始化SalesOrder对象时,我们还要计算经度和纬度。
有了这个,创建类对象字典的任务就变得更容易了:
orders = {row.order_id: SalesOrder(columns, row) for row in cursor}

我们的orders是一个字典,以order_id为键,以SalesOrder为值。最后,取消订单的任务与您的代码相同。
除了您已经完成的内容,我创建了一个名为as_row()的方法,如果以后您希望将SalesOrder对象写入CSV或数据库中,这个方法会很方便。现在,我使用它来显示“原始”行。通常,print语句/函数将调用__str__()方法获取对象的字符串表示形式,如果找不到,则尝试调用__repr__()方法,这正是我们在这里所做的。

嗨,这非常有帮助。它给了我一些关于如何更好地组织我的代码的想法,也让我确信我尝试使用同一类的多个实例的方式是类的“有效”用法。顺便说一下,“columns”变量只是我在SQL查询中选择的字段列表。 - teebagz
如果您想保留通过顺序括号引用嵌套项的能力,请参阅https://dev59.com/1W865IYBdhLWcg3wCqHI - Kenny Ostrom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接