Làm thế nào để trả về một giá trị từ __init__ trong Python?


102

Tôi có một lớp với một __init__hàm.

Làm cách nào để trả về giá trị số nguyên từ hàm này khi một đối tượng được tạo?

Tôi đã viết một chương trình, nơi __init__phân tích cú pháp dòng lệnh và tôi cần phải có một số giá trị được đặt. Có thể đặt nó trong biến toàn cục và sử dụng nó trong các hàm thành viên khác không? Nếu vậy làm thế nào để làm điều đó? Cho đến nay, tôi đã khai báo một biến bên ngoài lớp. và đặt nó một chức năng không phản ánh trong chức năng khác ??


8
Nếu bạn đang cân nhắc trả lại mã lỗi, hãy nêu ra một ngoại lệ thay thế.
JoeG

1
Vui lòng xóa bình luận của bạn và cập nhật câu hỏi của bạn. Bạn sở hữu câu hỏi. Đó là câu hỏi của bạn. Vui lòng sửa câu hỏi để hiển thị chính xác vấn đề thực sự của bạn là gì. Bạn đang lạm dụng __init__; chúng tôi có thể giúp bạn nếu bạn mô tả những gì bạn đang thực sự cố gắng đạt được.
S.Lott

Câu trả lời:


117

__init__được yêu cầu trả lại Không có. Bạn không thể (hoặc ít nhất là không nên) trả lại thứ khác.

Hãy thử tạo bất kỳ thứ gì bạn muốn để trả về một biến thể hiện (hoặc hàm).

>>> class Foo:
...     def __init__(self):
...         return 42
... 
>>> foo = Foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() should return None

24
+1: Bạn không thể trả lại thứ khác. Nó không có ý nghĩa gì cả.
S.Lott

72
init không trả về đối tượng mới được tạo - như đã thấy trong TypeError, nó bắt buộc phải trả về None, đúng không? Đối tượng mới tạo được trả về bởi new , init chỉ đặt một số thuộc tính của nó. Nhưng có, như bạn đã nói, thay đổi init , hoặc mới , để trả lại thứ khác thực sự không có ý nghĩa.
weronika

newđây là ở đâu? Có newẩn trong Python không? Tôi cho rằng ngữ nghĩa của Python khác với Java và các ngôn ngữ khác sử dụng từ này.
cs95,

1
@Shiva AFAIK, theo weronika mới có nghĩa là __new __ (self) không phải là ngữ nghĩa java chung.
Harsh Daftary

2
Chỉ vì nó không thể được thực hiện không có nghĩa là nó không có ý nghĩa. Ví dụ, sẽ rất tuyệt khi chuyển dữ liệu từ super().__init__lớp dẫn xuất mà không cần phải chuyển tiếp nó thông qua một biến cá thể.
cz

123

Tại sao bạn muốn làm điều đó?

Nếu bạn muốn trả về một số đối tượng khác khi một lớp được gọi, hãy sử dụng __new__()phương thức:

class MyClass(object):
    def __init__(self):
        print "never called in this case"
    def __new__(cls):
        return 42

obj = MyClass()
print obj

9
Vâng, mới là cách đúng đắn để trả về một thứ gì đó khác với một cá thể của lớp khi sử dụng một lớp ... Tôi chỉ tự hỏi - có lý do nào bạn thực sự muốn làm điều đó không?
weronika

33
@weronika Một ý tưởng: trong bất kỳ tình huống nào bạn thường sử dụng nhà máy, nhưng bạn có một số lý do để muốn trình bày một giao diện trông giống như mô tả lớp bình thường. Ví dụ: khi thêm một số tham số tùy chọn mới vào lớp của __init__bạn, bạn nhận ra rằng thực sự, để cung cấp tính linh hoạt bạn muốn, bạn cần một nhà máy sản xuất lớp trả về các thể hiện của các lớp con chuyên biệt. Nhưng người dùng thư viện của bạn đã sử dụng API hiện có của bạn. Để bảo vệ nó, bạn ghi đè __new__để trả về các phiên bản của các lớp con chuyên biệt của bạn.
Mark Amery

10
Nếu bạn muốn xem ví dụ về những gì Mark Amery đã nói, hãy xem mã nguồn của datetimemô-đun từ Thư viện chuẩn. Nó sử dụng __new__chính xác trong thời trang này.
Zearin

Ngoài ra nếu ai muốn làm điều này, hãy đảm bảo kế thừa từ đối tượng nếu không nó sẽ không hoạt động.
Mino_e

