如何动态生成类实例?具体来说,我正在做的事情:
我从电子表格中提取数据,该数据表会转换为CSV格式。该行是标题。在标题行之后,每一行代表有关特定订单的数据(col1是订单ID,col2是客户名称,col3是日期,col4是数量等)。现在,我正在将CSV导入到词典列表中。因此,列表中的每个项目都存储一个字典,该字典从标题行中提取键。所以,我可以通过以下方式查找订单#5的数量:
orderDict[5]['quantity']
我是面向对象编程的新手......但是想让这些命令中的每一个都成为Order类的一个实例。所以,我想创建一个名为“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]
结果将是一个名为order1,order2,order3,order4等的实例。创建的实例数取决于原始数据中的行数。可能是4 ......可能是数千人。
这样,如果我想找到订单5的数量,我可以致电:
order5.quantity
但是,到目前为止,我似乎需要手动显式创建每个实例:
order1 = Order()
order2 = Order()
order3 = Order()
处理数以千计的订单(并且不断增长)时,不是很方便或动态。似乎应该有一种方法可以根据输入程序的数据动态生成这些实例。
答案 0 :(得分:2)
如果你真的希望实例具有全局变量名(例如order1,order2等),则可能(但非常难看)使用例如globals()['order' + num] = Order(...)
。更清晰,更安全的方法是将实例存储在单个字典中。同样为了提高效率,您可以弹出标题以避免每次迭代测试为零,可以使用xrange而不是范围来避免啜饮完整的数据集,可以选择在对象的init中设置属性而不是之后(看到信息已经可用...),并且只能将标题和行传递给每个实例而不是所有数据。顺便说一下,你的for-lines两端缺少冒号:
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 :(得分:1)
对此的一般解决方案是使用字典将字符串映射到类
classes = {"order":Order,"something":Something}
keys = ["order","order","something"]
my_instances = [classes[key]() for key in keys]
答案 2 :(得分: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)
元组的iterable。然后,它会根据key
和value
添加属性。
使用此类,我们可以从csv文件创建订单,如下所示:
orderID,custName,Date,Qty
1,Bob,2/3/2013,2
2,jane,2/4/2013,1
使用csv模块中的DictReader
类:
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
答案 3 :(得分: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')