Trong hầu hết các ngôn ngữ OO nổi tiếng, một biểu thức như SomeClass(arg1, arg2)
sẽ phân bổ một thể hiện mới, khởi tạo các thuộc tính của thể hiện và sau đó trả về nó.
Trong hầu hết các ngôn ngữ OO nổi tiếng, phần "khởi tạo thuộc tính của thể hiện" có thể được tùy chỉnh cho mỗi lớp bằng cách định nghĩa một hàm tạo , về cơ bản chỉ là một khối mã hoạt động trên thể hiện mới (sử dụng các đối số được cung cấp cho biểu thức hàm tạo ) để thiết lập bất kỳ điều kiện ban đầu nào được mong muốn. Trong Python, điều này tương ứng với __init__
phương thức của lớp .
Python __new__
là không có gì hơn và không có gì khác hơn là tùy chỉnh tương tự cho mỗi lớp của phần "phân bổ một thể hiện mới". Điều này tất nhiên cho phép bạn làm những việc khác thường như trả về một thể hiện hiện tại thay vì phân bổ một cái mới. Vì vậy, trong Python, chúng ta không thực sự nghĩ phần này là nhất thiết liên quan đến phân bổ; tất cả những gì chúng tôi yêu cầu là __new__
đưa ra một ví dụ phù hợp từ đâu đó.
Nhưng đó vẫn chỉ là một nửa công việc và không có cách nào để hệ thống Python biết rằng đôi khi bạn muốn điều hành nửa công việc còn lại ( __init__
) sau đó và đôi khi bạn không làm. Nếu bạn muốn hành vi đó, bạn phải nói một cách rõ ràng.
Thông thường, bạn có thể cấu trúc lại để bạn chỉ cần __new__
, hoặc vì vậy bạn không cần __new__
, hoặc do đó, __init__
hành vi khác nhau trên một đối tượng đã được khởi tạo. Nhưng nếu bạn thực sự muốn, Python thực sự cho phép bạn xác định lại "công việc", do đó SomeClass(arg1, arg2)
không nhất thiết phải gọi __new__
theo sau __init__
. Để làm điều này, bạn cần tạo một siêu dữ liệu và xác định __call__
phương thức của nó .
Một metaclass chỉ là lớp của một lớp. Và __call__
phương thức của lớp kiểm soát những gì xảy ra khi bạn gọi các thể hiện của lớp. Vì vậy, phương thức của siêu dữ liệu__call__
kiểm soát những gì xảy ra khi bạn gọi một lớp; tức là nó cho phép bạn xác định lại cơ chế tạo cá thể từ đầu đến cuối . Đây là mức độ mà bạn có thể thực hiện một cách thanh lịch nhất một quy trình tạo cá thể hoàn toàn không chuẩn như mẫu đơn. Trong thực tế, có ít hơn 10 dòng mã bạn có thể thực hiện một Singleton
metaclass mà sau đó thậm chí không yêu cầu bạn phải futz với __new__
ở tất cả , và có thể biến bất kỳ lớp khác bình thường thành một singleton bằng cách đơn giản thêm __metaclass__ = Singleton
!
class Singleton(type):
def __init__(self, *args, **kwargs):
super(Singleton, self).__init__(*args, **kwargs)
self.__instance = None
def __call__(self, *args, **kwargs):
if self.__instance is None:
self.__instance = super(Singleton, self).__call__(*args, **kwargs)
return self.__instance
Tuy nhiên, đây có lẽ là phép thuật sâu sắc hơn là thực sự được bảo đảm cho tình huống này!