Cú pháp **kwargs trong định nghĩa hàm chỉ ra rằng trình thông dịch sẽ thu thập tất cả các đối số từ khóa không tương ứng với các tham số được đặt tên khác. Tuy nhiên, Python không giữ nguyên thứ tự mà các đối số từ khóa được thu thập đó được chuyển đến hàm. Trong một số bối cảnh, thứ tự quan trọng. PEP này chỉ ra rằng các đối số từ khóa đã thu thập được hiển thị trong thân hàm dưới dạng ánh xạ có thứ tự
Động lực
Cú pháp **kwargs của Python trong định nghĩa hàm cung cấp một phương tiện mạnh mẽ để xử lý động các đối số từ khóa. Trong một số ứng dụng của cú pháp [xem Trường hợp sử dụng ], ngữ nghĩa được áp dụng cho các đối số từ khóa đã thu thập yêu cầu phải giữ nguyên thứ tự. Không có gì đáng ngạc nhiên, điều này tương tự như cách OrderedDict liên quan đến dict.
Hiện tại, để giữ nguyên thứ tự, bạn phải thực hiện thủ công và tách biệt khỏi lệnh gọi chức năng thực tế. Điều này liên quan đến việc xây dựng một ánh xạ có thứ tự, cho dù là OrderedDict hay có thể lặp lại gồm 2 bộ, sau đó được chuyển dưới dạng một đối số cho hàm. [1]
Với khả năng được mô tả trong PEP này, bản soạn sẵn đó sẽ không còn cần thiết nữa
Để so sánh, hiện tại
kwargs = OrderedDict[] kwargs['eggs'] = ... ... def spam[a, kwargs]: ...
và với đề xuất này
def spam[a, **kwargs]: ...
Nick Coglan, khi nói về một số trường hợp sử dụng, đã tóm tắt rất hay [2]
These *can* all be done today, but *not* by using keyword arguments. In my view, the problem to be addressed is that keyword arguments *look* like they should work for these cases, because they have a definite order in the source code. The only reason they don't work is because the interpreter throws that ordering information away. It's a textbook case of a language feature becoming an attractive nuisance in some circumstances: the simple and obvious solution for the above use cases *doesn't actually work* for reasons that aren't obviously clear if you don't have a firm grasp of Python's admittedly complicated argument handling.
Quan sát này được hỗ trợ bởi sự xuất hiện của đề xuất này trong nhiều năm và nhiều lần mọi người đã bị nhầm lẫn bởi hàm tạo cho OrderedDict. [3] [4] [5]
Trường hợp sử dụng
Như Nick đã lưu ý, hành vi hiện tại của **kwargs là không trực quan trong trường hợp người ta cho rằng trật tự là quan trọng. Ngoài các trường hợp cụ thể hơn được nêu bên dưới, nói chung “bất kỳ điều gì khác mà bạn muốn kiểm soát thứ tự lặp lại cũng như đặt tên và giá trị trường trong một lệnh gọi sẽ có khả năng mang lại lợi ích. ” [6] Điều đó quan trọng trong trường hợp của các nhà máy [e. g. __init__[]] cho các loại được đặt hàng
Tuần tự hóa
Rõ ràng OrderedDict sẽ có lợi [cả __init__[] và update[]] từ kwargs đã đặt hàng. Tuy nhiên, lợi ích cũng mở rộng đến các API tuần tự hóa [2]
In the context of serialisation, one key lesson we have learned is that arbitrary ordering is a problem when you want to minimise spurious diffs, and sorting isn't a simple solution. Tools like doctest don't tolerate spurious diffs at all, but are often amenable to a sorting based answer. The cases where it would be highly desirable to be able use keyword arguments to control the order of display of a collection of key value pairs are ones like: * printing out key:value pairs in CLI output * mapping semantic names to column order in a CSV * serialising attributes and elements in particular orders in XML * serialising map keys in particular orders in human readable formats like JSON and YAML [particularly when they're going to be placed under source control]
gỡ lỗi
Theo lời của Raymond Hettinger [7]
It makes it easier to debug if the arguments show-up in the order they were created. AFAICT, no purpose is served by scrambling them.
Các trường hợp sử dụng khác
- đối tượng giả. [số 8]
- Kiểm soát trình bày đối tượng
- Têntuple thay thế [] nơi có thể chỉ định mặc định
- Chỉ định mức độ ưu tiên của đối số theo thứ tự
mối quan tâm
Màn biểu diễn
Như đã lưu ý, ý tưởng về các đối số từ khóa được sắp xếp đã xuất hiện trong một số trường hợp. Mỗi lần nó được đáp ứng với cùng một phản hồi, cụ thể là việc duy trì thứ tự từ khóa arg sẽ có tác động đủ bất lợi đến hiệu suất lệnh gọi hàm mà nó không đáng làm. Tuy nhiên, Guido lưu ý những điều sau đây [9]
Making **kwds ordered is still open, but requires careful design and implementation to avoid slowing down function calls that don't benefit.
Như sẽ được lưu ý bên dưới, có nhiều cách để giải quyết vấn đề này với chi phí là sự phức tạp gia tăng. Cuối cùng, cách tiếp cận đơn giản nhất là cách có ý nghĩa nhất. đóng gói các đối số từ khóa đã thu thập vào một OrderedDict. Tuy nhiên, nếu không có triển khai C của OrderedDict thì không có nhiều điều để thảo luận. Điều đó đã thay đổi trong Python 3. 5. [10]
Ghi chú. trong Python 3. 6 dict là giữ trật tự. Điều này hầu như loại bỏ những lo ngại về hiệu suất
Các triển khai Python khác
Một vấn đề quan trọng khác cần xem xét là các tính năng mới phải phù hợp với nhiều triển khai Python. Tại một thời điểm nào đó, mỗi người trong số họ sẽ thực hiện các lệnh kwarg. Về vấn đề này, dường như không có vấn đề gì với ý tưởng. [11] Một cuộc khảo sát không chính thức về các triển khai Python chính đã chỉ ra rằng tính năng này sẽ không phải là gánh nặng đáng kể
Sự chỉ rõ
Bắt đầu từ phiên bản 3. 6 Python sẽ giữ nguyên thứ tự của các đối số từ khóa khi được truyền cho một hàm. Để thực hiện điều này, kwargs được thu thập giờ đây sẽ là một ánh xạ có thứ tự. Lưu ý rằng điều này không nhất thiết có nghĩa là OrderedDict. chính tả trong Python 3. 6 hiện đã được đặt hàng, tương tự như PyPy
Điều này sẽ chỉ áp dụng cho các chức năng mà định nghĩa sử dụng cú pháp **kwargs để thu thập các đối số từ khóa không xác định. Chỉ thứ tự của các đối số từ khóa đó sẽ được giữ nguyên
Mối quan hệ với cú pháp **-unpacking
Cú pháp giải nén ** trong các lệnh gọi hàm không có mối liên hệ đặc biệt nào với đề xuất này. Các đối số từ khóa do giải nén cung cấp sẽ được xử lý theo cách chính xác như hiện tại. những tham số phù hợp với các tham số đã xác định sẽ được tập hợp ở đó và phần còn lại sẽ được thu thập vào các kwarg được sắp xếp theo thứ tự [giống như bất kỳ đối số từ khóa chưa từng có nào khác]
Lưu ý rằng việc giải nén ánh xạ có thứ tự không xác định, chẳng hạn như dict, sẽ giữ nguyên thứ tự lặp lại của nó như bình thường. Chỉ là thứ tự sẽ không được xác định. Ánh xạ theo thứ tự mà sau đó các cặp khóa-giá trị đã giải nén sẽ được đóng gói vào đó sẽ không thể cung cấp bất kỳ thứ tự thay thế nào. Điều này không có gì đáng ngạc nhiên
Đã có những cuộc thảo luận ngắn về việc chỉ cần chuyển các ánh xạ này tới các hàm kwargs mà không cần giải nén và đóng gói lại chúng, nhưng điều đó nằm ngoài phạm vi của đề xuất này và có lẽ là một ý tưởng tồi bất kể. [Có một lý do khiến những cuộc thảo luận đó ngắn gọn. ]
Mối quan hệ kiểm tra. Chữ ký
Đối tượng chữ ký không cần thay đổi. Tham số kwargs của kiểm tra. BoundArguments [được trả về bởi Chữ ký. liên kết [] và Chữ ký. bind_partial[]] sẽ thay đổi từ dict thành OrderedDict
C-API
Không thay đổi
cú pháp
Không có cú pháp nào được thêm hoặc thay đổi bởi đề xuất này
Tương thích ngược
Sau đây sẽ thay đổi
- thứ tự lặp lại của kwargs bây giờ sẽ nhất quán [tất nhiên là ngoại trừ trường hợp được mô tả ở trên]
Thực hiện tham khảo
Đối với CPython, không có gì để làm
Phương pháp thay thế
Trang trí từ chối
Điều này giống hệt với đề xuất hiện tại với ngoại lệ là Python cũng sẽ cung cấp một trình trang trí trong functools sẽ khiến các đối số từ khóa đã thu thập được đóng gói vào một lệnh bình thường thay vì một OrderedDict
tiên lượng
Điều này sẽ chỉ cần thiết nếu hiệu suất được xác định là khác biệt đáng kể trong một số trường hợp không phổ biến hoặc có những lo ngại khác về khả năng tương thích ngược mà không thể giải quyết bằng cách khác
Trang trí chọn tham gia
Hiện trạng sẽ không thay đổi. Thay vào đó, Python sẽ cung cấp một trình trang trí trong funcools sẽ đăng ký hoặc đánh dấu hàm được trang trí là một hàm sẽ nhận các đối số từ khóa được sắp xếp. Chi phí hoạt động để kiểm tra chức năng tại thời điểm gọi sẽ là cận biên
tiên lượng
Mặt trái thực sự duy nhất là trong trường hợp các nhà máy sản xuất hàm bao hàm [e. g. công cụ chức năng. một phần và nhiều bộ trang trí] nhằm mục đích duy trì hoàn hảo các đối số từ khóa bằng cách sử dụng kwargs trong định nghĩa trình bao bọc và giải nén kwargs trong lệnh gọi hàm được bao bọc. Mỗi trình bao bọc sẽ phải được cập nhật riêng, mặc dù có funcools. wraps[] làm điều này tự động sẽ giúp
__kworder__
Thứ tự của các đối số từ khóa sẽ được lưu trữ riêng trong một danh sách tại thời điểm gọi. Danh sách sẽ được liên kết với __kworder__ trong hàm local
tiên lượng
Điều này cũng làm phức tạp trường hợp trình bao bọc
Chính tả nhỏ gọn với phép lặp nhanh hơn
Raymond Hettinger đã đưa ra ý tưởng về việc triển khai chính tả sẽ dẫn đến việc duy trì thứ tự chèn trên các ký tự [cho đến lần xóa đầu tiên]. Đây sẽ là một sự phù hợp hoàn hảo cho kwargs. [5]
tiên lượng
Ý tưởng vẫn chưa chắc chắn về cả khả năng tồn tại và khung thời gian
Lưu ý rằng Python 3. 6 hiện có triển khai chính tả này
*** kwargs
Điều này sẽ thêm một biểu mẫu mới vào chữ ký của hàm dưới dạng song song loại trừ lẫn nhau với **kwargs. Cú pháp mới, ***kwargs [lưu ý rằng có ba dấu hoa thị], sẽ chỉ ra rằng kwargs sẽ giữ nguyên thứ tự của các đối số từ khóa
tiên lượng
Cú pháp mới chỉ được thêm vào Python trong những trường hợp nghiêm trọng nhất. Với các giải pháp khả dụng khác, cú pháp mới không chính đáng. Hơn nữa, giống như tất cả các giải pháp chọn tham gia, cú pháp mới sẽ làm phức tạp trường hợp chuyển qua
chú thích
Đây là một biến thể của phương pháp trang trí. Thay vì sử dụng một công cụ trang trí để đánh dấu chức năng, bạn sẽ sử dụng chú thích chức năng trên **kwargs
tiên lượng
Ngoài biến chứng chuyển qua, các chú thích đã không được khuyến khích tích cực trong quá trình phát triển cốt lõi của Python. Việc sử dụng các chú thích để chọn tham gia bảo quản đơn đặt hàng có nguy cơ cản trở việc sử dụng các chú thích ở cấp ứng dụng khác
mệnh lệnh. __gọi món__
các đối tượng dict sẽ có một thuộc tính mới, __order__ sẽ mặc định là Không có và trong trường hợp kwargs, trình thông dịch sẽ sử dụng theo cách tương tự như được mô tả ở trên cho __kworder__
tiên lượng
Điều đó có nghĩa là không ảnh hưởng đến hiệu suất của kwargs nhưng thay đổi sẽ khá xâm phạm [Python sử dụng dict rất nhiều]. Ngoài ra, đối với trường hợp trình bao bọc, trình thông dịch sẽ phải cẩn thận để bảo quản __order__
KWArgsDict. __gọi món__
Điều này cũng giống như dict. ý tưởng __order__, nhưng kwargs sẽ là một thể hiện của lớp con dict tối thiểu mới cung cấp thuộc tính __order__. dict thay vào đó sẽ không thay đổi