2013-12-02 4 views
3

Как я могу генерировать экземпляры экземпляров динамически? В частности, что я хочу сделать:Динамическое создание экземпляров класса в Python

Я извлекаю данные из электронной таблицы, которая преобразуется в CSV. Строка - это заголовок. После строки заголовка каждая строка представляет данные об определенном порядке (col1 - идентификатор заказа, col2 - имя клиента, col 3 - дата, col 4 - количество и т. Д.). Прямо сейчас я импортирую CSV в список словарей. Поэтому каждый элемент в списке хранит словарь, который извлекает ключ из строки заголовка. Таким образом, я мог бы LookUp количество заказа № 5 по:

orderDict[5]['quantity'] 

Я новичок в объектно-ориентированное программирование ... но хотелось бы, чтобы каждый из этих заказов экземпляр класса Order. Итак, я хотел бы создать класс под названием «Заказ», а затем вытащить свойства из строки заголовка CSV. Так, что-то вроде (inputList список, который был стянут из файла CSV):

class Order(object): 
     """Defines an individual order""" 
     def __init__(self, inputList): 
      for z in range(len(inputList[0])) 
       self.inputList[0][z] = None 

я тогда хотел бы иметь некоторый код, который проходит через данные, импортированные из CSV и создает экземпляр для каждого ряд.

for a in range(len(inputList)) 
    if a != 0: 
     orderName = 'order%d' % (a) 
     orderName = Order() #I know this won't work... but not sure how I variably name this 
     for b in range(len(inputList[a])) 
      orderName.b = inputList[a][b] 

В результате будет экземпляр называется Заказ1, order2, order3, порядка 4, и т.д. Количество экземпляров, созданных будет зависеть от количества строк в исходных данных. Может быть 4 ... может быть тысячи.

Таким образом, если я хочу, чтобы найти величину порядка 5, то я могу просто позвонить по:

order5.quantity 

Однако, до сих пор кажется, что я должен был бы явно создать каждый экземпляр вручную:

order1 = Order() 
order2 = Order() 
order3 = Order() 

Не очень удобно или динамично при работе с тысячами заказов (и растет). Похоже, что должен быть способ динамически генерировать эти экземпляры на основе данных, подаваемых в программу.

ответ

2

Если вы действительно хотите, чтобы экземпляры имели имена глобальных переменных (например, order1, order2 и т. д.) можно (но очень уродливо) с использованием, например,globals()['order' + num] = Order(...). Более чистым и безопасным способом было бы хранить экземпляры в одном дикторе. Кроме того, для повышения эффективности вы можете заполнить заголовок, чтобы избежать теста на ноль с каждой итерации, можно использовать xrange вместо диапазона, чтобы избежать наложения полных наборов данных вокруг, возможно опционально установить атрибуты в init объекта, а не потом (видя, что информация уже доступна ...) и может передавать только заголовок и строку для каждого экземпляра, а не всех данных. Кстати есть колоны отсутствующие концы ваших для-линий:

class Order(object): 
    """Defines an individual order""" 
    def __init__(self, input_header, input_line): 
     for z in xrange(len(input_header)): 
      setattr(self, input_header[z], input_line[z]) 

orders = {} 
input_header = input_list.pop(0) 
for a in xrange(len(input_list)): 
    orders[a] = Order(input_header, input_list[a]) 
1

общее решение этой проблемы является использование словаря отображения строк для классов

classes = {"order":Order,"something":Something} 

keys = ["order","order","something"] 
my_instances = [classes[key]() for key in keys] 
0

Вы можете динамически добавлять соответствующие атрибуты к экземпляру класса порядка во время после его конкретизации как так:

class Order(object): 
    def __init__(self,pairs): 
     for k,v in pairs: 
      setattr(self,k,v) 
    def __str__(self): 
     return "oID: %s, custName: %s, Date: %s, Qty %s" %(self.orderID,self.custName,self.Date,self.Qty) 

Это займет итерабельность, которая содержит (key,value) кортежей. Затем он добавит атрибуты на основе key и value.

Используя этот класс, мы можем создавать заказы из файла CSV, как так:

orderID,custName,Date,Qty 
1,Bob,2/3/2013,2 
2,jane,2/4/2013,1 

Использование DictReader класса из модуля CSV:

from csv import DictReader 

with open('orders.csv') as f: 
    orders = [] 
    reader = DictReader(f) 
    for row in reader: 
     orders.append(Order(row.items())) 

что приведет к:

for order in orders: 
    print(order) 
>>> 
oID: 1, custName: Bob, Date: 2/3/2013, Qty 2 
oID: 2, custName: jane, Date: 2/4/2013, Qty 1 
0

Генерация классов с динамическими свойствами и динамических имен переменных, вероятно, не является хорошей идеей. Как ваша программа узнает, для чего они нужны, чтобы получить к ним доступ? Например:

order5.quantity 

предполагает, что существует по крайней мере 5 (или 6), и что заказы Заказы имеют атрибут quantity.

Создание имен атрибутов класса из имен полей заголовка файла CSV является проблематичным, поскольку они могут быть недействительными идентификаторами Python.

Хотя это не касается последнего вопроса, вы должны рассмотреть что-то вроде следующего вместо:

Учитывая пример файла, orders.csv, как это:

order_id,customer,date,product,quantity 
01,Brian,2013-12-01,Spam,2 
13,Eric,2013-11-28,Eggs,3 
42,John,2013-11-30,Cheese,4 

Вы могли бы использовать что-то вроде следующее:

from collections import namedtuple 
import csv 

class Orders(object): 
    def __init__(self, csv_filename): 
     with open(csv_filename, 'rb') as inputfile: 
      csv_reader = csv.reader(inputfile) 
      self.fields = csv_reader.next() # read header row 
      self.Order = namedtuple('Order', self.fields) 
      self.records = [self.Order(*row) for row in csv_reader] 

    def __getitem__(self, index): 
     return self.records[index] 

    def __len__(self): 
     return len(self.records) 

который позволил бы большую часть своего рода использования вы желаете:

orders = Orders('orders.csv') 

if len(orders) >= 3: 
    print orders[2].quantity # assumes name of a field 

for id, order in enumerate(orders): 
    print 'order id {}: {}'.format(id, order) 

Выход:

4 
order id 0: Order(order_id='01', customer='Brian', date='2013-12-01', product='Spam', quantity='2') 
order id 1: Order(order_id='13', customer='Eric', date='2013-11-28', product='Eggs', quantity='3') 
order id 2: Order(order_id='42', customer='John', date='2013-11-30', product='Cheese', quantity='4') 
Смежные вопросы