使用 Python 创建 JSON
Use Python for Creating JSON
我想使用 Python 创建 JSON。
由于我找不到可以帮助我的库,我想知道是否可以检查 Python 文件中 类 的顺序?
例子
# example.py
class Foo:
pass
class Bar:
pass
如果我导入 example
,我想知道 类 的顺序。在这种情况下,它是 [Foo, Bar] 而不是 [Bar, Foo]。
这可能吗?如果"yes",怎么办?
背景
我对 yaml/json 不满意。我有一个模糊的想法,通过 Python 类 创建配置(仅 类,不实例化对象)。
欢迎提供有助于我实现目标的答案(使用易于使用且有趣的工具创建 JSON)。
你可以用metaclass来记录每个class的创建时间,之后再根据它对class进行排序。
这适用于 python2:
class CreationTimeMetaClass(type):
creation_index = 0
def __new__(cls, clsname, bases, dct):
dct['__creation_index__'] = cls.creation_index
cls.creation_index += 1
return type.__new__(cls, clsname, bases, dct)
__metaclass__ = CreationTimeMetaClass
class Foo: pass
class Bar: pass
classes = [ cls for cls in globals().values() if hasattr(cls, '__creation_index__') ]
print(sorted(classes, key = lambda cls: cls.__creation_index__))
inspect 模块可以告诉 class 声明的行号:
import inspect
def get_classes(module):
for name, value in inspect.getmembers(module):
if inspect.isclass(value):
_, line = inspect.getsourcelines(value)
yield line, name
所以下面的代码:
import example
for line, name in sorted(get_classes(example)):
print line, name
打印:
2 Foo
5 Bar
(将我的评论移至答案)
这是一个很棒的模糊想法。您应该 给 Figura 一个机会! 它正是这样做的。
(完全披露:我是 Figura 的作者。)
我应该指出声明的顺序在 Figura 中没有保留,在 json 中也没有。
我不确定 YAML 中的顺序保留,但我确实在 wikipedia 上找到了这个:
... according to the specification, mapping keys do not have an order
特定的 YAML 解析器可能会维护顺序,尽管它们不是必需的。
标准 json 模块易于使用,非常适合读写 JSON 配置文件。
对象在 JSON 结构中未排序,但 lists/arrays 是排序的,因此将依赖于顺序的信息放入列表中。
我已经使用 classes 作为配置工具,我所做的是从一个由特定 class 变量定制的基础 class 派生它们。通过像这样使用 class,我不需要工厂 class。例如:
from .artifact import Application
class TempLogger(Application): partno='03459'; path='c:/apps/templog.exe'; flag=True
class GUIDisplay(Application): partno='03821'; path='c:/apps/displayer.exe'; flag=False
在安装脚本中
from .install import Installer
import app_configs
installer = Installer(apps=(TempLogger(), GUIDisplay()))
installer.baseline('1.4.3.3475')
print installer.versions()
print installer.bill_of_materials()
人们应该使用正确的工具来完成这项工作,因此如果您需要订购,python class 这些工具可能不是正确的工具。
我用来创建 JSON 文件的另一个 python 工具是 Mako 模板系统。这是非常强大的。我们用它来将 IP 地址等变量填充到静态 JSON 文件中,然后由 C++ 程序读取这些文件。
首先,据我所知,您可以做两件事...
- 继续追求使用Python源文件作为配置文件。 (我不推荐这个,类似于用推土机打钉子或者把a shotgun转成轮子)
为配置文件切换到类似 TOML, JSON or YAML 的内容,这些文件专为作业而设计。
JSON 或 YAML 中没有任何内容阻止它们保存 "ordered" 键值对。 Python 的 dict
数据类型默认是无序的(至少到 3.5),list
数据类型是有序的。使用默认加载器时,它们分别直接映射到 JSON 中的对象和数组。反序列化它们时只需使用 Python 的 OrderedDict
之类的东西,瞧,你保留了顺序!
除此之外,如果您真的想要使用 Python 源文件进行配置,我建议尝试使用 ast
模块。抽象语法树是语法级别分析的强大工具。
我编写了一个用于从文件中提取 class 行号和名称的快速脚本。
您(或真正的任何人)可以使用它或将其扩展到更广泛的范围,并根据需要进行更多检查。
import sys
import ast
import json
class ClassNodeVisitor(ast.NodeVisitor):
def __init__(self):
super(ClassNodeVisitor, self).__init__()
self.class_defs = []
def visit(self, node):
super(ClassNodeVisitor, self).visit(node)
return self.class_defs
def visit_ClassDef(self, node):
self.class_defs.append(node)
def read_file(fpath):
with open(fpath) as f:
return f.read()
def get_classes_from_text(text):
try:
tree = ast.parse(text)
except Exception as e:
raise e
class_extractor = ClassNodeVisitor()
li = []
for definition in class_extractor.visit(tree):
li.append([definition.lineno, definition.name])
return li
def main():
fpath = "/tmp/input_file.py"
try:
text = read_file(fpath)
except Exception as e:
print("Could not load file due to " + repr(e))
return 1
print(json.dumps(get_classes_from_text(text), indent=4))
if __name__ == '__main__':
sys.exit(main())
这是以下文件的示例 运行:
input_file.py
:
class Foo:
pass
class Bar:
pass
输出:
$ py_to_json.py input_file.py
[
[
1,
"Foo"
],
[
5,
"Bar"
]
]
If I import example
,
如果您要导入模块,example
模块位于导入路径中。导入就是执行anyPython模块中的example
代码。这是一个相当大的安全漏洞——您在与应用程序其余部分相同的上下文中加载用户可编辑的文件。
我不确定这是否回答了您的问题,但它可能相关。看看优秀的 attrs 模块。它非常适合创建 类 用作数据类型。
这是来自 glyph's 博客(Twisted Python 的创建者)的示例:
import attr
@attr.s
class Point3D(object):
x = attr.ib()
y = attr.ib()
z = attr.ib()
它节省了您编写大量样板代码的时间 - 您可以免费获得 str
表示和比较之类的东西,并且该模块有一个方便的 asdict
函数,您可以将其传递给 json
图书馆:
>>> p = Point3D(1, 2, 3)
>>> str(p)
'Point3D(x=1, y=2, z=3)'
>>> p == Point3D(1, 2, 3)
True
>>> json.dumps(attr.asdict(p))
'{"y": 2, "x": 1, "z": 3}'
该模块使用了一种奇怪的命名约定,但将 attr.s
读作 "attrs",将 attr.ib
读作 "attrib",你会没事的。
我假设既然您关心保留 class-定义顺序,您也关心保留每个定义中的 顺序class.
值得指出的是,现在 python、since python3.6.
中的默认行为
另见 PEP 520:保留 Class 属性定义顺序。
刚刚谈到关于从 python 创建 JSON 的要点。有一个名为 jsonpickle 的出色库,可让您将 python 个对象转储到 json。 (单独使用或与此处提到的其他方法一起使用,你可能会得到你想要的)
我想使用 Python 创建 JSON。
由于我找不到可以帮助我的库,我想知道是否可以检查 Python 文件中 类 的顺序?
例子
# example.py
class Foo:
pass
class Bar:
pass
如果我导入 example
,我想知道 类 的顺序。在这种情况下,它是 [Foo, Bar] 而不是 [Bar, Foo]。
这可能吗?如果"yes",怎么办?
背景
我对 yaml/json 不满意。我有一个模糊的想法,通过 Python 类 创建配置(仅 类,不实例化对象)。
欢迎提供有助于我实现目标的答案(使用易于使用且有趣的工具创建 JSON)。
你可以用metaclass来记录每个class的创建时间,之后再根据它对class进行排序。
这适用于 python2:
class CreationTimeMetaClass(type):
creation_index = 0
def __new__(cls, clsname, bases, dct):
dct['__creation_index__'] = cls.creation_index
cls.creation_index += 1
return type.__new__(cls, clsname, bases, dct)
__metaclass__ = CreationTimeMetaClass
class Foo: pass
class Bar: pass
classes = [ cls for cls in globals().values() if hasattr(cls, '__creation_index__') ]
print(sorted(classes, key = lambda cls: cls.__creation_index__))
inspect 模块可以告诉 class 声明的行号:
import inspect
def get_classes(module):
for name, value in inspect.getmembers(module):
if inspect.isclass(value):
_, line = inspect.getsourcelines(value)
yield line, name
所以下面的代码:
import example
for line, name in sorted(get_classes(example)):
print line, name
打印:
2 Foo
5 Bar
(将我的评论移至答案)
这是一个很棒的模糊想法。您应该 给 Figura 一个机会! 它正是这样做的。
(完全披露:我是 Figura 的作者。)
我应该指出声明的顺序在 Figura 中没有保留,在 json 中也没有。
我不确定 YAML 中的顺序保留,但我确实在 wikipedia 上找到了这个:
... according to the specification, mapping keys do not have an order
特定的 YAML 解析器可能会维护顺序,尽管它们不是必需的。
标准 json 模块易于使用,非常适合读写 JSON 配置文件。
对象在 JSON 结构中未排序,但 lists/arrays 是排序的,因此将依赖于顺序的信息放入列表中。
我已经使用 classes 作为配置工具,我所做的是从一个由特定 class 变量定制的基础 class 派生它们。通过像这样使用 class,我不需要工厂 class。例如:
from .artifact import Application
class TempLogger(Application): partno='03459'; path='c:/apps/templog.exe'; flag=True
class GUIDisplay(Application): partno='03821'; path='c:/apps/displayer.exe'; flag=False
在安装脚本中
from .install import Installer
import app_configs
installer = Installer(apps=(TempLogger(), GUIDisplay()))
installer.baseline('1.4.3.3475')
print installer.versions()
print installer.bill_of_materials()
人们应该使用正确的工具来完成这项工作,因此如果您需要订购,python class 这些工具可能不是正确的工具。
我用来创建 JSON 文件的另一个 python 工具是 Mako 模板系统。这是非常强大的。我们用它来将 IP 地址等变量填充到静态 JSON 文件中,然后由 C++ 程序读取这些文件。
首先,据我所知,您可以做两件事...
- 继续追求使用Python源文件作为配置文件。 (我不推荐这个,类似于用推土机打钉子或者把a shotgun转成轮子)
为配置文件切换到类似 TOML, JSON or YAML 的内容,这些文件专为作业而设计。
JSON 或 YAML 中没有任何内容阻止它们保存 "ordered" 键值对。 Python 的
dict
数据类型默认是无序的(至少到 3.5),list
数据类型是有序的。使用默认加载器时,它们分别直接映射到 JSON 中的对象和数组。反序列化它们时只需使用 Python 的OrderedDict
之类的东西,瞧,你保留了顺序!
除此之外,如果您真的想要使用 Python 源文件进行配置,我建议尝试使用 ast
模块。抽象语法树是语法级别分析的强大工具。
我编写了一个用于从文件中提取 class 行号和名称的快速脚本。
您(或真正的任何人)可以使用它或将其扩展到更广泛的范围,并根据需要进行更多检查。
import sys
import ast
import json
class ClassNodeVisitor(ast.NodeVisitor):
def __init__(self):
super(ClassNodeVisitor, self).__init__()
self.class_defs = []
def visit(self, node):
super(ClassNodeVisitor, self).visit(node)
return self.class_defs
def visit_ClassDef(self, node):
self.class_defs.append(node)
def read_file(fpath):
with open(fpath) as f:
return f.read()
def get_classes_from_text(text):
try:
tree = ast.parse(text)
except Exception as e:
raise e
class_extractor = ClassNodeVisitor()
li = []
for definition in class_extractor.visit(tree):
li.append([definition.lineno, definition.name])
return li
def main():
fpath = "/tmp/input_file.py"
try:
text = read_file(fpath)
except Exception as e:
print("Could not load file due to " + repr(e))
return 1
print(json.dumps(get_classes_from_text(text), indent=4))
if __name__ == '__main__':
sys.exit(main())
这是以下文件的示例 运行:
input_file.py
:
class Foo:
pass
class Bar:
pass
输出:
$ py_to_json.py input_file.py
[
[
1,
"Foo"
],
[
5,
"Bar"
]
]
If I import
example
,
如果您要导入模块,example
模块位于导入路径中。导入就是执行anyPython模块中的example
代码。这是一个相当大的安全漏洞——您在与应用程序其余部分相同的上下文中加载用户可编辑的文件。
我不确定这是否回答了您的问题,但它可能相关。看看优秀的 attrs 模块。它非常适合创建 类 用作数据类型。
这是来自 glyph's 博客(Twisted Python 的创建者)的示例:
import attr
@attr.s
class Point3D(object):
x = attr.ib()
y = attr.ib()
z = attr.ib()
它节省了您编写大量样板代码的时间 - 您可以免费获得 str
表示和比较之类的东西,并且该模块有一个方便的 asdict
函数,您可以将其传递给 json
图书馆:
>>> p = Point3D(1, 2, 3)
>>> str(p)
'Point3D(x=1, y=2, z=3)'
>>> p == Point3D(1, 2, 3)
True
>>> json.dumps(attr.asdict(p))
'{"y": 2, "x": 1, "z": 3}'
该模块使用了一种奇怪的命名约定,但将 attr.s
读作 "attrs",将 attr.ib
读作 "attrib",你会没事的。
我假设既然您关心保留 class-定义顺序,您也关心保留每个定义中的 顺序class.
值得指出的是,现在 python、since python3.6.
中的默认行为另见 PEP 520:保留 Class 属性定义顺序。
刚刚谈到关于从 python 创建 JSON 的要点。有一个名为 jsonpickle 的出色库,可让您将 python 个对象转储到 json。 (单独使用或与此处提到的其他方法一起使用,你可能会得到你想要的)