[Python-Dev] Re: Nested functions and class scope
Guido van Rossum
Tue, 14 Nov 2000 09:00:39 -0500
> Guido van Rossum wrote:
> > Looks like you are missing the point. Of course I want to keep the
> > class as a local scope *inside the class def*.
John Max Skaller replied:
> Ah, ok: seem's I was missing your intent.
> > But I need it out of the way when executing methods.
> I don't think this is the right idea. Consider:
> class X:
> x = 'x'
> def f(self): print x
> a = X()
> a.f() # should print 'x'
We understand each other perfectly. I just disagree with you on what
this example should do! I believe that in the sake of backwards
compatibility *as well as* not "giving in" to Java and C++ conventions
that I believe are a bad idea for Python, the reference to 'x' from
inside 'f' should not find the class variable 'x' but only a
Backwards compatibility: currently this program prints '1':
x = 1
x = 2
def f(self): print x
I believe it should not be broken; I expect that this is, for better
or for worse, a popular idiom, especially when you look at methods
rather than varibles. I believe it might be common to find this:
from lower_level_module import some_call
"OO wrapper around some_call()"
Your rule would break this, because the reference to some_call()
inside C.some_call() would be changed to make a (senseless, recursive)
reference to itself instead of to the globally imported some_call()
Java/C++ expectations: in Java/C++, the rules are different. Inside a
method, not just names defined in the current class are in scope, but
also all names defined in its base classes. Look at this:
# Module a.py
def f(self): pass
# Module b.py
def g(self): pass
Under your rules, the reference to g() in h() would work, but the
reference to f() would fail. In similarly structured Java or C++
code, h() could reference both g() and f() without a naming
Python requires that you specify the class when you reference a class
attribute (method or class variable). I don't want to lose this rule,
it is important (to me) for readability.
[...more examples elided...]
> The point is that I think there is not really much choice
> in the matter: when you lookup an unqualified name in a function,
> you must look in the function locals, then in the scope of the
> object in which the function is defined, and then in the scope
> in which that is defined .. and so ontil you reach the bottom
> of the stack (which presumably is 'builtins').
I claim different, and above I have explained why I think this is
necessary. I'd agree if you said "the scope of the *function* in
which it is defined."
> There's no real issue of keeping the class of the object
> of a bound method 'out of the way' when executing the function
> of the bound method. The scope of that class should be searched
> if, and only if, the function happens to have been defined
> inside that class. Note there is no such thing as a method
> in python: executing a bound (or unbound) method results
> in executing a plain old function.
If the code generator keeps track of the distinction between class and
function scopes, my rules can be implemented easily without
introducing a distinction between functions and methods.
> You _could_ exclude class scopes from the search stack
> associated with a function, and just search locals, then
> enclosing functions, then the enclosing module and finally
> builtins. But it would be highly inconsistent, and not what
> people used to lexical scoping would expect.
Yet, this is what I want. It's impossible to design things so that
people coming from very different backgrounds will never encounter a
surprise. Since Python is primarily an OO language, and there's ten
years of established Python rules, I prefer to give the OO people and
existing Python users an easier time (note that the OO people at least
can count on *consistently* not seeing the class scope in the
"methods") and tell the lexical-scoping people about the exceptions.
> It will be hard
> enough to explain the _consistent_ rule that only local
> bindings can be changed by assignments -- unless a global
> directive changes that. But that rule IS consistent (and the
> global directive much less so!)
> I think there is general agreement that lexically
> scoping functions inside functions will not break much code.
> Do you have an example of real application code where searching a class
> in which a function is defined will break code?
I haven't found one yet, but I've seen plenty of examples where a
class defines a method with the same name as a global function
(including lots in the standard library -- it really is a common
idiom). I think this comes too close to risk breakage.
But even if we find that this doesn't break anything, I still think
it's unwise to allow unqualified access to class attributes from
within methods. People would discover that in this example:
m2a() and m2b() would be equivalent, i.e. m1(self) and self.m1() are
equivalent. That's evil, because it opens up a meaningless choice
between alternative (and the m1(self) notation is inferior, because it
doesn't look in base classes).
But I'm beginning to repeat myself, so I think I've said all that can
be said about this. Sorry the scope rules in Vyper are wrong.
--Guido van Rossum (home page: http://www.python.org/~guido/)