2016-09-27 3 views
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

Думайте о классе как о чем-то другом, кроме словаря с пользовательскими методами. –

+0

(a) Кажется, что ваш 'row' является объектом класса так, как вы его представляете в первом примере (например,' row.order_id'). (b) 'row.column' не будет работать. (c) Давайте немного подкрепляемся, я думаю, причина, по которой вы помещаете свои данные в словарь, - это легко найти ее, а затем обновить. Однако для чего предназначена ваша база данных, почему бы не напрямую запросить базу данных и не обновить ее? –

+0

@HaiVu (a) строка является объектом класса, но это всего лишь строка, возвращаемая курсором, я понимаю, как использовать существующие классы (в основном), меня больше беспокоит лучший способ реализовать мои собственные классы (b) Хорошее место на row.column, мое плохое, вот почему я использовал перечисление (столбцы) во втором примере, чтобы обойти это, теперь я отредактирую вопрос (c) Это будет лучший подход в данной ситуации но я упростил проблему для целей вопроса, и чистое решение db не обязательно подходит для моего более масштабного проекта (надеюсь, что это имеет смысл) –

ответ

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 объект из row объекта, скопировав все атрибуты, перечисленные в columns более. При инициализации объекта SalesOrder мы также вычисляем долготу и широту.

При том, что задача создания словаря объектов класса стало проще:

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

Наша orders представляет собой словарь с order_id как ключи и SalesOrder как значения. Наконец, задача по аннулированию заказов совпадает с вашим кодом.

В дополнение к тому, что у вас есть, я создал метод под названием as_row(), который удобен, если позже вы захотите написать объект SalesOrder в CSV или базу данных. Пока я использую его для отображения «сырой» строки. Как правило, оператор/функция print вызывают метод __str__(), чтобы получить представление строки для объекта, если он не найден, он попытается вызвать метод __repr__(), что и есть здесь.

+0

Привет, это очень полезно. Это дает мне некоторые идеи о том, как лучше структурировать мой код, но также уверяет, что способ, которым я пытаюсь использовать несколько экземпляров одного и того же класса, - это «правильное» использование классов. BTW переменная «столбцы» - это просто список полей, которые я выбрал в моем запросе sql. –

+0

Если вы хотите сохранить возможность ссылки на вложенные элементы с помощью последовательных скобок, см. Http://stackoverflow.com/questions/4014621/a -python-класса, что-акты, как-ДИКТ –

2

Классы в основном полезны для связывания данных с поведением и для обеспечения структуры (например, именования и документирования связи определенных свойств).

Вы не делаете ни одного из них здесь - нет никакого реального поведения в вашем классе (это не do ничего для данных), и вся структура предоставляется снаружи. Экземпляры класса просто используются для их словарей атрибутов, поэтому они просто причудливая оболочка вокруг вашего старого словаря.

Если вы сделать добавить реальное поведение (выше getLongLat и cancelOrder), или какая-либо реальная структура (кроме списка произвольных имен столбцов и значений полей, передаваемых извне), то имеет смысл использовать класс ,

Смежные вопросы