python DictReader子类化

时间:2014-05-21 17:40:57

标签: python csv subclassing

这是我关于子类化的第一次尝试,所以我需要一些专家的提示.. 我正在尝试将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 恩里科

2 个答案:

答案 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()