在Julia中的链式变量赋值

huangapple go评论48阅读模式
英文:

Chained variable assignment in Julia

问题

我对Julia如何处理以下代码块感到困惑:

a = [1,2,3]
a .= a/2 .= o = a .* 2

对于'a'和'o'的输出都是[2,4,6]。然而,我不明白为什么'a'的结果与我使用a .= a*2的结果相同。a/2被视为变量并传递给数组[2,4,6](即a*2的结果)吗?然后这个“变量”a/2被传递给a吗?我本来希望a保持为[1,2,3]。我不确定Julia是否以特定顺序执行这些操作。

英文:

I'm puzzled by how Julia handles the block of code below:

a = [1,2,3]
a .= a/2 .= o = a .* 2

The output for both 'a' and 'o' is [2,4,6]. However, I don't understand why the result for 'a' is the same as if I had used a .= a*2. Is a/2 treated as a variable and passed the array [2,4,6] (the result of a*2)? And then this "variable" a/2 is passed to a? I would have expected a to have stayed as [1,2,3]. I'm uncertain as to whether Julia executes these operations in a specific order.

答案1

得分: 2

表达式 a / 2 创建了一个新的数组,最初包含您期望的值 ([1,2,3]),然而,该数组的内容立即被右侧数组的广播赋值所覆盖。

让我们分解整个表达式,Julia 可以帮助我们:

julia> :(a .= a/2 .= o = a .* 2)
:(a .= (a / 2 .= (o = a .* 2)))

通过查看在打印 Expr 时插入的括号,我们可以更清楚地看到子表达式。正如您所看到的,顶部表达式是 a .= (右侧所有内容的结果)

让我们在 REPL 中对其进行评估:

julia> o = a .* 2
3-element Vector{Int64}:
 2
 4
 6
   
julia> a / 2 .= (o = a .* 2)
3-element Vector{Float64}:
 2.0
 4.0
 6.0
                  
julia> a .= (a / 2 .= (o = a .* 2))
3-element Vector{Int64}:
 2
 4
 6

正如您所看到的,由 a / 2 创建的数组是 Float64 数组,因此在放入 a 时被转换成 Int64,然后再次转换回来。

我们可以通过使用 Meta.show_sexpr 使右侧表达式更加明确。

julia> :(a/2 .= o = a .* 2) |> Meta.show_sexpr
(:.=, (:call, :/, :a, 2), (:(=), :o, (:call, :.*, :a, 2)))

让我们为清晰起见添加一些空格:

(:.=,
  (:call, :/, :a, 2),
  (:(=),
    :o,
    (:call, :.*, :a, 2)))

因此,此表达式是将值广播分配给调用参数 a2 上的 / 函数返回的值。分配的值是赋值 o = a * 2 返回的值。

英文:

The expression a / 2 creates a new array which initially contains the values you expect ([1,2,3]) however the contents of that array are immediately overwritten by a broadcast assignment with the contents in the right hand side array.

Let's break down the entire expression, Julia can help us:

julia> :(a .= a/2 .= o = a .* 2)
:(a .= (a / 2 .= (o = a .* 2)))

By looking at the parentheses inserted when the Expr is printed we see the subexpressions a bit more clearly. As you can see the top expression is a .= (result of everything on RHS).

Let's evaluate it in the REPL:

julia> o = a .* 2
3-element Vector{Int64}:
 2
 4
 6
   
julia> a / 2 .= (o = a .* 2)
3-element Vector{Float64}:
 2.0
 4.0
 6.0
                  
julia> a .= (a / 2 .= (o = a .* 2))
3-element Vector{Int64}:
 2
 4
 6

As you can see the array created by a / 2 is a Float64 array and the values are therefore converted and then converted back to Int64 when put into a.

We can make the right hand side expression even more explicit by using Meta.show_sexpr.

julia> :(a/2 .= o = a .* 2) |> Meta.show_sexpr
(:.=, (:call, :/, :a, 2), (:(=), :o, (:call, :.*, :a, 2)))

let's add some whitespace for clarity:

(:.=,
  (:call, :/, :a, 2),
  (:(=),
    :o,
    (:call, :.*, :a, 2)))

so this expression is broadcast assigning to the value that is returned by calling the / function on the arguments a and 2. The value that is assigned is what the assignment o = a * 2 returns.

huangapple
  • 本文由 发表于 2023年6月16日 01:16:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76484066.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定