2012-09-16 36 views
14

Giả sử lớp sau đây:tại sao __getitem__ không thể là lớp học?

class Class(object): 
    @classmethod 
    def getitem(*args): 
     print 'getitem %s' % (args,) 
    @classmethod 
    def __getitem__(*args): 
     print '__getitem__ %s' % (args,) 

Phương pháp GetItem cư xử như mong đợi: nó nhận Class như arg đầu tiên, nhưng __getitem__ nhận type như arg đầu tiên:

calling Class.getitem(test) 
getitem (<class '__main__.Class'>, 'test') 

calling obj.getitem(test) 
getitem (<class '__main__.Class'>, 'test') 

calling Class[test] 
'type' object has no attribute '__getitem__' 

calling obj[test] 
__getitem__ (<class '__main__.Class'>, 'test') 

sự kỳ diệu là gì đó đằng sau __getitem__?

Trả lời

18

phương pháp đặc biệt được nhìn lên trên lớp, không phải trên các trường hợp - không giống như các phương pháp thông thường được nhìn lên trên dụ Đầu tiên. Xem Special method lookup trong tài liệu mô hình dữ liệu Python.

Suy nghĩ về Class như một thể hiện của type, điều này có nghĩa là khi bạn làm

Class.getitem(test) 

Nó trông giống đầu tiên cho chính xác những gì bạn nói với nó: một phương pháp trong Class 's thuộc tính riêng gọi là getitem. Tuy nhiên, khi bạn sử dụng

Class[test] 

nó bỏ qua điều này, và đi thẳng đến type (là lớp của Class, hoặc metaclass của nó), và do đó gọi type.__getitem__(Class, test). Vì vậy, những gì đang xảy ra không phải là __getitem__ được type làm đối số đầu tiên của nó (nó vẫn sẽ nhận được Class, vì nó rõ ràng là Class.__getitem__(test)), mà nó tìm kiếm trong trường hợp này không tồn tại. Để làm cho nó tồn tại, bạn cần phải xác định metaclass của riêng bạn cho Class xác định nó như là một phương pháp thể hiện, thay vì xác định nó trên Class như là một classmethod.

+0

'Suy nghĩ về Class là một thể hiện của loại'. Cảm ơn bạn. Cảm ơn bạn. Cảm ơn bạn. – norbertpy

9

Khi bạn gọi x[test], thông dịch viên kiểm tra type(x) cho thuộc tính __getitem__. Trong trường hợp Class[test] là metaclass của Class, tức là type. Nếu bạn muốn có một lớp học __getitem__, hãy xác định nó trong một metaclass mới. (Không cần phải nói, đó là một loại ma thuật, như bất cứ điều gì bạn làm với metaclasses)

class Meta(type): 
    def __getitem__(self, arg): 
     print "__getitem__:", arg 


class X(object): 
    __metaclass__ = Meta 

X['hello'] # output: __getitem__ hello 
+0

Đó là giải pháp cho câu hỏi được nêu, nhưng nó quá nhiều mã hóa cho đường cú pháp như vậy. Và trong mã thực tế tôi đang cố gắng để __getitem__ trên metaclass chính nó :) – qMax

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