well I’m new to SO, OOP and python too, so please be gentle 😉
I’ve looked for threads and explainations related to this scoping issue elsewhere and haven’t found any. I would be grateful for any assistance.
Sample code:
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)
Output:
can't be done!?
zeus
impossible!?
zeus
now external calls:
zeus
zeus
zeus
zeus
During instantiation of zeus, if the __init__ method creates an instance of another class, maze, this new instance is not able to access its creator object, zeus (unless self is passed to it).
(Additionally, if the __init__ method calls a method within its own class, get_name_1, that method cannot access its objects attributes either (unless self is passed to it).)
However, AFTER the objects are both instantiated, the second object, maze can now recognise and access its creator object, zeus.
This behaviour has caused me some confusion and difficulties, as I was working on some code where everything was initialised and run from the __init__ sequence – now I suppose that it is better to avoid that..
My questions:
- Why is this the case?
- Are problems that can arise through this best avoided by leaving instantiation, out of
__init__calls? - Are there further design implications?
- Passing
selfto a new instance, seems as though it could create problems, due to self-referencing, should this also be avoided? - Other interesting implications/ Am I missing something?
Thanks for your help.
get_zeus_name_1()is trying to access the global variablezeus, which has not yet been initialised at the moment whenget_zeus_name_1()is called.get_zeus_name_2()takes an argument (scope) and accesses that, which works. It doesn’t try to access the global variablezeus.Same story with
get_name_1()andget_name_2().I think the key point is to understand how python executes this line:
This line says to python: execute the method
Zeus()(which is another name for the__init__(self)method in theZeusclass), and then assign the object returned by that method to the global variablezeus.Python first executes the method
Zeus()and then, after the init method has finished executing and returned an object-instance of the Zeus class, python assigns that object to the global variable zeus. So the global variable zeus has not been defined until after the init method finishes, so get_name_1() and get_zeus_name_1() cannot access it.get_name_2() and get_zeus_name_2() access the same object-instance of the Zeus class as get_name_1() and get_zeus_name_1() try to access, but they access it via a parameter that is passed to them, not via the global variable, so they don’t run into the problem.
Here is a simpler example that demonstrates exactly the same problem:
The
print self.nameline works just fine (equivalent to get_name_2() and get_zeus_name_2()), but theprint foo.nameline crashes (equivalent to get_name_2() and get_zeus_name_2()).