2015-10-28 17 views
6

Làm cách nào để triển khai toán tử sao đôi tùy chỉnh (**) để giải nén, tương tự như cách __iter__ hoạt động với toán tử đơn sao (*)?Nhà điều hành sao đôi tùy chỉnh cho một lớp học?

Ví dụ:

class PlayerManager(object): 

    def __init__(self, players=None): 
     self.players = players or [] 

    # Made up method to support ** operator 
    def __dict_iter__(self): 
     for player in self.players: 
      yield get_steamid(player), player 

def print_players(**players): 
    print(players) 

player_manager = PlayerManager([list, of, players]) 
print_players(player_manager) 

Output:

{ 
    'STEAM_0:0:02201': <Player object at 0x0000000000>, 
    'STEAM_0:0:10232': <Player object at 0x0000000064>, 
    'STEAM_0:0:73602': <Player object at 0x0000000128> 
} 

Trả lời

13

Như @ShadowRanger nói, triển khai Lập bản đồ. Dưới đây là một ví dụ:

from collections.abc import Mapping 

class Foo(Mapping): 
    def __iter__(self): 
     yield "a" 
     yield "b" 

    def __len__(self): 
     return 2 

    def __getitem__(self, item): 
     return ord(item) 

f = Foo() 

print(*f) 
print(dict(**f)) 

Các đầu ra chương trình:

a b 
{'a': 97, 'b': 98} 
+0

Xuất sắc. Cảm ơn bạn rất nhiều, chưa bao giờ nghe nói về 'Lập bản đồ' trước đây! –

9

Thực hiện Mapping ABC. Về mặt kỹ thuật, các tài liệu ngôn ngữ không chỉ định phương thức Mapping nào được sử dụng, vì vậy giả sử bạn chỉ cần một số tập con được sử dụng bởi việc triển khai hiện tại là một ý tưởng tồi. All it says is:

Nếu cú ​​pháp ** biểu hiện xuất hiện trong lệnh gọi hàm, biểu thức phải đánh giá bản đồ, nội dung được coi là đối số từ khóa bổ sung. Trong trường hợp của một từ khóa xuất hiện trong cả hai biểu thức và như một đối số từ khóa rõ ràng, một ngoại lệ TypeError được nâng lên.

Vì vậy, nếu bạn thực hiện Mapping ABC, bạn chắc chắn có các giao diện đúng, bất kể nó dựa trên .items(), lặp đi lặp lại trực tiếp và __getitem__ cuộc gọi vv

FYI, về kiểm tra, hành vi trong CPython 3.5 chắc chắn phụ thuộc vào cách thực hiện bạn thực hiện Mapping (nếu bạn kế thừa từ dict, nó sử dụng đường dẫn được tối ưu hóa truy cập trực tiếp dict internals, nếu không, nó lặp lại .keys() và tra từng phím khi nó đi). Vì vậy, yeah, không cắt góc, thực hiện toàn bộ ABC. Nhờ mặc định triển khai kế thừa từ Mapping ABC và cha mẹ của nó, điều này có thể được thực hiện với ít nhất là:

class MyMapping(Mapping): 
    def __getitem__(self, key): 
     ... 
    def __iter__(self): 
     ... 
    def __len__(self): 
     ... 

Việc triển khai mặc định bạn kế thừa có thể không tối ưu trong trường hợp cụ thể (ví dụ itemsvalues sẽ làm semi-ác các công cụ liên quan đến việc lặp lại và tra cứu, nơi những người truy cập trực tiếp có thể nhanh hơn tùy thuộc vào nội bộ), vì vậy nếu bạn sử dụng nó cho các mục đích khác, tôi khuyên bạn nên ghi đè những người có phiên bản được tối ưu hóa.

+0

Cảm ơn bạn rất nhiều, tôi chấp nhận câu trả lời @ codeape như nó rõ ràng cho thấy những gì tôi cần phải làm gì để hỗ trợ lớp học của tôi 'cái **' , nhưng tôi đã làm bạn thất vọng! –

+0

@MarkusMeskanen: Lạ. Tôi đã được xây dựng khi bạn đã viết này, nhưng SO đã không thông báo cho tôi (tôi vẫn không có một cảnh báo bình luận cho nó, và đại diện đã không xuất hiện trong vài phút sau khi lá phiếu đã được bỏ). Eh. Bất cứ điều gì. – ShadowRanger

+0

@ShadowRanger: Xảy ra để biết bit CPython nào thực hiện điều này? Tìm cách thêm hỗ trợ cho '**' vào một lớp C-side – Eric

Các vấn đề liên quan