Hầu hết các ngôn ngữ lập trình hướng đối tượng như Java, C++, C#. vv có khái niệm về hàm tạo, một phương thức đặc biệt tạo và khởi tạo đối tượng khi nó được tạo. Python hơi khác một chút; . Hàm tạo hiếm khi được sử dụng trừ khi bạn đang làm điều gì đó kỳ lạ. Vì vậy, chúng ta sẽ bắt đầu thảo luận về phương thức khởi tạo.
Giả định trong bài viết này là bạn đã biết cơ bản về lớp và đối tượng trong python.
Hàm tạo trong python được gọi là
class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
0 và class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
1 là hàm khởi tạoTrích dẫn tài liệu về python,
class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
0 được sử dụng khi bạn cần kiểm soát việc tạo phiên bản mới trong khi class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
1 được sử dụng khi bạn cần kiểm soát việc khởi tạo phiên bản mớiclass Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
0 là bước đầu tiên của quá trình tạo cá thể. Nó được gọi đầu tiên và chịu trách nhiệm trả về một phiên bản mới của lớp của bạnNgược lại,
class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
1 không trả lại bất cứ thứ gì; . Nói chung, bạn không cần ghi đè class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
0 trừ khi bạn đang phân lớp con một loại bất biến như str, int, Unicode hoặc tupleLƯU Ý.
Không bao giờ đặt tên hàm của riêng bạn bằng dấu gạch dưới kép ở đầu và cuối. Nó có thể không có ý nghĩa gì đối với Python, nhưng luôn có khả năng các nhà thiết kế Python sẽ thêm một chức năng có mục đích đặc biệt với tên đó trong tương lai và khi họ làm như vậy, mã của bạn sẽ bị hỏng.
ví dụ 1. Sử dụng class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
1
class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
class Point:
def __init__[self, data]:
self.num = data
def print_num[self]:
print[self.num]
obj = Point[100]
obj.print_num[]
đầu ra
class Person:
def __new__[cls]:
return object.__new__[cls]
def __init__[self]:
self.instance_method[]
def instance_method[self]:
print['success!']
personObj = Person[]
0Ghi chú. Tham số self là một tham chiếu đến thể hiện hiện tại của lớp và được sử dụng để truy cập các biến thuộc về lớp
ví dụ 2
class Person:
def __new__[cls]:
return object.__new__[cls]
def __init__[self]:
self.instance_method[]
def instance_method[self]:
print['success!']
personObj = Person[]
Lưu ý rằng
class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
1 nhận đối số self, trong khi class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
0 nhận lớp class Person:
def __new__[cls]:
return object.__new__[cls]
def __init__[self]:
self.instance_method[]
def instance_method[self]:
print['success!']
personObj = Person[]
3]. Vì class Person:
def __new__[cls]:
return object.__new__[cls]
def __init__[self]:
self.instance_method[]
def instance_method[self]:
print['success!']
personObj = Person[]
4 là một tham chiếu đến thể hiện, nên điều này sẽ cho bạn biết khá rõ ràng rằng thể hiện đã được tạo vào thời điểm class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
1 được gọi, vì nó đã vượt qua thể hiện. Cũng có thể gọi các phương thức thể hiện một cách chính xác vì thể hiện đã được tạoGần đây tôi đã hỏi tôi phương thức
class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
1 dunder đã làm gì trong Python. Và tôi đã nói, "nó được sử dụng để khởi tạo các biến bên trong một lớp". Và ngay sau đó, câu hỏi tiếp theo là, “vậy thì class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
2 dùng để làm gì?”. Và tôi hoàn toàn trống rỗng và không thể trả lời rằngTôi không thể trả lời câu hỏi đó vì không có nhiều hướng dẫn nói về
class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
2. Tôi không muốn xảy ra điều này với bạn. Và đó là lý do tại sao tôi nghĩ ra bài viết blog này cho bạnĐiểm tương đồng
Hãy bắt đầu với những điểm tương đồng
- Cả hai đều được gọi/gọi trong quá trình tạo thể hiện
sự khác biệt
Hãy bắt đầu với sự khác biệt
newinit1Được gọi trước initĐược gọi sau new2Chấp nhận một loại làm đối số đầu tiênChấp nhận một thể hiện làm đối số đầu tiên3Được cho là trả về một thể hiện của loại đã nhậnKhông được phép trả về bất kỳ thứ gì4Được sử dụng để kiểm soát việc tạo cá thểĐược sử dụng để khởi tạo các biến thể hiệnNói về điểm đầu tiên.
class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
2 được gọi khi phiên bản được tạo lần đầu tiên. Điều này xảy ra trước khi khởi tạo lớpNhân tiện, bạn có lưu ý rằng đối số đầu tiên của
class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
1 luôn là class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
6 không? . class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
6 là những gì class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
2 trả vềĐến điểm thứ ba,
class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
2 được cho là trả về một thể hiện của lớp. Lưu ý rằng nếu class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
2 không trả về bất cứ thứ gì, thì class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
1 sẽ không được gọiMà một trong số họ là một nhà xây dựng?
Nếu bạn đến từ một ngôn ngữ khác, bạn có thể ngạc nhiên rằng có hai điều giống nhau đang làm cùng một loại công việc. Hầu hết các ngôn ngữ mà bạn có thể đã từng làm việc sẽ có một thứ gọi là hàm tạo
Trong Python, khái niệm đó được chia thành hàm tạo và trình khởi tạo. Và bạn có thể đoán ra,
class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
2 là hàm tạo và class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
1 là hàm khởi tạoXin lưu ý rằng
class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
2 là ẩn. Có nghĩa là nếu bạn không thực sự cần sửa đổi việc tạo một thể hiện của lớp, thì bạn không cần phải có phương thức class Person:
def __new__[cls]:
return object.__new__[cls]
def __init__[self]:
self.instance_method[]
def instance_method[self]:
print['success!']
personObj = Person[]
95Một điều nữa tôi muốn thêm vào là… các biến thể hiện là cục bộ của một thể hiện. Vì vậy, bất cứ điều gì bạn đang làm trong init chỉ là cục bộ của phiên bản đó. Nhưng bất cứ điều gì bạn đang làm mới sẽ ảnh hưởng đến mọi thứ được tạo cho loại đó
Luồng thực thi với một ví dụ
Tôi sẽ thêm một số mã để làm cho điều này hấp dẫn hơn. Hãy xem xét ví dụ này
class Person:
def __new__[cls]:
return object.__new__[cls]
def __init__[self]:
self.instance_method[]
def instance_method[self]:
print['success!']
personObj = Person[]
0class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
Đây là ví dụ đơn giản nhất về cả
class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
2 và class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
1 đang hoạt động. Nếu bạn lưu đoạn mã trên vào một tệp và chạy nó, bạn sẽ thấy như thế nàyclass Person:
def __new__[cls]:
return object.__new__[cls]
def __init__[self]:
self.instance_method[]
def instance_method[self]:
print['success!']
personObj = Person[]
9Như bạn có thể thấy, phương thức mới được gọi đầu tiên và sau đó việc thực thi được chuyển sang phương thức init
Trường hợp sử dụng
Trường hợp sử dụng cho class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
2
class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
Một trong những trường hợp sử dụng tốt nhất mà tôi có thể lấy làm ví dụ là khi tạo một Singleton. Như chúng ta đã biết, Singleton đảm bảo một lớp chỉ có một thể hiện và cung cấp một điểm truy cập toàn cục cho nó
Một số nơi tôi đã thấy singleton đang hoạt động là trong lập trình trò chơi nơi chỉ có một phiên bản của trình phát. Một nơi khác, nếu bạn đã sử dụng các thư viện frontend như Vuex [hoặc Redux] thì chỉ có một phiên bản toàn cầu của cửa hàng. Không quan trọng bạn tạo bao nhiêu phiên bản, cuối cùng bạn sẽ chỉ có một
Hãy xem cách đạt được hành vi tương tự trong Python
class Person:
def __new__[cls]:
return object.__new__[cls]
def __init__[self]:
self.instance_method[]
def instance_method[self]:
print['success!']
personObj = Person[]
6class Person:
def __new__[cls]:
return object.__new__[cls]
def __init__[self]:
self.instance_method[]
def instance_method[self]:
print['success!']
personObj = Person[]
7đầu ra
class Person:
def __new__[cls]:
return object.__new__[cls]
def __init__[self]:
self.instance_method[]
def instance_method[self]:
print['success!']
personObj = Person[]
8Như bạn có thể thấy, việc tạo… chỉ được in một lần. cả hai đều trỏ đến cùng một vị trí bộ nhớ. Trong trường hợp của tôi, đó là
class Person:
def __new__[cls]:
return object.__new__[cls]
def __init__[self]:
self.instance_method[]
def instance_method[self]:
print['success!']
personObj = Person[]
99Bạn có thể đoán rằng chúng ta không thể làm điều tương tự với
class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
1? . Đó là bởi vì class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
1 không trả lại bất cứ thứ gì. Chúng ta sẽ xem trong phần tiếp theo class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
1 phù hợp với điều gìNhưng trước tiên, tôi muốn cho bạn thấy một trường hợp sử dụng khác của new
class Person:
def __new__[cls]:
return object.__new__[cls]
def __init__[self]:
self.instance_method[]
def instance_method[self]:
print['success!']
personObj = Person[]
3____34đầu ra
class Person:
def __new__[cls]:
return object.__new__[cls]
def __init__[self]:
self.instance_method[]
def instance_method[self]:
print['success!']
personObj = Person[]
5Tôi không phải là nhà động vật học. Nhưng bạn hiểu ý tôi ở đây. Bạn có thể sử dụng
class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
2 để tạo một thể hiện có điều kiện từ một lớpTrường hợp sử dụng cho class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
1
class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
Như chúng ta đã thấy trước đây.
class Person:
def __new__[cls]:
return object.__new__[cls]
def __init__[self]:
self.instance_method[]
def instance_method[self]:
print['success!']
personObj = Person[]
65 ở đó để khởi tạo một biến thể hiện. Các biến đối tượng này sau này có thể được sử dụng trong các phương thức khác nhau của đối tượngTôi đã sử dụng rộng rãi
class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
1 khi tôi từng làm việc với Qt framework. Qt là một khuôn khổ để phát triển giao diện người dùng dựa trên máy tính để bàn. Khi khởi tạo các đối tượng giao diện người dùng, bạn có thể đặt độ rộng hoặc độ dài của cửa sổ. Bạn cũng có thể đọc các tùy chọn từ một tệp và áp dụng tùy chọn đó trong giai đoạn khởi tạo ứng dụng. Đặt tiêu đề cửa sổ có thể là một ví dụ khácỞ đây tôi sẽ chứng minh một ví dụ như vậy
class Person:
def __new__[cls]:
return object.__new__[cls]
def __init__[self]:
self.instance_method[]
def instance_method[self]:
print['success!']
personObj = Person[]
0class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
0Ví dụ trên không phải là một ví dụ hoàn chỉnh, nhưng khi được thiết lập chính xác, nó sẽ hiển thị một cửa sổ tương tự như thế này
Chìa khóa rút ra
- Trong hầu hết các trường hợp, bạn không cần
2 được gọi trướcclass Demo: def __new__[cls, *args]: print["__new__ called"] return object.__new__[cls] def __init__[self]: print["__init__ called"] d = Demo[]
1class Demo: def __new__[cls, *args]: print["__new__ called"] return object.__new__[cls] def __init__[self]: print["__init__ called"] d = Demo[]
2 trả về một thể hiện của lớpclass Demo: def __new__[cls, *args]: print["__new__ called"] return object.__new__[cls] def __init__[self]: print["__init__ called"] d = Demo[]
1 nhận các thể hiện của lớp được trả về bởiclass Demo: def __new__[cls, *args]: print["__new__ called"] return object.__new__[cls] def __init__[self]: print["__init__ called"] d = Demo[]
2class Demo: def __new__[cls, *args]: print["__new__ called"] return object.__new__[cls] def __init__[self]: print["__init__ called"] d = Demo[]
- Sử dụng ________ 51 để khởi tạo giá trị
Khái niệm tương tự có thể được sử dụng để trả lời câu hỏi trừu tượng hóa và đóng gói
Sự kết luận
Đó là tất cả những gì tôi biết về
class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
1 so với class Demo:
def __new__[cls, *args]:
print["__new__ called"]
return object.__new__[cls]
def __init__[self]:
print["__init__ called"]
d = Demo[]
2. Nếu bạn có một cái gì đó trong tâm trí của bạn mà tôi bỏ lỡ. Làm ơn cho tôi biếtTôi cũng sẽ liệt kê một số tài liệu tham khảo mà tôi muốn viết bài đăng trên blog này để bạn có thể thực sự là nguồn thông tin thực sự.