Làm cách nào để truy xuất các đối số từ khóa ra khỏi một trường của các kwarg được chia nhỏ?


9

Nếu tôi có một chữ ký hàm như f(args...; kwargs...)thế nào, làm thế nào tôi có thể lấy một từ khóa cụ thể ra khỏi kwargs? Gõ ngây thơ kwargs.xkhông hoạt động:

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

Câu hỏi này đã xuất hiện trên kênh JuliaLang Slack trong #helpdesk. Đối với một lời mời tự động đến slack julia rất hữu ích, chỉ cần điền https://slackinvite.julialang.org

Câu trả lời:


10

Lý do điều này xảy ra là theo mặc định các đối số từ khóa không được lưu trữ trong một tuple có tên. Chúng ta có thể thấy cách chúng được lưu trữ như vậy:

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

Vì vậy, các kwargs được thay thế được lưu trữ dưới dạng một số đối tượng lặp. Tuy nhiên, chúng ta có thể dễ dàng chuyển đổi kwargstrình lặp đó thành NamedTuple như vậy: (;kwargs...)và sau đó truy cập nó theo cách chúng ta mong đợi, vì vậy ví dụ của bạn sẽ chuyển thành

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

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

Tất nhiên, cách thành ngữ hơn để làm điều này sẽ là thay vì viết hàm như

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

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

nhưng điều này giả sử bạn biết tên bạn muốn truy cập ( x) tại thời điểm bạn viết hàm.


Một sidenote ngắn gọn: Nếu chúng ta quay lại ví dụ của g(;kwargs...) = kwargschúng ta, chúng ta có thể yêu cầu tên trường của đối tượng iterator, nó được trả về như vậy:

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

Hừm, datalĩnh vực này là gì?

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

Aha! vì vậy chúng ta thực sự có thể lấy các kwarg như một tuple có tên bằng cách sử dụng, nghĩa là f(;kwargs...) = kwargs.data.xsẽ hiệu quả, nhưng tôi không khuyến nghị cách tiếp cận này vì nó dường như dựa vào hành vi không có giấy tờ, vì vậy nó có thể chỉ là một chi tiết triển khai không được đảm bảo để ổn định trên các phiên bản julia.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.