2012-02-01 21 views
31

Các Changelog cho Python 2.2 (nơi các lớp học kiểu mới đã được giới thiệu) nói như sau về __new__ chức năng:Tại sao không __new__ trong các lớp kiểu Python mới một phương thức lớp?

__new__ là một phương pháp tĩnh, không phải là một phương pháp lớp. Ban đầu tôi nghĩ rằng nó sẽ phải là một phương pháp lớp học, và đó là lý do tại sao tôi đã thêm classmethod nguyên thủy. Thật không may, với các phương thức lớp, upcalls không hoạt động ngay trong trường hợp này, vì vậy tôi đã phải làm cho nó một phương thức tĩnh với một lớp rõ ràng làm đối số đầu tiên của nó.

Tuy nhiên, tôi không thể nghĩ tại sao các phương pháp lớp học sẽ không hoạt động cho mục đích này và chắc chắn sẽ tốt hơn. Tại sao không __new__ kết thúc như là một phương pháp lớp học cuối cùng? Guido nói gì khi nói rằng "upcalls không hoạt động ngay trong trường hợp này"?

Trả lời

17

__new__ là phương pháp tĩnh cho phép một use-case khi bạn tạo một thể hiện của một lớp con trong đó:

return super(<currentclass>, cls).__new__(subcls, *args, **kwargs) 

Nếu new là một phương pháp học thì trên được viết như sau:

return super(<currentclass>, cls).new(*args, **kwargs) 

và không có chỗ để đặt subcls.

Tôi không thực sự thấy khi nào đó sẽ là sử dụng hợp lý của __new__. Có lẽ tôi không nhìn thấy nó, nhưng điều đó dường như với tôi là một cách sử dụng hoàn toàn bệnh lý của nó (và nó phải được nói, rằng nếu bạn vẫn thực sự muốn nó, sau đó bạn có thể truy cập nó với object.__new__.__func__). Ít nhất, tôi thấy rất khó để tưởng tượng rằng nó sẽ là lý do cho Guido thay đổi __new__ từ một phương pháp lớp học sang một phương pháp tĩnh.

Trường hợp phổ biến hơn là gọi điện cho cha mẹ __new__ mà không cần sử dụng super(). You need a place to pass cls explicitly in this case:

class Base(object): 
    @classmethod 
    def new(cls): 
     print("Base.new(%r)" % (cls,)) 
     return cls() 

class UseSuper(Base): 
    @classmethod 
    def new(cls): 
     print("UseSuper.new(%r)" % (cls,)) 
     return super(UseSuper, cls).new() # passes cls as the first arg 

class NoSuper(Base): 
    @classmethod 
    def new(cls): 
     print("NoSuper.new(%r)" % (cls,)) 
     return Base.new() # passes Base as the first arg 

class UseFunc(Base): 
    @classmethod 
    def new(cls): 
     print("UseFunc.new(%r)" % (cls,)) 
     return Base.new.im_func(cls) # or `.__func__(cls)`. # passes cls as the first arg 

print(UseSuper.new()) 
print('-'*60) 
print(NoSuper.new()) 
print('-'*60) 
print(UseFunc.new()) 
+0

@Duncan: Tôi đã cố ý sử dụng 'mới' thay vì '__new__'. Nếu nó không rõ ràng, để lại một bình luận tôi sẽ cố gắng để xây dựng. – jfs

+0

Tôi nghĩ nếu bạn đã sử dụng một cái tên khác biệt hơn một chút so với việc chỉ bỏ dấu gạch dưới, nó sẽ rõ ràng hơn, nhưng bây giờ tôi đã hiểu. – Duncan

+0

Khi nào điều này thực sự là một vấn đề? Nếu bạn muốn một thể hiện của 'subcls', tại sao bạn không gọi' subcls.new() '? Làm theo cách bạn mô tả chỉ có tác dụng không chạy các hàm '__new__' đúng trên' subcls'. – Dolda2000