Tôi nghĩ ở mức này, chỉ cần sử dụng một hàm thông thường sẽ có ý nghĩa hơn. Có thể hơi xa lạ với những người từ chiều Java (các chức năng không có trong các lớp? Dị giáo!) Nhưng chính xác của nó. (Ngoài ra bạn có thể gán thuộc tính chức năng như trong funtionName.val = .. mà là loại hoang dã nhưng nó hoạt động)
Shayne

37

Từ tài liệu của__init__ :

Là một ràng buộc đặc biệt đối với các hàm tạo, không có giá trị nào có thể được trả về; làm như vậy sẽ gây ra lỗi TypeError được đưa ra trong thời gian chạy.

Như một bằng chứng, mã này:

class Foo(object):
    def __init__(self):
        return 2

f = Foo()

Tạo ra lỗi này:

Traceback (most recent call last):
  File "test_init.py", line 5, in <module>
    f = Foo()
TypeError: __init__() should return None, not 'int'

17

Cách sử dụng mẫu của vấn đề được đề cập có thể như sau:

class SampleObject(object):

    def __new__(cls, item):
        if cls.IsValid(item):
            return super(SampleObject, cls).__new__(cls)
        else:
            return None

    def __init__(self, item):
        self.InitData(item) #large amount of data and very complex calculations

...

ValidObjects = []
for i in data:
    item = SampleObject(i)
    if item:             # in case the i data is valid for the sample object
        ValidObjects.append(item)

Tôi không có đủ danh tiếng nên tôi không thể viết bình luận, thật là điên rồ! Tôi ước tôi có thể đăng nó dưới dạng nhận xét cho weronika


3
Điều này sẽ nâng cao một NameError: selfkhông được định nghĩa trong__new__(cls, Item)
Hart Simha

15

Các __init__phương pháp như phương pháp và chức năng lợi nhuận khác Không theo mặc định trong sự vắng mặt của một tuyên bố trở lại, vì vậy bạn có thể viết nó như một trong những:

class Foo:
    def __init__(self):
        self.value=42

class Bar:
    def __init__(self):
        self.value=42
        return None

Nhưng, tất nhiên, thêm vào return Nonekhông giúp bạn bất cứ điều gì.

Tôi không chắc bạn đang theo đuổi điều gì, nhưng bạn có thể quan tâm đến một trong những điều này:

class Foo:
    def __init__(self):
        self.value=42
    def __str__(self):
        return str(self.value)

f=Foo()
print f.value
print f

bản in:

42
42

ohh..Tôi có thể truy cập biến thành viên ra khỏi lớp không? Sau đó, điều đó sẽ giải quyết vấn đề của tôi .... cảm ơn
webminal.org

@lakshmipathi, Có, các biến cá thể như thế này là công khai.
quamrana

Là một người xếp hàng để nhận được thứ gì đó có giá trị được trả lại sau khi bắt đầu lớp học:f = Foo().value
JLT

@JLT Có, bạn cam luôn làm điều đó nhưng nó vẫn không có nghĩa là bất cứ điều gì được trả lại từ __init__.
quamrana

7

__init__không trả lại bất cứ điều gì và nên luôn luôn trả lại None.


4

Bạn chỉ có thể đặt nó thành một biến lớp và đọc nó từ chương trình chính:

class Foo:
    def __init__(self):
        #Do your stuff here
        self.returncode = 42
bar = Foo()
baz = bar.returncode

2

Chỉ muốn thêm, bạn có thể trả lại các lớp trong __init__

@property
def failureException(self):
    class MyCustomException(AssertionError):
        def __init__(self_, *args, **kwargs):
            *** Your code here ***
            return super().__init__(*args, **kwargs)

    MyCustomException.__name__ = AssertionError.__name__
    return MyCustomException

Phương pháp trên giúp bạn triển khai một hành động cụ thể dựa trên một Ngoại lệ trong thử nghiệm của bạn


2
super().__init__đang trở lại None, vì vậy bạn đang quay trở lại None, điều đó là tốt, nhưng thừa.
cz

2

init () trả về không có giá trị nào được giải quyết hoàn hảo

class Solve:
def __init__(self,w,d):
    self.value=w
    self.unit=d
def __str__(self):
    return str("my speed is "+str(self.value)+" "+str(self.unit))
ob=Solve(21,'kmh')
print (ob)

đầu ra: tốc độ của tôi là 21 kmh


-2

Vâng, nếu bạn không quan tâm đến cá thể đối tượng nữa ... bạn có thể thay thế nó!

class MuaHaHa():
def __init__(self, ret):
    self=ret

print MuaHaHa('foo')=='foo'

2
Điều đó chỉ thay đổi những gì được gán cho tên selfbên trong hàm tạo đó.
Ondrej K.
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.