问题:Julia 中 Python 的 ast.literal_eval() 相当于什么?

Julia 中是否有任何内容相当于由包ast(抽象语法树)提供的 Python 的literal_eval?

其(literal_eval)描述摘要:

此函数仅评估 Python 文字结构:字符串、字节、数字、元组、列表、字典、集合、布尔值和None,并且可用于安全地评估来自不受信任来源的字符串,而无需自己解析值。它不能评估任意复杂的表达式,例如涉及运算符或索引。

解答

没有等价物,尽管您可以通过解析代码然后递归地确保在计算结果表达式中只有某些语法形式来相当容易地编写一个。然而,与许多基本类型及其语法和行为是内置且不可更改的 Python 不同,Julia 的“内置”类型只是用户定义的类型,恰好在系统启动之前定义。让我们探讨一下,例如,当您使用向量字面量语法时会发生什么:

julia> :([1,2,3]) |> dump
Expr
  head: Symbol vect
  args: Array{Any}((3,))
    1: Int64 1
    2: Int64 2
    3: Int64 3
  typ: Any

julia> f() = [1,2,3]
f (generic function with 2 methods)

julia> @code_lowered f()
CodeInfo(:(begin
        nothing
        return (Base.vect)(1, 2, 3)
    end))

julia> methods(Base.vect)
# 3 methods for generic function "vect":
vect() in Base at array.jl:63
vect(X::T...) where T in Base at array.jl:64
vect(X...) in Base at array.jl:67

所以[1,2,3]只是一个语法形式,它被降低为对Base.vect函数的调用,即Base.vect(1,2,3)。现在,我们将来可能会“密封”一些函数,这样就不能添加任何子方法或以任何方式覆盖它们的行为,但目前为某些参数集修改Base.vect的行为是完全可能的:

julia> function Base.vect(a::Int, b::Int, c::Int)
           warn("SURPRISE!")
           return invoke(Base.vect, Tuple{Any,Any,Any}, a, b, c)
       end

julia> [1,2,3]
WARNING: SURPRISE!
3-element Array{Int64,1}:
 1
 2
 3

由于数组文字在 Julia 中是可重载的,因此它并不是真正的纯文字语法。当然,我不建议做我刚才做的事——“惊喜!”不是您想在程序中间看到的东西——但这是可能的,因此从这个问题的意义上讲,语法不是“安全的”。在 Python 或 JavaScript(或大多数脚本语言)中用文字表示的其他一些构造是 Julia 中的显式函数调用,例如构造字典:

julia> Dict(:foo => 1, :bar => 2, :baz => 42)
Dict{Symbol,Int64} with 3 entries:
  :baz => 42
  :bar => 2
  :foo => 1

这只是对带有三个对对象参数的Dict类型的函数调用,根本不是文字语法。a => b对语法本身_也_只是对=>运算符的函数调用的特殊语法,它是Pair类型的别名:

julia> dump(:(a => b))
Expr
  head: Symbol call
  args: Array{Any}((3,))
    1: Symbol =>
    2: Symbol a
    3: Symbol b
  typ: Any

julia> :foo => 1.23
:foo=>1.23

julia> =>
Pair

julia> Pair(:foo, 1.23)
:foo=>1.23

整数文字呢?这些肯定是安全的!嗯,是的,也不是。小整数文字目前是安全的,因为它们在解析器中直接转换为Int值,没有任何可重载的入口点(但是将来可能会改变,允许用户代码选择整数文字的不同行为)。然而,足够大的整数文字被降低为宏调用,例如:

julia> :(18446744073709551616)
:(@int128_str "18446744073709551616")

对于Int64类型来说太大的整数文字被降低为带有包含整数数字的字符串参数的宏调用,允许宏解析字符串并返回适当的整数对象 - 在这种情况下是Int128值 - 被拼接到抽象语法树。但是您可以为这些宏定义新的行为:

julia> macro int128_str(s)
           warn("BIG SUPRISE!")
           9999999999999999
       end    

julia> 18446744073709551616
WARNING: BIG SUPRISE!
9999999999999999

本质上,Julia 没有有意义的“安全文字子集”。从哲学上讲,Julia 与 Python 非常不同:Julia 不是构建一组具有用户定义类型无法访问的特殊功能的固定类型,而是在语言中包含足够强大的机制,使语言可以从自身内部构建——一个过程称为“引导”。这些强大的语言机制对 Julia 程序员和对 Julia 程序员一样可用。这就是 Julia 的大部分灵活性和力量的来源。但是强大的力量带来了巨大的责任和所有这些......所以除非你有一个_really_好的理由,否则不要真正做我在这个答案中所做的任何事情:)

回到最初的问题,使用 Julia 语法为安全的文字对象构造创建解析器的最佳方法是为 Julia 的子集实现解析器,以不能重载的方式赋予文字它们的_通常_含义。例如,这个安全的语法子集可以包括数字文字、字符串文字、数组文字和Dict构造函数。但只使用 JSON 语法并使用 Julia 的JSON 包解析它可能更实用。

Logo

Python社区为您提供最前沿的新闻资讯和知识内容

更多推荐