Come posso recuperare gli argomenti delle parole chiave da un campo di kwarg splattati?


9

Se ho una firma di funzione come f(args...; kwargs...), come posso ottenere una parola chiave specifica da kwargs? La digitazione ingenua kwargs.xnon funziona:

julia> f(args...; kwargs...) = kwargs.x
f (generic function with 1 method)

julia> f(x=1)
ERROR: type Pairs has no field x
Stacktrace:
 [1] getproperty(::Base.Iterators.Pairs{Symbol,Int64,Tuple{Symbol},NamedTuple{(:x,),Tuple{Int64}}}, ::Symbol) at ./Base.jl:20
 [2] #f#7(::Base.Iterators.Pairs{Symbol,Int64,Tuple{Symbol},NamedTuple{(:x,),Tuple{Int64}}}, ::typeof(f)) at ./REPL[2]:1
 [3] (::var"#kw##f")(::NamedTuple{(:x,),Tuple{Int64}}, ::typeof(f)) at ./none:0
 [4] top-level scope at REPL[3]:1

Questa domanda è apparsa sul canale JuliaLang Slack nel #helpdesk. Per un invito automatico al molto utile julia slack, compila semplicemente https://slackinvite.julialang.org

Risposte:


10

Il motivo per cui ciò accade è che gli argomenti di parole chiave splattate non sono memorizzati in una tupla nominata per impostazione predefinita. Possiamo vedere come sono memorizzati in questo modo:

julia> g(;kwargs...) = kwargs
g (generic function with 1 method)

julia> g(a=1)
pairs(::NamedTuple) with 1 entry:
  :a => 1

julia> g(a=1) |> typeof
Base.Iterators.Pairs{Symbol,Int64,Tuple{Symbol},NamedTuple{(:a,),Tuple{Int64}}}

Quindi i kwarg splattati vengono invece memorizzati come una sorta di oggetto iteratore. Tuttavia, possiamo facilmente convertire kwargsquell'iteratore in una NamedTuple in questo modo: (;kwargs...)e quindi accedervi come ci aspetteremmo, quindi il tuo esempio si tradurrebbe in

julia> f(args...; kwargs...) = (;kwargs...).x
f (generic function with 1 method)

julia> f(x=1, y=2)
1

Ovviamente, il modo più idiomatico per farlo sarebbe invece scrivere la funzione come

julia> f(args...; x, kwargs...) = x
f (generic function with 1 method)

julia> f(x=1, y=2)
1

ma questo presuppone che tu conosca il nome a cui vuoi accedere ( x) nel momento in cui scrivi la funzione.


Un breve sidenote: se torniamo al nostro esempio di g(;kwargs...) = kwargs, possiamo chiedere i nomi dei campi dell'oggetto iteratore che è stato restituito in questo modo:

julia> g(x=1, y=2) |> typeof |> fieldnames
(:data, :itr)

Hm, che cos'è questo datacampo?

julia> g(x=1, y=2).data
(x = 1, y = 2)

Aha! quindi possiamo effettivamente ottenere i kwarg come tupla nominata usando quello, cioè f(;kwargs...) = kwargs.data.xfunzionerebbe, ma non consiglierei questo approccio poiché sembra basarsi su comportamenti privi di documenti, quindi potrebbe essere un semplice dettaglio di implementazione che non è garantito essere stabile attraverso le versioni di julia.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.