在Python中构建“复杂”数据结构的最佳方式

4 投票
4 回答
7046 浏览
提问于 2025-04-15 15:25

我需要制作一个工具,用来尽可能自动化地创建字段映射(在表之间)。

这里的情况是:想象一下一个表要添加到另一个表中。(暂时不考虑字段类型……)

CREATE OR REPLACE TABLE fooA(
id,
name,
type,
foo)

CREATE OR REPLACE TABLE otherFooTable(
idFoo,
nameFoo,
spam)

我在考虑创建一个这样的结构:

fieldMap = {'otherFooTable': [('idFoo','id'),('nameFoo','name'),('spam','foo')]}

我可以通过(例如)这样的方式来访问它:

print fieldMap['tabelax'][0][1]

这个结构并不复杂,但在使用时可能会遇到一些问题?有没有什么建议可以帮助我处理这类问题?我现在需要存储至少输入表(我不想为每个映射的字段重复它)、输入字段和输出字段。输出表没有必要存储,因为它总是事先已知的。

非常感谢大家的建议和经验分享。

PS:也许使用一个正式的结构(比如类)会更好?

谢谢

4 个回答

2

尽量避免通过固定的数字索引来访问你的数据,比如用 fieldMap['tabelax'][0][1] 这种方式。因为如果你一年后再看你的代码,可能需要花一些时间才能搞清楚这些数字代表的具体意思(比如“tabelax表中idFoo的值”)。而且,如果你需要更改数据结构(比如添加一个字段),那么你之前用的数字索引可能就得修改。这样一来,你的代码就变得很僵化,因为担心修改逻辑会出错而不敢去改动数据结构。

使用类来管理数据会好很多,利用类的方法来访问数据结构。这样,即使将来你需要更改类内部的数据结构,外部的代码也能保持不变。

6

老实说,我建议你可以参考一下SQLAlchemy或者Django模型。这两种方法都是经过验证的数据表示方式,非常可靠。

4

这里有一个小的包装类,用来让FooB看起来像FooA,但同时又保留了FooB的特点。

from collections import namedtuple

# use namedtuple to define some simple classes (requires Py2.6 or later)
FooA = namedtuple('FooA', 'id name type foo')
FooB = namedtuple('FooB', 'idfoo namefoo spam')

# create a wrapper class for FooB's to look like a FooA
class FooAMimic(object):
    attrMap = dict(zip(FooA._fields, FooB._fields))
    # or if the fields aren't nicely ordered, declare this mapping explicitly
    #~ attrMap = { 'id' : 'idfoo', 'name' : 'namefoo', 'foo' : 'spam' }
    def __init__(self, obj):
        self.obj = obj
    def __getattr__(self, aname):
        ob = self.obj
        if aname in self.attrMap:
            return getattr(ob, self.attrMap[aname])
        elif  hasattr(ob, aname):
            return getattr(ob, aname)
        else:
            raise AttributeError("no such attribute " + aname)
    def __dir__(self):
        return sorted(set(dir(super(FooAMimic,self)) 
                          + dir(self.obj) 
                          + list(FooA._fields)))

使用方法如下:

# make some objects, some FooA, some FooB
fa = FooA('a', 'b', 'c','d')
fb = FooB('xx', 'yy', 'zz')
fc = FooA('e', 'f', 'g','h')

# create list of items that are FooA's, or FooA lookalikes
coll = [fa, FooAMimic(fb), fc]

# access objects like FooA's, but notice that the wrapped FooB
# attributes are still available too
for f in sorted(coll, key=lambda k : k.id):
    print f.id, '=', 
    try:
        print f.namefoo, "(really a namefoo)"
    except AttributeError:
        print f.name

输出结果:

a = b
e = f
xx = yy (really a namefoo)

撰写回答