2

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.

2
  • If you think one of the answers posted in response was helpful enough, you should accept it as the main answer by clicking the checkmark next to it. Commented Oct 23, 2014 at 18:03
  • @David well, both were helpful, but really to convince me to follow other way and abandon class nesting. Commented Oct 23, 2014 at 18:09

2 Answers 2

4

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).

Sign up to request clarification or add additional context in comments.

8 Comments

I can't believe I'm questioning Martijn Pieters, but... isn't the y inside a.__init__ an instance attribute of a? To be clear, I'm looking at the line self.y=9. So wouldn't it be visible as a().y?
@JohnY: ++++ OUT OF CAFFEINE ERROR ++++ REDO FROM START ++++ fzzzwt
Indeed I asked both for a.b() and a().b() to consider the case of y.
At least now I start to understand why nobody uses nested class declarations :-( But even if class objects do not create scopes (whatever a 2.7 scope is) they have some hierarchy: the class b is in the dict of class a, which in turn is in the dict of globals. I would expect b to have some way to access the x variable.
@arivero: it does have access to x. As a class attribute of a, so a.x.
|
2

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.

7 Comments

ok, could I add explicitly to b and d the fact that a is its previous namespace? Somthing as self['b'].vader=self at class level?
@arivero Not exactly sure what you mean, can you try to re-state your question?
I was thinking... some class method running after the definition of the a class and passing the information. Ok, will try an answer.
@arivero If you're saying that you want to set up some kind of hierarchy between instances of a, b, d, etc. you're free to do that. Just make sure it's the simplest way to do things given everything that python is capable of. I'd suggest you spend a bit more time learning about python classes before you decide that's the way to go.
@arivero Lol. You should probably edit your original question and include a note about what you decided to use. Then you should click the checkmark next to the answer that you thought was the most helpful. It's also good form to upvote any answer to your question that was helpful.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.