在命名元组中使用下划线

Using underscores with namedtuples

我正致力于在 Python 中构建一个 SQL 模拟器并存储行,我想使用 namedtuples 因为我可以使用 select 轻松处理复杂的查询、排序方式和地点。我从普通元组开始,但我经常发现自己在寻找行的属性并需要维护列的顺序,所以我来到了 namedtuples。

问题是我的一些列名有前导下划线,这导致我以 ValueError: Field names cannot start with an underscore: '_col2'

结尾

我正在寻找一种方法来使用带下划线的命名元组(可能是某种覆盖类型)或合适的替代容器,使我能够轻松地转换为原始列顺序的值元组或访问单个值通过他们的字段名称。

我考虑过为每个元组附加一个前导字符串,然后编写一个中间件函数作为 getattr 函数,但首先删除前导字符串 - 但这似乎非常 hacky。

考虑使用 OrderedDict 类型。 您可以通过括号语法访问具有任何字符串名称的字段,并最终使用“.items”将其转换为元组。

from collections import OrderedDict
ordered_form = OrderedDict([("col1", 'Apple'), ("col2", 'Orange'), ("_col3", 'Banana')])
ordered_form["_col3"] = 'Grapefruit'
tuple_form = tuple([i[1] for i in list(ordered_form.items())])
print(tuple_form)

您可以使用 rename=True 参数避免 ValueError

from collections import namedtuple

a = namedtuple("Table", "_col1 _col2 _col3 col4", rename=True)

print(a._fields)

('_0', '_1', '_2', 'col4')

@Edit1您可能想要跟踪哪些字段已更改

from collections import namedtuple

columns = "_col1 _col2 _col3 col4"
a = namedtuple("Table", columns, rename=True)

old_feilds = columns.split()
new_feilds = a._fields

mapper = {}

for f1,f2 in zip(old_feilds, new_feilds):
    mapper[f1] = f2

print(mapper)

{'_col3': '_2', '_col1': '_0', 'col4': 'col4', '_col2': '_1'}

你总是可以使用 type:

obj = type('Foo', tuple(), {'_closed': False})()

现在我可以访问它了:

obj._closed

让我们添加一些实用函数:

from collections import deque
from itertools import islice


it_consumes = (lambda it, n=None: deque(it, maxlen=0) or None if n is None
               else next(islice(it, n, n), None))                                  

def update_d(d, **kwargs):
    d.update(kwargs)
    return d

好的,现在让我们从 t = 'a', 'b', 'c', '_can' 中任意选择 tuple 并执行此操作:

MyClass = type('MyClass', tuple(),
               update_d({k      : None for k in t},
                        __init__=lambda self, **kwargs: it_consumes(
                                     setattr(self, k, v) 
                                     for k,v in kwargs.items())))

然后可以这样使用:

obj = MyClass(a=5, b=6, _can='haz')
print('obj._can:', obj._can)