[英]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__
序列运行 - 现在我认为最好避免这种情况。
我的问题:
__init__
调用离开实例化,可以避免出现这种问题吗? self
传递给一个新实例,似乎它可能会因为自我引用而产生问题,是否也应该避免这种情况? 谢谢你的帮助。
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.