如何在Python中从__init__返回一个值?

163

我有一个带有__init__函数的类。

当对象被创建时,如何从这个函数中返回一个整数值?

我编写了一个程序,在其中__init__函数执行命令行解析,并且我需要设置一些值。将其设置为全局变量并在其他成员函数中使用是否可以?如果可以,如何操作呢?到目前为止,我在类之外声明了一个变量。但是在一个函数中设置它并不会反映在其他函数中??


9
如果你在考虑返回错误代码,那么请改为抛出异常。 - JoeG
1
请删除您的评论并更新您的问题。这是您自己的问题。请修复问题以正确显示您真正的问题所在。您正在误用__init__;如果您描述您真正想要实现的内容,我们可以帮助您。 - S.Lott
2
__init__ 应该不要进行命令行解析。定义一个类方法来执行实际的解析,并将解析后的值传递给 __init__。让 __init__ 关注创建必要的属性,而不是弄清楚如何生成这些属性的值。 - chepner
未来的读者请注意:如果您想通过调用__init__方法获取通用信息,请参考此处给出的答案。如果您想表示发生了错误,请引发异常。这并没有回答在此处提出的问题,但可能是您所需要的。 - Karl Knechtel
13个回答

200

如果你想在调用一个类时返回一些其他的对象,那么可以使用__new__()方法:

class MyClass:
    def __init__(self):
        print("never called in this case")

    def __new__(cls):
        return 42

obj = MyClass()
print(obj)
# Output: 42

15
是的,__new__是在使用类时返回除类实例以外的东西的正确方式...我只是想知道 - 你是否有任何想要这样做的原因? - weronika
50
一种想法是,在通常需要使用工厂的任何情况下,但您有某些原因希望呈现类实例化的常规接口。例如:当向类的__init__中添加一些新的可选参数时,您意识到为了提供所需的灵活性,您需要一个返回专门子类实例的类工厂。但是,您库的用户已经在使用您现有的API。为了保留它,您重写了__new__以返回专门子类的实例。 - Mark Amery
18
如果你想看到马克·埃默里所说的例子,可以查看标准库中“datetime”模块的源代码。该模块正是使用了 __new__ 来实现这一点。 - Zearin
另外,如果有人想要这样做,请确保从object继承,否则它将无法工作。 - Mino_e
我认为在这个时候,使用普通函数更有意义。对于来自Java领域的人来说可能有点陌生(函数不在类中?邪教!),但这是Pythonic的。 (此外,您可以将属性分配给函数,例如funtionName.val =..,这有点疯狂,但它确实有效) - Shayne

166

__init__ 必须返回 None。你不能(或者至少不应该)返回其他值。

尝试将你想要返回的内容作为实例变量(或函数)。

>>> 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

36
+1:你不能返回其他东西。这没有任何意义。 - S.Lott
83
__init__方法并不返回新创建的对象,正如TypeError所示,需要返回None。新创建的对象是由__new__返回的,而__init__仅设置它的某些属性。但是,正如你所说,更改__init__或__new__,使其返回其他值确实没有意义。 - weronika
这里在哪里使用 new 关键字?Python 中是否隐含了 new 关键字?我认为 Python 的语义与使用此关键字的 Java 和其他语言不同。 - cs95
1
据我所知,新的weronika指的是__new__(self),而不是一般的Java语义。 - Harsh Daftary
2
仅仅因为某件事情做不到并不意味着它没有意义。例如,如果能够在不通过实例变量中继数据的情况下从super().__init__传递数据到派生类,那将是很好的。 - c z
显示剩余2条评论

44

根据__init__文档:

在构造函数中有一个特殊的限制,就是不能返回任何值;如果返回值则会导致在运行时引发TypeError异常。

下面的代码可作为证明:

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

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

24

问题的样例使用可以如下:

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)

3
这将引发一个NameError错误:__new__(cls, Item)中的self未定义。 - Hart Simha

16

如果没有返回语句,像其他方法和函数一样,__init__ 方法默认返回 None。因此,你可以写出下面两种形式中的任何一种:

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

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

当然,添加return None并没有任何作用。

我不确定你想要什么,但你可能会对其中一个感兴趣:

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

f=Foo()
print f.value
print f

输出:

42
42

哦..我能在类外访问成员变量吗?那应该解决我的问题...谢谢。 - webminal.org
@lakshmipathi,是的,像这样的实例变量是公共的。 - quamrana
作为一行代码,在类的初始化后获取有价值的返回值:f = Foo().value - JLT
@JLT 是的,你总是可以这样做,但这仍然不意味着从__init__返回任何内容。 - quamrana

11

__init__ 不返回任何值,并且应始终返回 None


6
你可以将它设置为一个类变量,并从主程序中读取它:
class Foo:
    def __init__(self):
        #Do your stuff here
        self.returncode = 42
bar = Foo()
baz = bar.returncode

4

我们无法从init中返回值。但我们可以使用new来返回值。

class Car:
    def __new__(cls, speed, unit):
        return (f"{speed} with unit {unit}")


car = Car(42, "km")
print(car)

是的,但你不能从__new__返回任意值并仍然使类“protocol”有意义。 - chepner

2

init() 函数已完美解决返回值为none的问题

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)

输出: 我的速度是21公里/小时


0

只是想补充一下,你可以在__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

上述方法可以帮助您在测试中对异常执行特定操作


5
super().__init__ 返回的是 None,所以你返回 None 是可以的,但是多余了。 - c z

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接