2012-07-24 45 views
11

Tôi đang ghi đè phương thức __new__() của một lớp để trả về một cá thể lớp có tập hợp __init__() cụ thể. Python dường như gọi đẳng cấp cung cấp __init__() phương pháp thay vì phương pháp dụ cụ thể, mặc dù các tài liệu Python tạiTại sao Python không gọi phương thức instance __init __() khi tạo cá thể nhưng các lớp gọi __init __() thay thế?

http://docs.python.org/reference/datamodel.html

nói:

triển khai điển hình tạo một đối tượng mới của lớp bằng gọi phương thức __new __() của lớp cha bằng cách sử dụng siêu (lớp hiện tại, cls) .__ new __ (cls [, ...]) với các đối số thích hợp và sau đó sửa đổi trường hợp mới tạo thành cần thiết trước khi trả về.

Nếu __new __() trả về một thể hiện của cls, sau đó các trường hợp mới của __init __() phương pháp sẽ được gọi như __init __ (tự [, ...]), nơi tự là trường hợp mới và đối số còn lại là giống như đã được chuyển đến __new __().

Đây là mã thử nghiệm của tôi:

#!/usr/bin/env python 

import new 

def myinit(self, *args, **kwargs): 
    print "myinit called, args = %s, kwargs = %s" % (args, kwargs) 


class myclass(object): 
    def __new__(cls, *args, **kwargs): 
     ret = object.__new__(cls) 

     ret.__init__ = new.instancemethod(myinit, ret, cls) 
     return ret 

    def __init__(self, *args, **kwargs): 
     print "myclass.__init__ called, self.__init__ is %s" % self.__init__ 
     self.__init__(*args, **kwargs) 

a = myclass() 

mà kết quả đầu ra

$ python --version 
Python 2.6.6 
$ ./mytest.py 
myclass.__init__ called, self.__init__ is <bound method myclass.myinit of <__main__.myclass object at 0x7fa72155c790>> 
myinit called, args =(), kwargs = {} 

Có vẻ như cách duy nhất để có được myinit() để chạy, là để gọi nó một cách rõ ràng như self.__init__() bên myclass.__init__().

+1

Great câu hỏi! – Marcin

Trả lời

8

phương pháp đặc biệt về các lớp học kiểu mới được nhìn trên loại của cá thể, không phải trên bản thân cá thể. Đây là documented behaviour:

Đối với lớp mới, phương pháp đặc biệt chỉ được đảm bảo hoạt động chính xác nếu được xác định trên loại đối tượng, không có trong từ điển thể hiện của đối tượng.hành vi đó là lý do tại sao đoạn mã sau đặt ra một ngoại lệ (không giống như các ví dụ tương đương với các lớp học kiểu cũ):

>>> class C(object): 
...  pass 
... 
>>> c = C() 
>>> c.__len__ = lambda: 5 
>>> len(c) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: object of type 'C' has no len() 
8

Các phương pháp đặc biệt khác nhau (bao gồm __init__, nhưng các toán tử quá tải như __add__, v.v.) là always accessed via the class rather than the instance. Không chỉ vậy, nhưng họ không thể được truy cập thông qua một phương pháp __getattr__ hoặc __getattribute__ trên lớp hoặc metaclass, họ phải được trên lớp trực tiếp. Đây là vì lý do hiệu quả:

Bỏ qua các máy móc __getattribute__() trong thời trang này cung cấp phạm vi đáng kể cho optimisations tốc độ trong phiên dịch, với chi phí của một số linh hoạt trong việc xử lý các phương pháp đặc biệt (phương pháp đặc biệt phải được thiết lập trên chính đối tượng lớp để được trình thông dịch gọi một cách nhất quán).

Nó không hoàn toàn rõ ràng những gì bạn đang cố gắng để hoàn thành, nhưng có một điều bạn có thể làm ở đây là để phân lớp myclass trong __new__ phương pháp:

class myclass(object): 
    def __new__(cls, *args, **kwargs): 
     class subcls(cls): 
      def __new__(cls, *args, **kwargs): 
       return object.__new__(cls) 
     subcls.__init__ = myinit 
     return subcls(*args, **kwargs) 
Các vấn đề liên quan