Як я можу отримати аргументи ключових слів із поля заплямованих кваргів?


9

Якщо у мене є такий підпис функції f(args...; kwargs...), як я можу отримати певне ключове слово kwargs? Наївно вводити текст kwargs.xне працює:

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

Це запитання з’явилося на каналі JuliaLang Slack в #helpdesk. Для автоматичного запрошення на дуже корисну прогулку Джулії просто заповніть https://slackinvite.julialang.org

Відповіді:


10

Причина цього відбувається в тому, що аргументовані аргументи ключових слів за замовчуванням не зберігаються у названому кортежі. Ми можемо бачити, як вони зберігаються так:

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}}}

Таким чином, заплетені кварги замість цього зберігаються як якийсь об’єкт ітератора. Однак ми можемо легко перетворити цей kwargsітератор в NamedTuple так: (;kwargs...)і потім отримати доступ до нього так, як ми очікували, щоб ваш приклад перетворився на

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

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

Звичайно, більш ідіоматичним способом зробити це було б замість цього записати функцію як

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

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

але це передбачає, що ви знаєте ім'я, до якого ви хочете отримати доступ ( x) під час написання функції.


Короткий посилання: Якщо ми повернемося до нашого прикладу g(;kwargs...) = kwargs, ми можемо запитати імена полів об’єкта ітератора, який було повернуто так:

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

Гм, що це за dataполе?

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

Ага! тому ми можемо насправді отримати кворгів як названий кортеж, використовуючи це, тобто f(;kwargs...) = kwargs.data.xпрацював би, але я б не рекомендував цей підхід, оскільки він, мабуть, покладається на недокументовану поведінку, тому це може бути просто деталізацією щодо впровадження, яка не гарантує стабільності. у версіях Джулії.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.