Python 使用namedtuple嵌套
我在获取python中所需格式的数据时遇到困难 基本上,我有一个程序,读取二进制数据,并提供打印和分析所述数据的功能 我的数据有主标题和副标题,可以是任意数量的不同数据类型 我希望能够访问我的数据,例如:Python 使用namedtuple嵌套,python,namedtuple,Python,Namedtuple,我在获取python中所需格式的数据时遇到困难 基本上,我有一个程序,读取二进制数据,并提供打印和分析所述数据的功能 我的数据有主标题和副标题,可以是任意数量的不同数据类型 我希望能够访问我的数据,例如: >>> a = myDatafile.readit() >>> a.elements.hydrogen.distributionfunction (a big array) >>> a.elements.hydrogen.mass 1 &g
>>> a = myDatafile.readit()
>>> a.elements.hydrogen.distributionfunction
(a big array)
>>> a.elements.hydrogen.mass
1
>>> a.elements.carbon.mass
12
for i in range(0,self.nelements):
self.elements[i] = namedtuple('details',['ux','uy','uz','mass','distributionfunction'])
但直到运行时我才知道原子的名字
我尝试过使用namedtuple,例如在我读入所有atom名称之后:
self.elements = namedtuple('elements',elementlist)
其中elementlist是字符串列表,例如('hydrogen','carbon')。但问题是,我无法使用以下示例嵌套这些:
>>> a = myDatafile.readit()
>>> a.elements.hydrogen.distributionfunction
(a big array)
>>> a.elements.hydrogen.mass
1
>>> a.elements.carbon.mass
12
for i in range(0,self.nelements):
self.elements[i] = namedtuple('details',['ux','uy','uz','mass','distributionfunction'])
然后能够通过例如
self.elements.electron.distributionfunction.
也许我完全错了。我对python相当缺乏经验。我知道,如果我不介意动态命名变量,这将很容易做到
我希望我已经清楚地表明了我想要实现的目标 在不了解您的数据的情况下,我们只能给出一个通用的解决方案 考虑到前两行包含标题和副标题,您以某种方式确定了层次结构。您所要做的就是创建一个分层字典 例如,扩展您的示例
data.elements.hydrogen.distributionfunction
data.elements.nitrogen.xyzfunction
data.elements.nitrogen.distributionfunction
data.compound.water.distributionfunction
data.compound.hcl.xyzfunction
因此,我们必须创建一个这样的词典
{'data':{'elements':{'hydrogen':{'distributionfunction':<something>}
'nitrogen':{'xyzfunction':<something>,
'distributionfunction':<something>}
}
compound:{'water':{'distributionfunction':<something>}
'hcl':{'xyzfunction':<something>}
}
}
}
如果您的元素名是动态的,并且是在运行时从数据中获得的,那么您可以将它们分配给dict并进行如下访问
elements['hydrogen'].mass
但是如果您想要点符号,您可以在运行时创建属性,例如
from collections import namedtuple
class Elements(object):
def add_element(self, elementname, element):
setattr(self, elementname, element)
Element = namedtuple('Element', ['ux','uy','uz','mass','distributionfunction'])
elements = Elements()
for data in [('hydrogen',1,1,1,1,1), ('helium',2,2,2,2,2), ('carbon',3,3,3,3,3)]:
elementname = data[0]
element = Element._make(data[1:])
elements.add_element(elementname, element)
print elements.hydrogen.mass
print elements.carbon.distributionfunction
这里我假设您拥有的数据,但是对于任何其他格式的数据,您都可以使用类似的技巧这里有一种从嵌套数据递归创建命名耦合的方法
from collections import Mapping, namedtuple
def namedtuplify(mapping, name='NT'): # thank you https://gist.github.com/hangtwenty/5960435
""" Convert mappings to namedtuples recursively. """
if isinstance(mapping, Mapping):
for key, value in list(mapping.items()):
mapping[key] = namedtuplify(value)
return namedtuple_wrapper(name, **mapping)
elif isinstance(mapping, list):
return [namedtuplify(item) for item in mapping]
return mapping
def namedtuple_wrapper(name, **kwargs):
wrap = namedtuple(name, kwargs)
return wrap(**kwargs)
stuff = {'data': {'elements': {'hydrogen': {'distributionfunction': 'foo'},
'nitrogen': {'xyzfunction': 'bar',
'distributionfunction': 'baz'}
},
'compound': {'water': {'distributionfunction': 'lorem'},
'hcl': {'xyzfunction': 'ipsum'}}}
}
example = namedtuplify(stuff)
example.data.elements.hydrogen.distributionfunction # 'foo'
我对嵌套的json也有同样的问题,但需要能够用pickle序列化输出,而pickle不喜欢动态创建对象 我已经采纳了@bren的答案并对其进行了增强,以便生成的结构可以通过pickle序列化。您必须将对创建的每个结构的引用保存到全局变量,以便pickle可以对它们进行跟踪
##############################################
class Json2Struct:
'''
Convert mappings to nested namedtuples
Usage:
jStruct = Json2Struct('JS').json2Struct(json)
'''
##############################################
def __init__(self, name):
self.namePrefix = name
self.nameSuffix = 0
def json2Struct(self, jsonObj): # thank you https://gist.github.com/hangtwenty/5960435
"""
Convert mappings to namedtuples recursively.
"""
if isinstance(jsonObj, Mapping):
for key, value in list(jsonObj.items()):
jsonObj[key] = self.json2Struct(value)
return self.namedtuple_wrapper(**jsonObj)
elif isinstance(jsonObj, list):
return [self.json2Struct(item) for item in jsonObj]
return jsonObj
def namedtuple_wrapper(self, **kwargs):
self.nameSuffix += 1
name = self.namePrefix + str(self.nameSuffix)
Jstruct = namedtuple(name, kwargs)
globals()[name] = Jstruct
return Jstruct(**kwargs)
下面的示例应如下所示,并且可以序列化:
stuff = {'data': {'elements': {'hydrogen': {'distributionfunction': 'foo'},
'nitrogen': {'xyzfunction': 'bar',
'distributionfunction': 'baz'}
},
'compound': {'water': {'distributionfunction': 'lorem'},
'hcl': {'xyzfunction': 'ipsum'}}}
}
example = Json2Struct('JS').json2Struct(stuff)
example.data.elements.hydrogen.distributionfunction # 'foo'
你能给我们看一下样本数据吗?@abhijit它相当复杂,是作为二进制数据读入的。化学元素的数量因文件而异,但每个元素都有:“名称(字符串)质量(双精度)电荷(双精度)三维速度网格(3*n*双精度)相位空间网格(n^6*双精度)”我有一个类,它读取二进制数并将其读入变量,但是我在创建能够以我描述的方式访问的数据结构时遇到了问题。感谢您的快速响应!这对任何数据类型都有效吗?例如,如果某些字段是字符串,而某些字段是numpy数组?那么我可以做“distributionfunction”:self.dist1,其中self.dist1是一个3d numpy数组吗?再次感谢!我非常感谢你的时间!正如您在示例中看到的,我只希望键是字符串(可以散列)。只要键是可散列的,您就可以存储值中的任何内容,任何数据类型、函数、对象,以及您想要的任何内容。这非常棒。唯一的问题是它不会与pickle序列化,因为pickle无法跟踪结构。我已经做了一个增强版本,它可以。我将在下面发布。