1

Newbie question about scope: in the following example, how is property able to get access to getx and setx etc. That is, why don't those names have to be qualified with a C.getx, for example? The code is directly from the python docs (https://docs.python.org/3/library/functions.html#property):

class C:
    def __init__(self):
        self._x = None

    def getx(self):
        return self._x

    def setx(self, value):
        self._x = value

    def delx(self):
        del self._x

    x = property(getx, setx, delx, "I'm the 'x' property.")

Update: based on comment

Conversely if I had a class like this

class A:
    def foo(self):
        print("foo")

    def bar(self):
        foo(self)

This would fail. Is that because CPython has no idea what's in bar until I actually try to run it (and at that point we are no longer in the class scope)?

Alex
  • 19,533
  • 37
  • 126
  • 195
  • 1
    Because upon class creation the code in the class body is run in its own scope. `getx`, `setx`, `delx` are simply functions defined in that scope. – a_guest Apr 19 '18 at 02:06
  • understood - let me just edit the question to follow up on this comment to clarify things ... – Alex Apr 19 '18 at 02:09
  • 2
    Based on update: Yes, this class scope ceases to exist when the class is created. The metaclass (in this case `type`) will add the single objects defined in that scope to the class as attributes. This is why you need to prefix the class for attribute access `A.foo()`. – a_guest Apr 19 '18 at 02:20
  • 1
    For a nice read on Python scoping rules see [this answer](https://stackoverflow.com/a/23471004). – a_guest Apr 19 '18 at 02:33

2 Answers2

3

The class is its own namespace until it is finalized, and so names inside it don't need to be qualified during class definition. (In fact, they can't be: the class doesn't yet have a name, so there is no way to specify the class as a namespace.)

class C:
    a = 0
    b = a + 1   # uses a from preceding line

In your class definition, getx, setx, and delx can be used unqualified because the property(...) call is executed during class definition.

After the class is finalized, the class has a name, and for methods that are called on instances, the instance has a name (traditionally self). Accessing attributes and methods at this point requires qualifying the name with either the class or instance reference (e.g. C.foo or self.foo).

kindall
  • 178,883
  • 35
  • 278
  • 309
  • Wow, such similar example : ) – Sraw Apr 19 '18 at 02:19
  • so it is the case that the interpreter simply never looks inside `bar` until it is called.. at that point the class is finalized and it's "creation" namespace is destroyed? if not, then why does `C.bar` not look at the parent scope as would happen with a nested function for example – Alex Apr 19 '18 at 02:22
  • 1
    Defining a function inside a class does not give the function any inherent knowledge of what class or instance it is defined in. A class is not a function's parent in a namespace sense. The namespace of a function isn't determined until runtime (which implies that methods of a class don't need to be defined in that class's definition). – kindall Apr 19 '18 at 02:42
0

That is because there are two different scopes. One is Class and one is function.

When you define a function in a class, that function is defined in Class scope. You can build a minimal example:

class A:
    a = 1
    b = a + 1
    pass

You can see that when defining b, we can directly access variable a as they are in the same scope A Class.

But when you use a Class scope variable in a function, that is another scope function. So in this case you need to manually specify scope.

Actually, this behave varies from language to language.

Sraw
  • 18,892
  • 11
  • 54
  • 87
  • right but if it's not in the current scope, won't CPython look in the parent scope (in this case being the class scope)? ie why is when `C.bar` is being defined, `foo` isn't searched for in `C` scope – Alex Apr 19 '18 at 02:21
  • 1
    @Alex A variable defined in `Class` scope is bound to `Class` but not instance, that means every instances of this class will share the same `Class` variables. But the variable used in methods is bound to instance. As far as I think, CPython **can** look in the parent scope, but that will be a little confuse as in runtime, a function in instance object need to look for variable in another object(Class object). – Sraw Apr 19 '18 at 02:29