Python:必须__init __(self,foo)后面跟着self.foo = foo?

时间:2012-03-16 00:48:50

标签: python init self

我一直在努力奋斗三天,围绕__init__和“自我”,从学习Python艰苦之路练习42开始,然后继续阅读部分Python文档,{{ 3}},Alan Gauld's chapter on Object-Oriented ProgrammingStack threads like this one on "self"坦率地说,我正准备用砖块击打自己,直到我昏倒。

话虽如此,我注意到在初始__init__定义中有一个非常常见的约定,即跟进(self,foo)然后立即在该定义中声明self.foo = foo 。

来自LPTHW,ex42:

class Game(object): 
    def __init__(self, start): 
        self.quips = ["a list", "of phrases", "here"]
        self.start = start

来自Alan Gauld:

def __init__(self,val): self.val = val

我正处于那个可怕的空间,在那里我可以看到只有一件大事,我没有得到,而且无论我多少读过它并尝试弄明白,我仍然保持不透明。也许如果有人能够向我解释这一点点的一致性,那么光就会亮起来。这是因为我们需要说变量“foo”将始终等于(foo)参数,该参数本身包含在“self”参数中,该参数会自动分配给附加到它的def吗?

3 个答案:

答案 0 :(得分:6)

您可能想要研究面向对象的编程

松散地说,当你说

class Game(object):
    def __init__(self, start):
        self.start = start
你说的是:

  • 我有类型的“东西”名为 Game

  • 每当创建新的Game时,它都会要求我提供一些额外的信息start。 (这是因为名为Game的{​​{1}}初始值设定项要求提供此信息。)

  • 初始化程序(也称为“构造函数”,虽然这是轻微的用词不当)需要知道哪个对象(创建了一会儿)之前)它正在初始化。这是第一个参数 - 通常按惯例称为__init__(但你可以调用其他任何东西......)。

  • 游戏可能需要记住我给它的self是什么。因此,它通过创建名为start的实例变量 来创建“内部”信息(没有什么特别的,它只是你想要的名字),并且分配start变量start参数的值。

    • 如果它不存储参数的值,则不会将该信息提供给以后使用。

希望这能解释正在发生的事情。

答案 1 :(得分:2)

我不太确定你错过了什么,所以让我点击一些基本项目。

Python class对象中有两个“特殊”初始化名称,一个对用户来说比较少见,称为__new__,另一个更为常见,称为{{ 1}}。

调用类对象构造函数时,例如(根据您的示例)__init__,首先调用x = Game(args)来获取保存对象的内存,然后Game.__new__填写该内存。大多数情况下,您可以允许底层Game.__init__分配内存,而您只需填写它。(您可以使用自己的分配器来处理特殊奇怪的罕见情况,例如永远不会更改并可能共享身份的对象例如普通整数的做法。它也适用于那些做奇怪事情的“元类”。但这些都是后来的主题。)

调用object.__new__函数时,“构造函数的所有参数”加上前面的一个存储,这是为该对象本身分配的内存。 (对于“普通”对象,主要是“属性”的字典,加上类的魔术胶,但对于Game.__init__对象,省略了属性字典。)命名第一个参数__slots__只是一个惯例 - 但不要违反它,人们会恨你,如果你这样做。 : - )

没有什么要求你将所有参数保存到构造函数中。您可以设置您喜欢的任何或所有实例属性:

self

事实是,在初始化之后,一个Weird()实例是无用的,因为你需要传递两个简单抛弃的参数,并给出第三个可选参数,它也被抛弃:

class Weird(object):
    def __init__(self, required_arg1, required_arg2, optional_arg3 = 'spam'):
        self.irrelevant = False
    def __str__(self):
        ...

要求那些抛弃的参数的唯一要点是未来的扩展,因为它(在早期开发期间你可能有这些未使用的字段)。因此,如果您没有立即使用和/或保存x = Weird(42, 0.0, 'maybe') 的参数,__init__中的某些内容肯定是奇怪的。

顺便提一下,在类定义中使用Weird的唯一原因是向Python 2.x表明这是一个“新式”类(区别于非常旧的Python“仅实例”)类)。但通常最好使用它 - 它使我上面所说的关于(object)为真,例如:-) - 直到Python 3,其中旧式的东西完全消失了。

答案 2 :(得分:0)

参数名称应该是有意义的,以传达它们在函数/方法中扮演的角色或者有关其内容的一些信息。

您可以看到构造函数的参数更为重要,因为它们通常是新实例工作所必需的,并且包含该类的其他方法所需的信息。

想象一下,你有一个Game课,它接受playerList

class Game:

    def __init__(self, playerList):
        self.playerList = playerList    # or self.players = playerList

    def printPlayerList(self):
        print self.playerList           # or print self.players

该类的各种方法都需要此列表。因此,将它分配给self.playerList是有意义的。您也可以将其分配给self.players,无论您感觉更舒服,认为可以理解。但是,如果您不将其分配给self.<somename>,则无法通过其他方法访问它。

因此,如何命名参数/属性/ etc(there are some special class methods though)并没有什么特别之处,但使用有意义的名称可以使代码更容易理解。或者,如果您有以下内容,您是否理解上述课程的含义:

class G:

    def __init__(self, x):
        self.y = x

    def ppl(self):
        print self.y

? :)它完全相同,但更难理解......