6

I have a problem understanding what is happening with the outcome of the following pieces of code:

my_str = "outside func"
def func():
    my_str = "inside func"
    class C():
        print(my_str)
        print((lambda:my_str)())
        my_str = "inside C"
        print(my_str)

The output is:

outside func
inside func
inside C

Another piece of code is:

my_str = "not in class"
class C:
    my_str = "in the class"
    print([my_str for i in (1,2)])
    print(list(my_str for i in (1,2)))

The output is:

[‘in the class’, 'in the class’]
['not in class’, 'not in class’]

The question is:

  1. What is happening here in each print() statement?
  2. Can anyone explain why the print() statement get the string from the different namespaces?

Edit 1:

I think this is different from this question because I humbly think the answers there do not explain this variation:

my_str = "outside func"
def func():
    my_str = "inside func"
    class C():
        print(my_str)
        print((lambda:my_str)())
       #my_str = "inside C"
        print(my_str)

The output is:

inside func
inside func
inside func

Edit 2:

Indeed, this is a duplicate from this question because as Martijn Pieters says:

The answer there states: If a name is assigned to within a class body, almost at the start. You assigned to my_str, making it the same case as y there. Commenting out that line means you are no longer assigning to my_str, making it the same case as x.


Community
  • 1
  • 1
Dargor
  • 623
  • 1
  • 4
  • 12
  • @MartijnPieters Antti's beautiful answer there covers the first case. The second case trickles down to that but yet it is not a exact dupe. Perhaps I will leave that link there for future visitors to this question. (You've already prepared the draft rite ;)) – Bhargav Rao Jun 04 '15 at 14:26
  • 2
    @BhargavRao: sorry, I actually assumed you were linking to [Short Description of Python Scoping Rules](http://stackoverflow.com/q/291978)! This is indeed a dupe. – Martijn Pieters Jun 04 '15 at 14:27

1 Answers1

5

There are four scopes here:

  1. the global scope
  2. the function scope
  3. the class body
  4. the lambda scope

When creating a class statement, the class body is executed as a function would and the local namespace of that 'function' is used as the class attributes.

However, a class body is not a scope, and as such behaves differently from functions. In a function body, binding defines scope; assign to a name in a function and it is marked as a local. In a class, assigning to a name makes it a global until you actually do the assignment.

So your first print() call finds my_str as a global, because later in the class body you bind to the name. This is a consequence of class bodies not taking part in scopes.

Next, you define a lambda and call it. my_str is never assigned to in that lambda so it has to be found in a parent scope. Here the class body is not a scope, and the next scope up is the function scope. This is why that line prints inside func.

Last, you assign to the local name my_str in the class body, and print that local.

The moment you remove the assignment, the names in the class are treated as non-local; the first and last print() statements are now equal, and the name is simply looked up according to the normal scoping rules.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Could you extend your answer to explain the variation of Edit1 ? – Dargor Jun 04 '15 at 14:28
  • 3
    @PabloGalindoSalgado: your edit only *confirms* that the post is a dupe. – Martijn Pieters Jun 04 '15 at 14:30
  • I'm so sorry, then. I read the answers twice and do not understand that variation....but is straightforward as you said. Time for coffee. :( – Dargor Jun 04 '15 at 14:32
  • @PabloGalindoSalgado: The answer there states: *If a name is assigned to within a class body*, almost at the start. You assigned to `my_str`, making it the same case as `y` there. Commenting out that line means you are no longer assigning to `my_str`, making it the same case as `x`. – Martijn Pieters Jun 04 '15 at 14:33
  • Today I am not being careful enoght. My apologies and sorry for the confusion. – Dargor Jun 04 '15 at 14:35