这是我关于子类化的第一次尝试,所以我需要一些专家的提示.. 我正在尝试将csv.DictReader / Writer子类化为更高级别的类来做这样的事情:
a = CsvRdr('filename.csv')
for row in a.rows:
# do something with dict returned in row
a.close()
我想出了一个像这样的子类:
class CsvRdr(csv.DictReader):
def __init__(self, filename):
self.__fo = open(filename, 'rb')
self.__delim = '\t'
self.rows = csv.DictReader(self.__fo, self.__delim)
self.rows.__init__(self.__fo, self.__del)
def close(self):
self.__fo.close()
但是当我这样做时:
for i in a.rows:
print i
它返回一个未格式化的dict,其中包含分隔符\ t作为键:
{'\t': 'seriesid\tseriesname\tstatus\tquality\tgroup\tpath'}
{'\t': '80337\tMad Men\tAiring\thdtv\tTV Shows\t/share/MD0_DATA/SORT/TV Shows/Mad Men'}
{'\t': '271910\tHalt and Catch Fire\tHiatus\thdtv\tTV Shows\t/share/MD0_DATA/SORT/TV
而不是包含正确字段名的dict和由分隔符
分割的相对值但是当我要从另一个函数实例化DictReader时,我需要做的就是:
fo = open(filename, 'rb')
reader = csv.DictReader(fo, delimiter='\t')
并且读者对象正确地为您提供所需的输出。
有什么建议吗? 我没有在脑海中清楚地看到子类化过程,到现在为止在网上找到的东西对我没有帮助。
TIA 恩里科
答案 0 :(得分:1)
您发布的代码将使用AttributeError
进行barf,如果您有self._del
,则表示self._delim
。
除此之外,你的另一个问题是你错误地调用了构造函数:
self.rows = csv.DictReader(self.__fo, self.__delim)
应该是
self.rows = csv.DictReader(self.__fo, delimiter = self.__delim)
查看DictReader
的构造函数签名,我们看到实际发生了什么:
csv.DictReader(self, f, fieldnames=None, restkey=None, restval=None, dialect='excel', *args, **kwds)
您的self.__delim
参数已设置为fieldnames
参数。当你给一个只剩下关键字参数的函数提供一个非关键字位置参数时,这就是Python(无论如何)默认执行的操作。它使用位置参数填充签名中的下一个关键字参数。
所以你告诉DictReader
“嘿,这个CSV只有一列,它的名字是'\ t'”。所以DictReader
做的逻辑事情是每行只有一个值,该值就是整行。
最后这一行:
self.rows.__init__(self.__fo, self.__del)
没有做任何事情,你只是以更明确的方式重复构造函数调用。
以下是我将如何重写你想要做的事情:
class CsvRdr(object):
def __init__(self, filename):
self.__fo = open(filename, 'rb')
self.__delim = '\t'
self.rows = csv.DictReader(self.__fo, delimiter = self.__delim)
def close(self):
self.__fo.close()
注意我将csv.DictReader
更改为object
,这是因为您使用的这种模式实际上是委托而不是子类或继承。您只是将一个对象属性设置为您感兴趣的类的实例,并且您的方法只是以更方便的方式调用该实例的方法。
答案 1 :(得分:0)
最后,我以这种方式解决了:
class CsvRdr(object):
def __init__(self, filename, delimiter=None):
self.__fo = open(filename, 'rb')
self.__delim = ( delimiter if delimiter else '\t' )
self.__rows = csv.DictReader(self.__fo, delimiter = self.__delim)
def __iter__(self):
return self.__rows
def close(self):
self.__fo.close()
此函数调用的类:
def CsvRead(filename):
try:
reader = CsvRdr(filename)
return reader
except IOError, e:
print "Error reading file : %s ERROR=%s" % (filename, e)
sys.exit(2)
在第二次尝试中,我添加了 iter 魔术方法来模仿Csv.DictReader的原始行为,因此您可以通过常规方式循环数据,而不是使用object.rows方法:
reader = CsvRead(catalog)
seriesnames = [ row['seriesname'].lower() for row in reader ]
reader.close()