[Tutor] class variables [was Tutor Digest, Vol 118, Issue 99]

Steven D'Aprano steve at pearwood.info
Sat Dec 21 16:59:48 CET 2013


(I fixed the subject line for you.)

On Sat, Dec 21, 2013 at 02:53:28AM -0500, Keith Winston wrote:
> On Sat, Dec 21, 2013 at 2:14 AM, <tutor-request at python.org> wrote:
> 
> > I don't like the terms "class variable" and "instance variable". In the
> > Python community, these are usually called class and instance attributes
> > rather than variables or members.
> >
> 
> Hey Steven, that was a very generous explanation. Thanks! Very clear. I was
> floundering over the simple name/concept of attibute, and it had undermined
> my reading of other material. Your examples were extremely helpful. I think
> I understood everything you said (after a second reading). 

Glad to be of service!


> I keep hearing
> about how Python creates namespaces which I think are dictionaries, I'm
> going to have to look into that further to understand how some of this fits
> together.

Think of a typical family. Unless you're one of George Foreman's five 
sons all called George, chances are that everyone in the family has a 
different name. (Or at least a different nickname.) "Fred" in your 
family is not the same as "Fred" in my family. In this case, the family 
plays the role of a namespace: everyone inside the family has a unique 
name that they are known by, but people in different families can have 
the same name.

In general, a "namespace" is some sort of environment or container that 
holds identifiers (such as names, or ID numbers). Within a single 
namespace, all identifiers have to be unique, but two different 
namespaces can hold the same identifier. For example, in Python, each 
module is a namespace. If you have two files, say "spam.py" and 
"eggs.py", the two modules may include variables with the same name:

spam.thing = 23
eggs.thing = 42

Even though they are both called "thing", they live in different 
namespaces so they can have different values.

Python namespaces are usually dictionaries. The globals() function 
returns the global namespace, which is a dict. You will find all your 
global variables in it. Here's an example:

py> x = 23
py> d = globals()
py> d['x']
23
py> d['x'] = 42
py> x
42


(Note: operating directly on globals(), as I do in that example, is not 
a common thing to do. Python gives you the ability to do so, but it's 
quite rare to actually need it.)

Classes and instances also behave as namespaces. Both normally have a 
special attribute called "__dict__" (that's two underscores at the start 
and end of the name). Class.__dict__ holds the class attributes, 
including methods. The instance __dict__ holds the instance attributes.

Rather than access the __dict__ directly, it is nearly always better to 
use getattr and setattr functions. That is:

# don't do this
obj.__dict__['attribute'] = 23

# this is better
setattr(obj, 'attribute', 23)

# but this is even better
obj.attribute = 23


The main reason for using getattr and setattr is when you don't know the 
name of the attribute when you write the code, but only at runtime. For 
example:

name = get_some_name()  # returns some attribute name
getattr(obj, name)

You can't use obj.name, since that will return the attribute called 
literally "name". In this case, you want the attribute named *by* name 
instead -- if name == "colour", you want obj.colour, if name == "height", 
you want obj.height, and so on.


> I think that's where Python is going when you're talking about
> looking up attributes (and it would include methods too, unless they're
> still functions... maybe they're methods for instances and functions for
> classes? Ok, I don't get that part yet).

Methods and functions are another story, but in a nutshell, methods are 
just like functions except that they live inside classes, and when you 
call a method, it automatically gets the instance as the first argument. 
Confused? Here's an example, using a string method.

Strings have a method, replace, that works like this:

py> "the cat in the hat eats green ham".replace("cat", "dog")
'the dog in the hat eats green ham'


If replace were a function, we would write it something like this:

# simplified version
def replace(s, old, new):
    ...


and you would call it like this:


replace("the cat in the hat eats green ham", "cat", "dog")
=> returns "the dog in the hat eats green ham"


So you can think of the difference between methods and functions that 
methods use the syntax:

    arg1.method(arg2, arg3, ...)

instead of:

    function(arg1, arg2, arg3, ...)


There are other differences, but that is the most important one.



-- 
Steven


More information about the Tutor mailing list