繁体   English   中英

为什么在__init__期间实例化的对象不能看到它们的创建者?

[英]Why can't objects instantiated during __init__ see their creator?

好吧,我也是SO,OOP和python的新手,所以请温柔;)

我在其他地方寻找与此范围问题相关的线索和解释,但没有发现任何问题。 如有任何帮助,我将不胜感激。

示例代码:

class Zeus(object):
    def __init__(self):
        self.name='zeus'
        self.maze=Maze()
        self.maze.get_zeus_name_1()
        self.maze.get_zeus_name_2(self)
        self.get_name_1()
        self.get_name_2(self)

    def get_name_1(self):
        try:
            print zeus.name
        except:
            print "impossible!?"

    def get_name_2(self,scope):
        print scope.name

class Maze(object):
    def get_zeus_name_1(self):
        try:
            print zeus.name
        except:
            print "can't be done!?"

    def get_zeus_name_2(self,scope):
        print scope.name

zeus=Zeus()
print 'now external calls:'
zeus.maze.get_zeus_name_1()
zeus.maze.get_zeus_name_2(zeus)
zeus.get_name_1()
zeus.get_name_2(zeus)

输出:

can't be done!?
zeus
impossible!?
zeus
now external calls:
zeus
zeus
zeus
zeus

zeus实例化期间,如果__init__方法创建了另一个类的实例, maze ,这个新实例无法访问其创建者对象zeus (除非将self传递给它)。 (另外,如果__init__方法在其自己的类get_name_1调用方法,则该方法也无法访问其对象属性(除非将self传递给它)。)

然而,在对象被实例化之后,第二个对象, maze现在可以识别并访问其创建者对象zeus

这种行为给我带来了一些困惑和困难,因为我正在编写一些代码,其中所有内容都已初始化并从__init__序列运行 - 现在我认为最好避免这种情况。

我的问题:

  1. 为什么会这样?
  2. 通过__init__调用离开实例化,可以避免出现这种问题吗?
  3. 还有进一步的设计含义吗?
  4. self传递给一个新实例,似乎它可能会因为自我引用而产生问题,是否也应该避免这种情况?
  5. 其他有趣的含义/我错过了什么?

谢谢你的帮助。

get_zeus_name_1()正在尝试访问全局变量zeus ,该变量在调用get_zeus_name_1()时尚未初始化。

get_zeus_name_2()接受一个参数( scope )并访问它,这是有效的。 它不会尝试访问全局变量zeus

get_name_1()get_name_2()相同的故事。

我认为关键是要了解python如何执行这一行:

zeus=Zeus()

这行告诉python:执行方法Zeus() (这是Zeus类中__init__(self)方法的另一个名称),然后将该方法返回的对象分配给全局变量zeus

Python首先执行方法Zeus()然后, init方法完成执行并返回Zeus类的对象实例之后,python将该对象分配给全局变量zeus。 因此,在init方法完成之前,尚未定义全局变量zeus,因此get_name_1()和get_zeus_name_1()无法访问它。

get_name_2()和get_zeus_name_2()访问Zeus类的同一对象实例,因为get_name_1()和get_zeus_name_1()尝试访问,但是它们通过传递给它们的参数访问它,而不是通过全局变量访问它,所以它们不要遇到问题。

这是一个更简单的示例,演示了完全相同的问题:

>>> class Foo:
...     def __init__(self):
...         self.name = 'foobar'
...         print self.name
...         print foo.name
... 
>>> foo = Foo()
foobar
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __init__
NameError: global name 'foo' is not defined
>>> 

print self.name行工作正常(相当于get_name_2()和get_zeus_name_2()),但print foo.name行崩溃(相当于get_name_2()和get_zeus_name_2())。

我想这是因为Python本质 - 它“逐行”执行源代码。 在这一行: zeus=Zeus()你创建一个对象,并调用__init__方法。 当它执行时,还没有全局的zeus变量。 我想你抓到了NameError:名字'zeus'没有被定义(顺便说一句,捕获每个异常都是不好的做法, except: ... ;相反,你应该只捕获你期望的异常; except NameError: ... )。

你需要记住,在Python中,一切都在运行时发生。 这里

x = 1 # x is just created, y 2 isn't created yet, you can't access it
y = 2 # y is just created, you can use it

当模块A导入模块B时,这也可能导致循环导入,而模块B从模块A导入某些东西,但模块A尚未创建 - 错误。

在你的情况下,最好将原始Zeus对象的链接传递给Maze对象,如__init__ ,并且只有在完全创建Zeus对象后才能从Maze访问它。

让我们看看我是否可以举一个例子来帮助我。

如果我们想与一群希腊神一起工作,我们需要从一个非常简单的GreekGod类开始:

class GreekGod(object):

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

zeus = GreekGod('Zeus')
athena = GreekGod('Athena')
print zeus.name

如果现在我们想要做更多,例如在每个希腊神给他自己的加 ,我们需要在我们班上添加加词属性:

class GreekGod(object):

    def __init__(self, name, epithet):
        self.name = name
        self.epithet = epithet

    def get_catch_frase(self):
        return self.name + ' ' + self.epithet

zeus = GreekGod('Zeus', 'Father of the gods')
print zeus.get_catch_frase()  # -> Zeus Father of the gods

正如你所看到的方法get_catch_frase返回一个字符串,不打印该字符串,当你调用一个方法“get_something”时会出现这种行为,因为人们会期望返回的东西,而不是其他东西。

我也希望你看到self的角色,它代表了类中的对象实例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM