I'm trying to understand how scopes work within a class definition.
I'll quickly illustrate with an example. Say I had the following class
definition:
class Abc:
message = 'Hello World'
def print_message(self):
print message
>>> instance = Abc()
>>> instance.print_message()
NameError: global name 'message' not defined
My question is, why? message is not defined in print_message, but it
is defined in the enclosing scope (the class)?
Thanks!
A class' scope is never consulted when resolving variable names in its methods.
The scopes consulted are roughly (and in this order):
1. Local variable scope (i.e. of the current function/method)
2. Enclosing functions (if you have functions nested inside other functions)
3. Globals (i.e. module-level variables)
3. Builtins (i.e. the built-in functions and methods, such as len())
To access class-level variables from within instance methods of the
class, you have 2 options:
A. Use the class name, i.e. Abc.message
B. Reference the class indirectly, i.e. self.__class__.message
Cheers,
Chris
--
http://blog.rebertia.com
It's a deliberate design decision. I don't recall the reasons for it, but
the class namespace is deliberately excluded from the method scope.
The correct way of writing the above is:
class Abc:
message = 'Hello World'
def print_message(self):
print self.message
self.message will first search the instance namespace for an attribute
`message`, then search the class, then any superclasses. If you
specifically want the class attribute, even if the instance masks it with
an instance attribute of the same name, you do this instead:
print self.__class__.message
--
Steven
Note that when *running* the code that is *inside* print_message() method
called within the global scope, the outer (enclosing) scope is indeed the
global scope (the scope in which e.g. 'instance' name exists; note that
e.g. 'print instance' in that method would be ok).
As Chris wrote, class' scope (contrary to outer function scope) is not
considered as the 'enclosing' scope.
The only ways to reach Abc's attribute 'message' from that method are:
* 'Abc.message'
* 'self.__class__.message'
* 'self.message' (unless there is an instance attribute 'message' which
overrides the class attribute).
Cheers,
*j
--
Jan Kaliszewski (zuo) <z...@chopin.edu.pl>
> The only ways to reach Abc's attribute 'message' from that method are:
> * 'Abc.message'
> * 'self.__class__.message'
> * 'self.message' (unless there is an instance attribute 'message' which
> overrides the class attribute).
And of course getattr(Abc), getattr(self.__class__) etc. :-)
Out of 'Abc.message' and 'self.message', which is the favoured
convention? It would be very easy to accidentally override
'self.messages' with an instance attribute!
> Out of 'Abc.message' and 'self.message', which is the favoured
> convention?
It's not a matter of convention. They mean different things, so you use
each depending on what you mean.
> It would be very easy to accidentally override 'self.messages' with an
> instance attribute!
Right. So you use ‘Abc.message’ when you specifically want a class
independent of any instance, and you use ‘self.message’ when you want
the attribute of this instance (with fallback to the usual resolution
order).
--
\ “Any intelligent fool can make things bigger and more complex… |
`\ It takes a touch of genius – and a lot of courage – to move in |
_o__) the opposite direction.” —Albert Einstein |
Ben Finney
> Right. So you use ‘Abc.message’ when you specifically want a class
> independent of any instance
That's “a class attribute independent of any instance”, of course.
--
\ “Humanity has advanced, when it has advanced, not because it |
`\ has been sober, responsible, and cautious, but because it has |
_o__) been playful, rebellious, and immature.” —Tom Robbins |
Ben Finney
Or even simpler - *if* there's no synonym instance attribute:
=> self.message
Attribute lookup will try to resolve the attribute name on the class
(and it's parent classes) if it's not found on the instance.
> Out of 'Abc.message' and 'self.message', which is the favoured
> convention? It would be very easy to accidentally override
> 'self.messages' with an instance attribute!
Only use 'Abc.message' if you want to make sure you get the Abc class
'message' attribute - that is, if you want to skip possible overrides in
subclasses. As far as I'm concerned, I'd tend to consider this bad style
unless it's a very very specific implementation point of an abstract
class (in which case it would probably be named '__message' to prevent
accidental override) - but YMMV of course.
Use 'self.__class__.message' (or 'type(self).message') if you want to
make sure you get the class 'message' attribute - that is, if you want
to honor possible overrides in subclasses, but not per-instance
override. But then - at least in your example code - I'd use a classmethod:
class Abc:
message = 'Hello World'
@classmethod
def print_message(cls):
print cls.message
Now the most common idiom - that is, outside classmethods - is to just
use 'self.message'. Someone (even you) might have a very valid reason to
override the 'message' attribute on a per-instance basis. FWIW, if you
start to worry about possible accidental overrides here, then Python
might not be the right language for you - nothing prevents "accidental"
overrides of method and even the class (the '__class__' attribute)
itself - yes, they are all attributes, and you can dynamically override
them !-)