2011-09-20 30 views
5

Nói rằng tôi có một metaclass:của metaclass "__call__" và "__init__" sản phẩm đẳng cấp của

class Meta(type): 
    def __call__(cls, *args): 
     print "Meta: __call__ with", args 

class ProductClass(object): 
    __metaclass__ = Meta 
    def __init__(self, *args): 
     print "ProductClass: __init__ with", args 

p = ProductClass(1) 

đầu ra như sau:

Meta: __call__ with (1,) 

Câu hỏi:

Tại sao không phải là ProductClass's __init__ được kích hoạt? Chỉ vì Meta's __call__?

UPDATE:

Bây giờ, tôi thêm __new__ cho ProductClass:

class ProductClass(object): 
     __metaclass__ = Meta 
     def __new__(cls, *args): 
      print "ProductClass: __new__ with", args 
      return super(ProductClass, cls).__new__(cls, *args) 
     def __init__(self, *args): 
      print "ProductClass: __init__ with", args 

p = ProductClass(1) 

Có trách nhiệm __call__ 's Meta để gọi ProductClass của __new____init__?

Trả lời

4

Có - tối đa Meta.__call__ để gọi ProductClass.__init__ (hoặc không, như trường hợp có thể).

Để trích dẫn documentation: Hành vi

ví dụ xác định một phương pháp tùy chỉnh __call__() trong metaclass cho phép tùy chỉnh khi các lớp được gọi, ví dụ không phải luôn luôn tạo một phiên bản mới.

Trang đó cũng đề cập đến một kịch bản mà của __call__ metaclass có thể trở lại một thể hiện của một lớp học khác nhau (ví dụ: không ProductClass trong ví dụ của bạn). Trong trường hợp này, rõ ràng là không thích hợp để tự động gọi ProductClass.__init__.

+0

nếu tôi có một "__new__" trong ProductClass thì sao? "__call__" của Meta có gọi là "__new__" và "__init__" của ProductClass không? Xem CẬP NHẬT của tôi. – Alcott

+0

Và rõ ràng, "__call__" của Meta được gọi đầu tiên trước "__new__" của ProductClass. – Alcott

+0

Vấn đề là lệnh 'Meta .__ call__' được yêu cầu để gọi' ProductClass .__ new__' và 'ProductClass .__ init__'. Thông thường, 'type .__ call__' thực hiện điều này cho bạn, nhưng khi bạn định nghĩa' Meta .__ call__' bạn _override_ hành vi đó, có nghĩa là nó không được thực hiện trừ khi bạn làm như vậy. Vì vậy, bạn hoặc là cần thiết để gọi '__new__' và' __init__' chính mình, hoặc thực hiện cuộc gọi đến một cái gì đó như 'loại .__ gọi __ (cls, * args)'. –

6

Có một sự khác biệt trong OOP giữa mở rộng một phương pháp và cách ghi đè nó, những gì bạn chỉ cần làm trong metaclass bạn Meta được gọi là trọng vì bạn đã định nghĩa phương pháp __call__ của bạn và bạn đã không gọi cho phụ huynh __call__. để có hành vi mà bạn muốn bạn phải mở rộng phương thức __call__ bằng cách gọi phương thức gốc:

class Meta(type): 
    def __call__(cls, *args): 
     print "Meta: __call__ with", args 
     return super(Meta, cls).__call__(*args) 
Các vấn đề liên quan