2013-04-01 16 views
18

Tôi sẽ sử dụng Python function annotations để chỉ định loại giá trị trả về của một phương pháp nhà máy tĩnh. Tôi hiểu điều này là one of the desired use cases cho chú thích.Tại sao tên của lớp chứa không được nhận dạng là chú thích hàm trả về giá trị?

class Trie: 
    @staticmethod 
    def from_mapping(mapping) -> Trie: 
     # docstrings and initialization ommitted 
     trie = Trie() 
     return trie 

PEP 3107 khẳng định rằng:

Chức năng chú thích là gì khác hơn là một cách để kết hợp biểu Python tùy ý với các bộ phận khác nhau của một hàm tại thời gian biên dịch.

Trie là một biểu thức hợp lệ trong Python, phải không? Python không đồng ý hay đúng hơn, không thể tìm thấy tên:

def from_mapping(mapping) -> Trie:
NameError: name 'Trie' is not defined

Nó đáng chú ý rằng lỗi này không xảy ra nếu một loại cơ bản (như object hoặc int) hoặc loại thư viện chuẩn (chẳng hạn như collections.deque) được chỉ định.

Điều gì gây ra lỗi này và cách khắc phục?

+1

trùng lặp có thể xảy ra của [Làm thế nào để xác định rằng các kiểu trả về của một phương pháp tương tự như lớp chính nó trong python?] (https://stackoverflow.com/questions/33533148/how-do-i-specify-that-the-return-type-of-a-method-is-the-same-as-the- class-itsel) –

Trả lời

10

PEP 484 cung cấp giải pháp chính thức cho điều này dưới dạng forward references.

Khi gợi ý loại chứa tên chưa được xác định, định nghĩa đó có thể được biểu thị dưới dạng chuỗi ký tự, được giải quyết sau.

Trong trường hợp của mã câu hỏi:

class Trie: 
    @staticmethod 
    def from_mapping(mapping) -> Trie: 
     # docstrings and initialization ommitted 
     trie = Trie() 
     return trie 

trở thành:

class Trie: 
    @staticmethod 
    def from_mapping(mapping) -> 'Trie': 
     # docstrings and initialization ommitted 
     trie = Trie() 
     return trie 
+0

Wow, tôi rất ngạc nhiên vì tôi đã bỏ lỡ điều đó - cảm ơn bạn đã đóng góp câu trả lời này. – Adam

12

Trie là biểu thức hợp lệ và đánh giá thành giá trị hiện tại được liên kết với tên tên Trie. Nhưng tên đó chưa được xác định - một đối tượng lớp chỉ bị ràng buộc với tên của nó là sau khi nội dung lớp đã chạy để hoàn thành. Bạn sẽ lưu ý hành vi tương tự trong ví dụ đơn giản hơn nhiều này:

class C: 
    myself = C 
    # or even just 
    C 

Thông thường, cách giải quyết sẽ đặt thuộc tính lớp sau khi lớp được xác định, bên ngoài lớp học. Đây không phải là một lựa chọn thực sự tốt ở đây, mặc dù nó hoạt động. Ngoài ra, bạn có thể sử dụng bất kỳ giá trị giữ chỗ trong định nghĩa ban đầu, sau đó thay thế nó trong __annotations__ (mà là hợp pháp vì nó là một cuốn từ điển thường xuyên):

class C: 
    def f() -> ...: pass 
print(C.f.__annotations__) 
C.f.__annotations__['return'] = C 
print(C.f.__annotations__) 

không cảm thấy khá hacky mặc dù. Tùy thuộc vào trường hợp sử dụng của bạn, thay vào đó, bạn có thể sử dụng đối tượng sentinel (ví dụ: CONTAINING_CLASS = object()) và để giải thích cho bất kỳ điều gì thực sự xử lý chú thích.

+0

Thú vị ... tuy nhiên, tôi có thể sử dụng tên lớp * bên trong * phương pháp tĩnh của tôi. Có phải vì nội dung của hàm chỉ được phân tích cú pháp khi nó được thực hiện, nhưng chữ ký được phân tích cú pháp ngay lập tức sau định nghĩa lớp? Đây là [phần liên quan] (http://docs.python.org/3.3/reference/compound_stmts.html#class-definitions) của tham chiếu ngôn ngữ Python cho bất kỳ ai quan tâm. – Adam

+2

@codesparkle: Phân tích cú pháp tách biệt với việc thực thi. Lỗi xảy ra khi thực thi. Định nghĩa lớp học của bạn, bao gồm chú thích là việc thực thi mã. Tuy nhiên, nội bộ của các hàm không được thực thi (rõ ràng) khi lớp được định nghĩa. –

+0

Làm thế nào về chỉ viết '-> 'trả về Trie'' – jamylak