__init__的目的是什么?

4
我已经阅读了一些内容,但仍无法完全理解。我正在使用LPTHW教程中的示例脚本创建一个小型“选择你自己的冒险”游戏,以下是完整的脚本:http://codepad.org/YWVUlHnU 我不理解以下内容:
class Game(object):

    def __init__(self, start):
        self.quips = [
            "You died. Please try again.",
            "You lost, better luck next time.",
            "Things didn't work out well. You'll need to start over."
            "You might need to improve your skills. Try again." 
        ]
        self.start = start

我知道我们正在创建一个类,但为什么要定义__init__?之后我会做一些像print self.quis[randint(0, len(self.quips)-1)]这样的事情,它会打印出quips中的四个字符串中的一个,但为什么我不只是创建一个名为quips的函数呢?

3个回答

15
当您调用Game("central_corridor")时,将创建一个新对象,并调用Game.__init__()方法,其中将该新对象作为第一个参数(self),并将"central_corridor"作为第二个参数。由于您编写了a_game = Game(...),因此您已将a_game指定为引用该新对象。
这张图可能会使这个过程更容易理解: Python object creation 注意:__new__方法是Python提供的。它创建一个给定类的新对象。内置的__new__方法不会对其余的参数做任何处理。如果需要,可以覆盖__new__方法并利用其他参数。 __init__()存在于您的程序中的实际原因是设置Game实例的start属性(您调用a_game的那个实例),以便第一次调用a_game.play()从您想要的位置开始。
关于quips,您说得对。没有理由在__init__()中设置quips。您只需将其设置为类属性即可:
class Game(object):
    quips = ["You died. Please try again.",
            "You lost, better luck next time.",
            "Things didn't work out well. You'll need to start over."
            "You might need to improve your skills. Try again." ]
    def __init__(self, start):
        self.start = start

我认为如果我创建了一个 Game 类的实例,那么我使用的任何属性将决定游戏从哪里开始。因此,如果我想让游戏从 Game 类中的 laser_weapon_armory 函数开始,我会这样做:a_game = game("laser_weapon_armory") ,然后 a_game.play()__init__ 与此有什么关系? - ZCJ
init 方法设置了对象的基本状态... 想象一下,如果它需要先连接到数据库并下载一些数据来准备自己,你会在 init 中完成这些操作,然后再进行其他操作。这就像从经销商那里购买汽车一样... 如果没有 __init__,你会得到一个没有轮子、没有引擎的汽车对象,但如果你想的话,仍然可以 car.drive()。 - michaelfilms
1
当你编写 Game("laser_weapon_armory") 时,实际上发生的是创建了一个新的 Game 实例,我们称其为 obj(在此时实际上没有名称),然后Python 自动 运行 Game.__init__(obj, "laser_weapon_armory") 并返回 obj(最终分配给名称 a_game)。 __init__ 中设置了 obj.start"laser_weapon_armory"。当你运行 a_game.play() 时,实际上发生的是Python运行 Game.play(a_game) - self 参数用 a_game 填充,因此当你调用 a_game.play() 时, self.start"laser_weapon_armory" - Steven T. Snyder
@Series8217: 非常好的回答 - 只是有一点挑剔,__new__方法被传递的参数与稍后传递给__init__的参数相同,而不仅仅是类。 - jsbueno
@jsbueno 您当然是正确的。我会添加一条注释。 - Steven T. Snyder

5
更广泛地说,Python类的__init__方法和较少人知道但通常更危险的__new__方法旨在初始化对象的状态。对于您特定的对象来说,这并不是真正必要的,我想您可能会认为有很多非常简单的数据存储类不需要进行初始化,但使用Python进行更深层次的编程的现实是,几乎每个更复杂的类都需要初始化其基本状态。此外,主要原因是让您的类具有多用途性:
class Foo(object):
    def __init__(self, word_of_power="Ni"):
        self.fact = "We are the knights who say %!" % word_of_power

>>> f = Foo()
>>> w = Foo("No!")
>>> print f.fact
"We are the knights who say Ni!"
>>> print w.fact
"We are the knights who say No!"

“多用途”是指我可以使用这个类来创建像Foo()这样的实例,也可以创建带有属性的实例,例如Foo("No!")?你的意思是说,将其设计为多用途的好处在于这两种情况都能够正常工作? - ZCJ
@ZCJ,为了保持术语的准确性,请注意在语句Foo("No!")中,"No!"不是“属性”。它是一个“参数”,并且与任何函数的参数一样工作。实际上,将Foo视为一种特殊类型的函数,它接受一些参数并返回类型为Foo的对象可能会有所帮助。另一方面,self.fact是一个“属性”。 - senderle
好的,非常感谢您的澄清 - 我正在努力理清术语。所以您在回答中提到的 w.fact 是一个属性,但是当将变量 fw 分配给 foo 的不同实例时,foo 可以在括号内带一个参数,因为该类允许这样做。听起来正确吗? - ZCJ

1

__init__在这里作为构造函数使用。因此,当创建游戏实例时,将调用__init__方法。如果您定义另一种设置quips的方法,则必须显式调用它。


严格来说,__new__ 是构造函数而 __init__ 是“初始化器”。 - glglgl

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