Python 如何创建一个类来定义包含标题的CSV文件布局?

Python 如何创建一个类来定义包含标题的CSV文件布局?,python,export-to-csv,namedtuple,Python,Export To Csv,Namedtuple,我想创建一种方法,在这里我可以定义一个CSV文件的结构(下面应该是excel的扩展名),其中有一个行定义以及标题。在这种方法中,定义的简单重新排序将移动输出中的列 我的第一次尝试是使用名为tuple的。实际上处理了我的大部分需求,但我不能创建一个空行来根据需要填充它。我试着使用一个recordclass,但也有同样的问题 我的输出文件可能有>30列,因此创建一个包含大量Nones的新实例会变得非常草率。我还希望能够向结构中添加一列,而不必更新\uuuu init\uuuu等 我的想法是伪代码(使

我想创建一种方法,在这里我可以定义一个CSV文件的结构(下面应该是excel的扩展名),其中有一个行定义以及标题。在这种方法中,定义的简单重新排序将移动输出中的列

我的第一次尝试是使用名为tuple的
。实际上处理了我的大部分需求,但我不能创建一个空行来根据需要填充它。我试着使用一个
recordclass
,但也有同样的问题

我的输出文件可能有>30列,因此创建一个包含大量
None
s的新实例会变得非常草率。我还希望能够向结构中添加一列,而不必更新
\uuuu init\uuuu

我的想法是伪代码(使用
namedtuple
s进行说明)是:

class TableRow(namedtuple(TableRow, "id name password hostip"))
    __slots__ = ()


class TableRowHeader:
    def __init__(self):
        header = TableRow()
        header.id = 'ID'
        header.name = "Name"
        header.password = "Password"
        header.hostip = "Host IP"


class OutputTable():
    def __init__(self):
        self.header = TableRowHeader()
        self.rows = list()

    def add(self, new_row):
        # Example assumes new_row is an instance of TableRow
        self.rows.append(new_row)

    def to_csv(self, file_name):
        with open(file_name, 'w') as csv_file:
            # creating a csv writer object
            csv_writer = csv.writer(csv_file)

            # writing the fields
            csv_writer.writerow(self.header)

            for row in sorted(self.rows):
                csv_writer.writerow(row)  


outtable = OutputTable()
row = TableRow()
row.id = 1
row.name = 'Matt'
row.hostip = '10.0.0.1'
row.password = 'obvious'      
outtable.add(row)

outtable.to_csv('./example.csv') 

我喜欢这个模式,但在Python中找不到一个干净的方法来处理这个问题。

您想要类似的东西吗

import csv
from collections import namedtuple

TableRowShort = namedtuple('TableRow', "id name password hostip")
TableRowFull = namedtuple('TableRowFull', "id name password hostip description source admin_name")


class TableRowOptional:
    def __init__(self, id, name, password=None, hostip=None, description=None, source=None, admin_name=None):
        super().__init__()

        self.id = id
        self.name = name
        self.password = password
        self.hostip = hostip
        self.description = description
        self.source = source
        self.admin_name = admin_name


class OutputTable():
    def __init__(self):
        self.headers = []
        self.rows = list()

    def add(self, row):
        if hasattr(row, '_asdict'):
            value = row._asdict()
        elif hasattr(row, '__dict__'):
            value = row.__dict__
        elif isinstance(row, dict):
            value = row
        else:
            raise ValueError('Not supported row type: {}'.format(type(row)))

        for header in value.keys():
            if header not in self.headers:
                self.headers.append(header)

        self.rows.append(value)

    def to_csv(self, file_name):
        with open(file_name, 'w') as csv_file:
            # creating a csv writer object
            csv_writer = csv.writer(csv_file)

            # writing the fields
            csv_writer.writerow(self.headers)

            for row in self.rows:
                csv_writer.writerow([row.get(header, None) for header in self.headers])


outtable = OutputTable()
outtable.add(TableRowShort(1, 'Matt', 'obvious', '10.0.0.1'))
outtable.add(TableRowFull(2, 'Maria', 'obvious as usual', '10.1.0.1', 'some description', 'localnet', 'super_admin'))
outtable.add(TableRowOptional(3, 'Maria', hostip='10.1.0.1', description='some description', source='localnet'))
outtable.add({
    'id': 1337,
    'name': 'hacker',
    'hostip': '127.0.0.1',
    'extra': "I've hacked you guys lol!",
})

outtable.to_csv('./example.csv')


此解决方案为您提供了将一些“准备好的命名偶、普通对象(使用
\uuuuuu dict\uuuuu
接口)和原始dict对象存储为行的接口。它根据提供的行结构自动管理CSV头:)

看起来很清楚,对我来说很有用。你觉得呢

输出CSV

# > cat example.csv
id,name,password,hostip,description,source,admin_name,extra
1,Matt,obvious,10.0.0.1,,,,
2,Maria,obvious as usual,10.1.0.1,some description,localnet,super_admin,
3,Maria,,10.1.0.1,some description,localnet,,
1337,hacker,,127.0.0.1,,,,I've hacked you guys lol!

可以使用
recordclass
库按如下方式重写初始代码:

import csv
from recordclass import make_dataclass

TableRow = make_dataclass(
            'TableRow', 
            "id name password hostip description source admin_name",
            defaults=5*(None,),
            iterable=True)

class OutputTable():
    def __init__(self):
        self.header = TableRow(*TableRow.__fields__)
        self.rows = list()

    def add(self, new_row):
        # Example assumes new_row is an instance of TableRow
        self.rows.append(new_row)

    def to_csv(self, file_name):
        with open(file_name, 'w') as csv_file:
            # creating a csv writer object
            csv_writer = csv.writer(csv_file)

            # writing the fields
            csv_writer.writerow(self.header)

            for row in sorted(self.rows):
                csv_writer.writerow(row)

outtable = OutputTable()
outtable.add(TableRow(1, 'Matt', 'obvious', '10.0.0.1'))
outtable.add(TableRow(2, 'Maria', 'obvious as usual', '10.1.0.1', 'some description', 'localnet', 'super_admin'))
outtable.add(TableRow(3, 'Maria', hostip='10.1.0.1', description='some description', source='localnet'))

outtable.to_csv('./example.csv')
结果将是:

id,name,password,hostip,description,source,admin_name
1,Matt,obvious,10.0.0.1,,,
2,Maria,obvious as usual,10.1.0.1,some description,localnet,super_admin
3,Maria,,10.1.0.1,some description,localnet,

这是出于教育/学习的目的吗?好的,我一直在学习,但如果这是个问题的话,这不是我正在学习的课程。我是Python新手,来自Java。我用Java为此构建了一个类,我已经用了多年,可以用Python构建另一个类,但我很感兴趣,想看看我是否只是在重新发明轮子。我问这个问题,因为Python已经有了使用Excel和使用类似乎有点过分。这就是我现在所拥有的。缺点是,如果用户想要添加列或重新排序输出顺序,我需要在3个位置进行更改,并且当您有很多列时,出错的可能性会很高。这也是一种痛苦。啊,所以您想要一个解决方案吗n存储行列和“基于动态处理的行的任何标题”“,对吗?听起来不错是的。我想将数据管理与物理输出隔离开来。所以表的布局不会影响我如何构建行。@MatthewDoering现在就检查它,更接近我的想法是的,谢谢。我认为,如果我使用一个recordclass或一个包装器,允许我为一个对象赋值,然后让该类构建namedtuple,我将得到我所需要的。再次感谢你。