2

I'm new to Python, targeting version 2.6 with forward compatibility to 3.x in mind. I am trying to wrap my head around what access to what variables are accessible from where. I already invested a lot of time in reading/understanding this topic, ultimately I would like to confirm the accuracy of my understanding of this topic.

Here's what I think I've got:

You can think of the "top level" of a Python script as being a "root object" that contains everything else in the program. It's like other instantiated objects, but has special features:

  • you can access its members (variables, functions, classes) from any function or class, without "self"

  • you can reassign its members from within any class or function by first using "global"

Any function/method, no matter how deeply nested, has access to all variables assigned anywhere above it. If the variable is a mutable object, its members can be changed, regardless of whether the variable is a member of the root object or more deeply nested.

If an existing variable name is used for assignment within a function, a new local variable with the same name, limited in scope to the function, is created. If there are multiple local variables with the same name in nested functions, the access is to the nearest enclosed local variable.

If the variable is a member of the root object (i.e. exists at the top level of the script) and "global" is used before the variable name is assigned, then no new local variable is created, so assignment applies to the member of the root object. In Python 3, "nonlocal" can be used similarly to have a variable assignment apply to the member of nearest enclosing function where the variable is assigned.

Because functions are created once upon execution, an object used as a default parameter assignment will persist across repeated calls to the function. If the object is mutable, changes to its members will also persist across calls to the function if the function doesn't reassign the variable name to another value.

The rules above apply inside a class, except that you need to refer to class members from within its methods via "self", and from outside the class via a reference to the class or an instantiation of the class.

