arivero
arivero

Reputation: 955

namespace for class inside of class in python

I am trying to understand the nesting of namespaces in python 2.7.

Consider the following not-working code:

class c(object):
  def debug(self):
     print globals(),locals()
     print x,y

class a(object):
   x=7 
   def __init__(self):
     self.y=9
   class b(object):
      def debug(self):
         print globals(),locals()
         print x,y
   class d(c):
      pass

How do I access to the variables x and y, from the calls

a().b().debug()
a.b().debug()
a().d().debug()
a.d().debug()

None of them seems able to see either x nor y.

EDIT after discussion, it seems that what I want (avoid reference to globals) can be reached only by explicitly extending the information on the nested classes. For instance

class a(object):
   #
   @classmethod
   def _initClass(cls):
     for v in dir(cls):
       if type(cls.__dict__[v])==type:
         setattr(cls.__dict__[v],'vader',cls)   
   #
   x=7 
   class b(object):
     def debug(self):
       print b.vader.x
   class d(c):
     pass

 a._initClass()

And even this technique does not seem useful to access an instance variable, as intended in the a().d().debug sequence.

Upvotes: 2

Views: 1123

Answers (2)

David Sanders
David Sanders

Reputation: 4129

Martijn already gave a good answer, but I'll take a stab at my own.

As Martijn said, class declarations are executed rather like one-off functions, with their own local scope, when their module is first imported. Whatever's left over in this local scope, after everything in the class declaration has been executed, is used as the class's dictionary. So x, __init__, b, and d all end up being attributes on the a class object. The same is true of your classes b and d; their bodies are executed when the module is imported and the local scopes left over are used as their dictionaries as well.

The reason your code isn't working is that, by the time the debug method executes, the only scopes it's aware of are the global scope and its own local scope. In python, methods do not implicitly include a class instance's dictionary as part of their scope as they do in languages like C++. The class instance is available explicitly as the self argument which appears in the argument list (hence, Python's zen "explicit is better than implicit" -- try import this in the python console).

Also, it doesn't matter whether or not you instantiate a before accessing and instantiating the other classes b and d on a since b and d are both class attributes on a. Therefore, python can successfully retrieve b and d from either an instance of a or a direct reference to the a class object.

Upvotes: 2

Martijn Pieters
Martijn Pieters

Reputation: 1121972

class objects do not create a scope; class bodies are executed just once and discarded, the local namespace producing the class attributes. Class bodies never participate in nested scopes; they are ignored entirely when resolving non-local names.

As such, your x = 7 is not a name that the nested b class (or its methods) could ever access. Instead, it is a class attribute on a. Accessing a.x will work. y is an instance attribute, and you'll have to have a reference to the instance for it to be accessible anywhere else.

Note that this applies to class b as well; it is a class attribute on a now, just like x is a class attribute.

There is nothing special about your class b other than how you reference the class object. Just because you created an instance of a does not mean that b has any privileged access to it; a().b() does not create a relationship between the instances. You could do:

b = a.b
b_instance = b()

and there would be no difference. You could even do:

a.b.a = a
a.b.a()

and the world will not implode! (fancy that).

Upvotes: 4

Related Questions