Câu hỏi tôi sắp hỏi có vẻ trùng lặp với Python's use of __new__ and __init__?, nhưng không phân biệt, chính xác sự khác biệt thực tế giữa __new__
và __init__
là gì.Python (và Python C API): __new__ so với __init__
Trước khi bạn vội vàng nói với tôi rằng __new__
là để tạo đối tượng và __init__
là để khởi tạo đối tượng, hãy để tôi rõ ràng: Tôi hiểu điều đó. Trong thực tế, sự khác biệt đó là khá tự nhiên đối với tôi, vì tôi có kinh nghiệm trong C++, nơi chúng tôi có placement new, mà tương tự tách phân bổ đối tượng từ khởi tạo.
Các Python C API tutorial giải thích nó như thế này:
Các thành viên mới có trách nhiệm tạo (như trái ngược với khởi tạo) đối tượng của các loại. Nó được hiển thị trong Python làm phương thức
__new__()
. ... Một lý do để thực hiện một phương pháp mới là đảm bảo các giá trị ban đầu của biến thể hiện.
Vì vậy, yeah - Tôi được gì __new__
có, nhưng bất chấp điều này, tôi vẫn không hiểu tại sao nó rất hữu ích trong Python. Ví dụ cho biết rằng __new__
có thể hữu ích nếu bạn muốn "đảm bảo các giá trị ban đầu của các biến mẫu". Vâng, không phải là chính xác những gì __init__
sẽ làm gì?
Trong hướng dẫn API C, một ví dụ được hiển thị khi một Loại mới (được gọi là "Noddy") được tạo và chức năng __new__
của Type được xác định. Loại Noddy chứa một thành viên chuỗi gọi first
, và là thành viên chuỗi này được khởi tạo một chuỗi rỗng như vậy:
static PyObject * Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
.....
self->first = PyString_FromString("");
if (self->first == NULL)
{
Py_DECREF(self);
return NULL;
}
.....
}
Lưu ý rằng nếu không có __new__
phương pháp định nghĩa ở đây, chúng ta sẽ phải sử dụng PyType_GenericNew
, mà chỉ đơn giản khởi tất cả các thành viên biến đối tượng thành NULL. Vì vậy, lợi ích duy nhất của phương thức __new__
là biến cá thể sẽ bắt đầu như một chuỗi rỗng, trái ngược với NULL. Nhưng tại sao điều này lại hữu ích, vì nếu chúng ta quan tâm đến việc đảm bảo các biến mẫu của chúng ta được khởi tạo thành một giá trị mặc định, chúng ta có thể thực hiện điều đó trong phương thức __init__
?
mã bạn gọi là "boilerplate" trong '__new__' không phải là bản mẫu, bởi vì boilerplate không bao giờ thay đổi. Đôi khi bạn cần thay thế mã cụ thể đó bằng một thứ khác. –
Tạo, hoặc bằng cách khác thu được, cá thể (thường là với một cuộc gọi 'super') và trả về cá thể là các phần cần thiết của bất kỳ việc thực hiện' __new__' nào và "bản mẫu" mà tôi đang đề cập đến. Ngược lại, 'pass' là một thực thi hợp lệ cho' __init__' - không có hành vi bắt buộc nào. – ncoghlan