You can execute statements in classes outside methods, like the "root object" does; however, they are executed immediately upon executing the class definition, not during instantiation. Class members can then be accessed from outside the class by referring to the class itself. It's as if when the class is defined, it is instantiated as as "class object" using its own name for the object, without calling the constructor. Further instantiations are shallow copies of that initial instantiation (the class object), in whatever state it exists, and execute the constructor if present. When referring to the class object rather than an instantiation, variables are accessible, but methods can't be called unless they are decorated with @classmethod (which allows access to class members) or @staticmethod (which doesn't).

Only references to the class members are copied during instantiation, so any assignments not within a method are "class variables" shared between all instantiations of the class. As with a function, assignments to the same variable name in an instantiated object will create a new variable limited in scope to that object, but changes to members of mutable objects will be seen across all instantiations of the class, including the class object, because the variables within those objects all refer to the same mutable object. To prevent variables from being shared across instantiations of the same class, they can be assigned within a method, using "self".

The class exists within whatever scope it is defined (e.g. it can be inside a function, and would be inaccessible outside of that unless the function returns the reference to the class, or assigns it to an outside variable it has access to, e.g. via global/nonlocal, or a class variable, or a member of a mutable object).

So, do I understand Python scoping yet? Thanks for any and all insight.

ρss
  • 5,115
  • 8
  • 43
  • 73
Ivan X
  • 2,165
  • 16
  • 25
  • 6
    Oh boy... I sense either a __lot__ of upvotes or a __lot__ of downvotes. – sshashank124 May 05 '14 at 09:02
  • Well, I figured I might as well dive in deep. – Ivan X May 05 '14 at 09:04
  • I don't blame you. It is great to see someone wanting to understand the concepts of scope. It's just that your question may not exactly be deemed "fit" for this site. – sshashank124 May 05 '14 at 09:06
  • surely ur question will be flagged as too broad – sundar nataraj May 05 '14 at 09:06
  • You can verify all this by simple experiments with code. It's a matter of few minutes, I guess a bit less then the time you've spent producing this wall of text. This question as a whole is too broad. You should start with experimenting and verifying your assumptions by yourself, and after identifying some particular issue you don't understand ask a question regarding some concrete piece of code. – BartoszKP May 05 '14 at 09:06
  • I sometimes get confused about how to vote/flag this kind of posts? :P I may upvote because you are at least trying something, but may be I downvote because I don't see any code snippet for playing around. So, finally I wait before any vote or flag. – ρss May 05 '14 at 09:06
  • @sshashank124 he is right.. – sundar nataraj May 05 '14 at 09:06
  • 3
    There is no "root object". There are modules, each .py file is a module. A module is a namespace (it can have variables in it). Other things can be namespaces too, like classes and instances. – RemcoGerlich May 05 '14 at 09:07
  • https://www.youtube.com/watch?v=xzjHT6CVcAA – Hypothetical Ninja May 05 '14 at 09:08
  • @pss, +1 for curiosity. -1 for broadness/verbosity. +1-1 = 0 --> Leave the question alone :) No votes – sshashank124 May 05 '14 at 09:08
  • 1
    @sshashank124 Yes, I usually prefer to encourage the new users. Because some day I was in the same stage. :) So, no votes or flags for this quest. – ρss May 05 '14 at 09:09
  • 1
    In my opinion this question is too broad as per *There are either too many possible answers, or good answers would be too long for this format. Please add details to narrow the answer set or to isolate an issue that can be answered in a few paragraphs.* This is not to say that it's a bad question, just too broad :/ – Ffisegydd May 05 '14 at 09:10
  • very tempted to +1 this, *and* vote to close :-). Another tip: be aware at all this whether you are *rebinding a name*, i.e. letting a variable refer to some other object (e.g., `x = 3`) or whether you're *mutating* the referred to object (`x.append(3)`). Rebinding by default creates a local variable, mutating doesn't change anything about variable bindings. – RemcoGerlich May 05 '14 at 09:10
  • 1
    @BartoszKP Thanks. I've spent the last *many* hours with simple code experiments -- like I said, I'm new at this -- arriving at these conclusions, which I think are accurate. However, the documentation of these things are scattered in multiple places, and I'm not sure I understand 100% of it, so I thought that a single reference could be useful, and that the pros could tell us noobs what we're missing. – Ivan X May 05 '14 at 09:11
  • Actually, this question looks like useful, but it's still *waaaaay* too broad. – vaultah May 05 '14 at 09:12
  • @frostnational, perhaps it should be turned into a wiki post? – dilbert May 05 '14 at 09:12
  • @RemcoGerlich So it might be semantically inaccurate, but doesn't the namespace at the top level of a .py file behave the same as an instantiated object, for the most part? Apart from being able to reference its members from anywhere? – Ivan X May 05 '14 at 09:16
  • 1
    MY PREDICTION HAS COME TRUE!!! (see first comment) – sshashank124 May 05 '14 at 09:17
  • 1
    possible duplicate of [Short Description of Python Scoping Rules](http://stackoverflow.com/questions/291978/short-description-of-python-scoping-rules) – thefourtheye May 05 '14 at 09:20
  • Once you are happy with the stage you are at, move on to embedded functions (functions within functions) and closures. See what happens to variables in those cases. When you move to Python 3, check-out `nonlocal`. – cdarke May 05 '14 at 09:21
  • @SundarNataraj Comments section should not be used to ask help with some other questions. It is totally not constructive, from this question's perspective. – thefourtheye May 05 '14 at 09:23
  • @ALL Please STOP spamming the comment section if you really want to discuss then please make a good use of chat. – ρss May 05 '14 at 09:23
  • 1
    Thanks to all who have constructively commented and edited. This is really helpful and I appreciate the community. I will make a point of future questions being more focused towards a specific answer. – Ivan X May 05 '14 at 09:39
  • Thanks all I did write an answer to this before closing as too broad :D – Antti Haapala -- Слава Україні May 05 '14 at 10:03
  • http://stackoverflow.com/questions/291978/short-description-of-python-scoping-rules/23471004#23471004 – Antti Haapala -- Слава Україні May 05 '14 at 11:09
  • @IvanX now that you have enough rep, you'd want to visit python chat at http://chat.stackoverflow.com/rooms/6/python – Antti Haapala -- Слава Україні May 05 '14 at 11:20

0 Answers0