Why no lexical scoping for a method within a class?

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Wed Dec 17 20:15:36 EST 2008


On Wed, 17 Dec 2008 10:20:21 -0800, walterbyrd wrote:

> On Dec 17, 10:00 am, r <rt8... at gmail.com> wrote:
>> When writing
>> procedural code how would you like it if vars inside functions were
>> automatically global. Your code with be blowing chunks in no time.
> 
> That was my point - I consider python's ordinary use of lexical scoping
> to be a good thing, and I was wondering why this "good thing" was not
> used in classes, as well as outside of classes.

But it is. You're mistaking lexical scoping for object attribute access. 
The rules for lexical scoping inside a class are (almost) the same as 
they are for inside a function:

def parrot(breed):
    def message(colour):
        return "The %s %s has beautiful plumage." % (breed, colour)
    return message("Blue")

class Parrot:
    def parrot(self, breed):
        def message(colour):
            return "The %s %s has beautiful plumage." % (breed, colour)
        return message("Blue")

And in use: 

>>> parrot("Norwegian")
'The Norwegian Blue has beautiful plumage.'
>>> p = Parrot()
>>> p.parrot("Swedish")
'The Swedish Blue has beautiful plumage.'


Notice that to have lexical scoping work, you actually have to nest the 
functions. Otherwise they are in different scopes.


This might lead you believe you can do this:

class Parrot2:
    colour = "Blue"
    def parrot(self, breed):
        return "The %s %s has beautiful plumage." % (breed, colour)


>>> p = Parrot2()
>>> p.parrot("Norwegian")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in parrot
NameError: global name 'colour' is not defined

What's going on? Why doesn't the parrot method see the name "colour" in 
the class scope?

The reason is that the class scope is deliberately left out of the nested 
scope chain. This was a design decision from when nested scopes were 
introduced: 

"An alternative would have been to allow name binding in class
scope to behave exactly like name binding in function scope.  This
rule would allow class attributes to be referenced either via
attribute reference or simple name.  This option was ruled out
because it would have been inconsistent with all other forms of
class and instance attribute access, which always use attribute
references.  Code that used simple names would have been obscure."

http://www.python.org/dev/peps/pep-0227/

So inside the method, you need to refer to Parrot.colour (or thanks to 
the rules of attribute inheritance, self.colour).

Classes could be closures, but that could radically change the way 
methods and classes work. Depending on design decisions, it might require 
huge changes to the Python compiler. How would it change the existing 
lexical scoping in factory functions?

def factory(colour):
    class Parrot:
        def parrot(self, breed):
            return "The %s %s has beautiful plumage." % (breed, colour)
    return Parrot

>>> redparrot = factory("Red")()
>>> redparrot.parrot("Swedish")
'The Swedish Red has beautiful plumage.'


Consider a hypothetical Python with classes included in the lexical 
scoping:

class Parrot3:
    colour = "Blue"
    def parrot(self):
        colour = "Red"


What should method parrot do? I can think of at least three possibilities:

* create a local name colour inside the method scope;
* change the class attribute Parrot3.colour to "Red";
* create an instance attribute self.colour.

Whatever solution you come up with, there is potential inconsistency with 
other parts of the language.



-- 
Steven



More information about the Python-list mailing list