Các hàm tạo Python và __init__


107

Tại sao các constructor thực sự được gọi là "Constructors"? Mục đích của chúng là gì và chúng khác với các phương thức trong một lớp như thế nào?

Ngoài ra, có thể có nhiều hơn cái đó __init__trong một lớp không? Tôi đã thử những điều sau đây, ai đó có thể vui lòng giải thích kết quả không?

>>> class test:
    def __init__(self):
        print "init 1"
    def __init__(self):
        print "init 2"

>>> s=test()
init 2

Cuối cùng, có phải là __init__một trình nạp chồng toán tử?


41
Về mặt kỹ thuật, __init__là một khởi tạo . Python constructor__new__. Python sử dụng khởi tạo hai giai đoạn tự động - __new__trả về một đối tượng hợp lệ nhưng (thường là) không được phổ biến (xem boolví dụ về phản đối), đối tượng này sau đó đã __init__tự động gọi nó. Điều này tránh được các vấn đề mà các ngôn ngữ như C ++ gặp phải với các đối tượng được xây dựng một phần - bạn không bao giờ có một đối tượng trong Python (mặc dù nó có thể được khởi tạo một phần). Bạn sẽ hầu như không cần phải ghi đè cả hai __new____init__trên một lớp.
Tim Delaney

2
@TimDelaney: Tôi không chắc ý bạn với các đối tượng được xây dựng một phần trong C ++.
Sebastian Mach

11
@phresnel Trong C ++, kiểu của đối tượng là lớp cơ sở (không phải lớp con) trong khi ở phương thức khởi tạo lớp cơ sở. Bạn không thể gọi một phương thức ảo trong phương thức khởi tạo lớp cơ sở và để lớp con cung cấp việc triển khai. Trong Java, bạn có thể gọi một phương thức lớp con trong phương thức khởi tạo lớp cơ sở, nhưng các biến thành viên của lớp con sẽ tự động khởi tạo sau phương thức khởi tạo lớp cơ sở (và lời gọi phương thức). Trong các ngôn ngữ có khởi tạo hai giai đoạn như Python, bạn có thể vui vẻ gọi các phương thức trong trình khởi tạo lớp cơ sở và để lớp con cung cấp (hoặc ghi đè) hành vi.
Tim Delaney

@TimDelaney: À, cảm ơn bạn đã làm rõ.
Sebastian Mach

4
@TimDelaney. Tôi nghĩ rằng bình luận của bạn nên thay thế câu trả lời được chấp nhận.
flamenco

Câu trả lời:


114

Không có tính năng nạp chồng hàm trong Python, có nghĩa là bạn không thể có nhiều hàm có cùng tên nhưng các đối số khác nhau.

Trong ví dụ mã của bạn, bạn không quá tải __init__() . Điều gì xảy ra với định nghĩa thứ hai rebinds tên __init__với phương pháp mới, vẽ các phương pháp không thể tiếp cận đầu tiên.

Đối với câu hỏi chung của bạn về các trình xây dựng, Wikipedia là một điểm khởi đầu tốt. Đối với nội dung cụ thể về Python, tôi thực sự khuyên bạn nên sử dụng tài liệu Python .


