glom是一种用Python处理数据的新方法,具有以下特点:

  • 嵌套结构并基于路径访问
  • 使用轻量级的Pythonic规范进行声明性数据转换
  • 可读、有意义的错误信息
  • 内置数据探测和调试功能

在上一篇博文当中,简要记录一下glom的使用,以及一些它的特性!接下来,将记录一下glom更多方法的使用:

glom.glom(target, spec, **kwargs)

从给定的target,根据spec声明规范构造一个值

反问嵌套数据,我们可以这样:

from glom import glom

target = {"a": {"b": "c"}}
print(glom(target, "a.b"))      # c

这里的规范一个表示路径的字符串。下面我们来构建或重构更加复杂的嵌套数据:

from glom import glom

target = {"a": 1, "b": {"c": 1, "d": 2}, "c": [0, 1, 2]}
spec = {"a": "a", "b": "b.c", "c": ("c", [lambda x: x * 2])}
print(glom(target, spec))

######## 打印结果如下 ########
{'a': 1, 'b': 1, 'c': [0, 2, 4]}

glom还支持一个default参数用于设置默认值。如果设置了此值,那么glom操作失败之后将会自动返回默认值,类似dict.get(),如下:

spec = "a.xx"
print(glom(target, spec, default=1234))     # 1234

在target数据中可以看到,并没有哪个路径为“a.xx”,所以glom返回默认值为1234。

另外,我们还可以指定skip_exc参数来控制哪些错误应该被忽略,如下:

print(glom({}, lambda x: 100 / len(x), default=0, skip_exc=ZeroDivisionError))          # 0

glom支持的参数说明如下:

  • target:glom将在其上运行的对象
  • spec:以dictlisttuplestring,或其他glom结构,以及这些结构的任何组合
  • default:出现异常时,将返回该值
  • skip_exc:一个可选异常或可忽略的异常元组
  • scope:可以通过glom-spec中的S访问的其他数据(不是特别理解!!)

glom.Path(*path_parts)

a.b.c此类常规样式语法不起作用或不可取时,Path对象指定显示路径。使用它来包装整数、日期时间和其他有效键,以及带有不应展开的点的字符串:

from glom import glom, Path

target = {"a": {"b": 1, "c.d": 2, 2: 3}}
print(glom(target, Path("a", "c.d")))       # 2
print(glom(target, Path("a", 2)))           # 3

在上面的栗子,如果使用a.c.da.2来进行匹配获取的话,将会发生错误!

Path对象可以将其他Path对象或者T对象连接到一起:

>>> from glom import Path, T
>>> Path(Path("a", 1), Path("b", 2))
Path("a", 1, "b", 2)
>>> Path(T["a"], T["b"])
T["a"]["b"]

Path对象还支持索引和切片,每次反问都是返回一个新的Path对象:

>>> from glom import Path
>>> p = Path("a", "b", "c", "d")
>>> p[0]
Path("a")
>>> p[0:2]
Path("a", "b")

glom.Literal(value)

Literal对象在少数情况下指定文字值,而不应将部分规范解释为glommable subspec。无论在规范中遇到Literal对象,它都会被包含中的值替换:

from glom import glom, Literal

target = {"a": {"b": "c"}}
spec = {"name": "a.b", "age": Literal(18)}
print(glom(target, spec))

######## 打印结果如下 ########
{'name': 'c', 'age': 18}

glom.Spec(spec, scope=None)

具有类似于Literal的用法,也具有glom函数的操作,如下:

from glom import glom, Spec

target = {"a": {"b": "c"}, "d": 1}
spec = {"a": "a.b", "s": Spec("d")}
print(glom(target, spec))           # {'a': 'c', 's': 1}

Spec还有自带的glom()方法,用法如下:

from glom import Spec

target = {"a": {"b": "c"}, "d": 1}
s = Spec("a.b")
print(s.glom(target))               # c

glom.Coalesce(*subspecs, **kwargs)

Coalesce是一个glom结构,允许你为你的子目录指定回退行为。但是,如果有一组数据,同时满足Coalesce中的所有匹配,那么它将会依次匹配,直到满足匹配为止!

from glom import glom, Coalesce

target = {"a": {"b": "c"}, "d": 1}
spec = {"result": Coalesce("a.c", "a.b")}
print(glom(target, spec))           # {"result": "c"}

同样,Coalesce也可以指定default参数来设置默认值,如下:

from glom import glom, Coalesce

target = {"a": {"b": "c"}, "d": 1}
spec = {"result": Coalesce("a.c", "a.d", default=0)}
print(glom(target, spec))           # {"result": 0}

Coalesce支持的参数说明如下:

  • subspecs:一个或多个glommable规范
  • default:默认值,如果subspecs都未曾匹配将返回默认值
  • default_factory:一个执行的函数,作为默认值返回
  • skip:表示要忽略的值、值元组或者匿名函数
  • skip_exc:一个可选异常或可忽略的异常元组

default_factory参数用法如下:

from glom import glom, Coalesce

def default_factory():
    return 0

target = {"a": {"b": "c"}, "d": 1}
spec = {"result": Coalesce("a.c", "a.d", default_factory=default_factory)}
print(glom(target, spec))           # {"result": 0}

skip参数用法如下:

from glom import glom, Coalesce

target = {"a": {"b": "c"}, "d": 1}
spec = {"result": Coalesce("a.b", "d", skip="c")}
print(glom(target, spec))           # {"result": 1}


target = {"a": {"b": "c"}, "d": 1}
spec = {"result": Coalesce("a.b", "d", skip=("c", ))}
print(glom(target, spec))           # {"result": 1}


target = {"a": {"b": "c"}, "d": 1}
spec = {"result": Coalesce("a.b", skip=lambda x: x, default=0)}
print(glom(target, spec))           # {"result": 0}

从上面三个栗子中可以看到,第一个匹配条件都是符合的,但是因为有skip参数,而且值正好与skip中所设置的符合,所以将会往下匹配!直到不符合情况为止!skip_exc用法与glom()中的skip_exc参数用法一致!

glom.OMIT

取消赋值操作

使用如下:

from glom import glom, OMIT

target = {"a": "b"}
spec = {"result": lambda x: x["a"] if x["a"] == "a" else OMIT}
print(glom(target, spec))           # {}

glom.assign(obj, path, val)

修改嵌套数据的结构

使用如下:

from glom import glom, assign

target = {"a": [{"name": "laozhang"}]}
_ = assign(target, "a.0.name", "laowang")
print(target)                       # {"a": [{"name": "laowang"}]}

a.0.name其中0表示列表中的第一个元素

glom.Assign(path, val)

当不需要复制时,Assign可用于对大型数据结构进行临时修改:

from glom import glom, Assign

target = {"a": {}}
spec = Assign("a.b", 1)
_ = glom(target, spec)
print(target)                       # {"a": {"b": 1}}

要分配的值也可以是一个Spec,这对于复制数据结构中的值非常有用:

from glom import glom, Assin, Spec

target = {"a": {"b": "c"}}
spec = Assign("a.c", Spec("a.b"))
_ = glom(target, spec)
print(target)                       # {"a": {"b": "c", "c": "c"}}