我也是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
传递给新实例,似乎可能因为自我引用而产生问题,是否也应避免这种情况?感谢您的帮助。
答案 0 :(得分: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()
(这是__init__(self)
类中Zeus
方法的另一个名称),然后将该方法返回的对象分配给全局变量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())。
答案 1 :(得分:4)
我认为这是因为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访问它。
答案 2 :(得分:1)
让我看看我是否可以举一个例子来帮助他。
如果我们想与一群希腊神一起工作,我们需要从一个非常简单的GreekGod
类开始:
class GreekGod(object):
def __init__(self, name):
self.name = name
zeus = GreekGod('Zeus')
athena = GreekGod('Athena')
print zeus.name
如果现在我们想要做更多的事情,例如在每个希腊神给他自己的epithet,我们需要在我们班上添加加词属性:
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
的角色,它代表了类中的对象实例。