Nó cũng có nghĩa là tệp nguồn được phân tích cú pháp (diễn giải?) Tuần tự? Tôi có thể chắc chắn bất kỳ chức năng nào tôi đã xác định sau này sẽ ghi đè lên chức năng được xác định có cùng tên trước đó không? :( âm thanh Q của tôi ngớ ngẩn .. đáng lẽ phải biết nó
0xc0de

4
@ 0xc0de: Trong Python, các định nghĩa hàm thực sự là các câu lệnh thực thi và được chạy từ đầu đến cuối, vì vậy có.
NPE

1
@ 0xc0de Điều thực sự xảy ra là phần thân của lớp được thực thi trong không gian tên riêng của nó, không gian tên đó sau đó được chuyển đến siêu kính (trong đó có tên và cơ sở). Định nghĩa hàm sau đó chỉ là tạo một hàm với phần thân được chỉ định và gán cho nó tên của nó. Nhiệm vụ cuối cùng __init__sẽ là những gì kết thúc trong lớp.
skyking

64

Tại sao các constructor thực sự được gọi là "Constructors"?

Hàm tạo (được đặt tên __new__) tạo và trả về một thể hiện mới của lớp. Vì vậy, C.__new__phương thức lớp là phương thức khởi tạo cho lớp C.

Các C.__init__phương pháp dụ được gọi vào một trường hợp cụ thể, sau khi nó được tạo ra, để khởi nó trước khi được truyền lại cho người gọi. Vì vậy, phương thức đó là trình khởi tạo cho các phiên bản mới của C.

Chúng khác với các phương thức trong một lớp như thế nào?

Như đã nêu trong tài liệu chính thức __init__ được gọi sau khi phiên bản được tạo . Các phương pháp khác không nhận được điều trị này.

Mục đích của họ là gì?

Mục đích của hàm tạo C.__new__là xác định hành vi tùy chỉnh trong quá trình xây dựng một Ccá thể mới .

Mục đích của trình khởi tạo C.__init__là xác định khởi tạo tùy chỉnh của từng phiên bản Csau khi nó được tạo.

Ví dụ: Python cho phép bạn làm:

class Test(object):
    pass

t = Test()

t.x = 10   # here you're building your object t
print t.x

Nhưng nếu bạn muốn mọi trường hợp Testcó thuộc tính xbằng 10, bạn có thể đặt mã đó bên trong __init__:

class Test(object):
    def __init__(self):
        self.x = 10

t = Test()
print t.x

Mọi phương thức thể hiện (một phương thức được gọi trên một thể hiện cụ thể của một lớp) nhận thể hiện làm đối số đầu tiên của nó. Đối số đó được đặt tên theo quy ước self.

Các phương thức lớp, chẳng hạn như hàm tạo __new__, thay vào đó nhận lớp làm đối số đầu tiên của chúng.

Bây giờ, nếu bạn muốn các giá trị tùy chỉnh cho xthuộc tính, tất cả những gì bạn phải làm là chuyển giá trị đó làm đối số cho __init__:

class Test(object):
    def __init__(self, x):
        self.x = x

t = Test(10)
print t.x
z = Test(20)
print t.x

Tôi hy vọng điều này sẽ giúp bạn xóa một số nghi ngờ, và vì bạn đã nhận được câu trả lời tốt cho các câu hỏi khác nên tôi sẽ dừng ở đây :)


9

Các lớp chỉ đơn giản là bản thiết kế để tạo các đối tượng từ đó. Hàm tạo là một số mã được chạy mỗi khi bạn tạo một đối tượng. Vì vậy, không có ý nghĩa gì khi có hai hàm tạo. Điều gì xảy ra là thứ hai viết trên đầu tiên.

Những gì bạn thường sử dụng chúng là tạo các biến cho đối tượng đó như sau:

>>> class testing:
...     def __init__(self, init_value):
...         self.some_value = init_value

Vì vậy, những gì bạn có thể làm sau đó là tạo một đối tượng từ lớp này như thế này:

>>> testobject = testing(5)

Testobject sau đó sẽ có một đối tượng được gọi là some_valuetrong mẫu này sẽ là 5.

>>> testobject.some_value
5

Nhưng bạn không cần đặt giá trị cho từng đối tượng như tôi đã làm trong mẫu của mình. Bạn cũng có thể làm như sau:

>>> class testing:
...     def __init__(self):
...         self.some_value = 5

thì giá trị của some_value sẽ là 5 và bạn không phải đặt nó khi tạo đối tượng.

>>> testobject = testing()
>>> testobject.some_value
5

>>> và ... trong mẫu của tôi không phải là những gì bạn viết. Nó sẽ trông như thế nào trong vỏ sò ...


Không có vấn đề, vui mừng nó giúp bạn :)
Niclas Nilsson

1

coonstructors được gọi tự động khi bạn tạo một đối tượng mới, do đó "xây dựng" đối tượng. Lý do bạn có thể có nhiều hơn một init là vì tên chỉ là tham chiếu trong python và bạn được phép thay đổi nội dung mà mỗi biến tham chiếu bất cứ khi nào bạn muốn (do đó nhập động)

def func(): #now func refers to an empty funcion
    pass
...
func=5      #now func refers to the number 5
def func():
    print "something"    #now func refers to a different function

trong định nghĩa lớp của bạn, nó chỉ giữ cái sau


0

Không có khái niệm về nạp chồng phương thức trong Python. Nhưng bạn có thể đạt được hiệu quả tương tự bằng cách chỉ định các đối số tùy chọn và từ khóa

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.