【问题标题】:python DictReader subclassingpython DictReader 子类化
【发布时间】:2014-05-21 17:40:57
【问题描述】:

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

它返回一个未格式化的字典,其中包含分隔符 \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 

而不是包含正确字段名和由分隔符分隔的相对值的字典

但是当我要从另一个函数实例化 DictReader 时,我需要做的就是:

fo = open(filename, 'rb')
reader = csv.DictReader(fo, delimiter='\t')

阅读器对象正确地为您提供所需的输出。

有什么建议吗? 我还不清楚子类化过程,到目前为止在网上找到的内容对我没有帮助。

TIA 恩里科

【问题讨论】:

  • 快速思考......你的 init 需要调用 csv.DictReader 的 init 吗?

标签: python csv subclassing


【解决方案1】:

您发布的代码将与AttributeError 相混淆,而您的意思是self._delim,而您却拥有self._del

除此之外,您的另一个问题是您错误地调用了构造函数:

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(无论如何是 2.7)默认执行的操作。它使用位置参数填充签名中的下一个关键字参数。

所以你告诉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,这是因为您使用的这种模式实际上是委托而不是子类化或继承。您只是将一个对象属性设置为您有兴趣使用的类的一个实例,而您的方法只是以更方便的方式调用该实例的方法。

【讨论】:

  • 感谢 qww*,这次尝试是复制我在解释器中找到的一般指令的结果。我注意到 '\t' 被视为字段名而不是分隔符,但我认为分隔符是作为第二个参数的位置。愚蠢的错误,但我这样做是为了学习。
【解决方案2】:

最后,我是这样解决的:

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

【讨论】:

    猜你喜欢
    • 2023-03-26
    • 2011-12-14
    • 2010-11-15
    • 1970-01-01
    • 2012-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-26
    相关资源
    最近更新 更多