Does Python have Class methods

David Bolen db3l at fitlinxx.com
Fri May 11 20:31:23 EDT 2001


costas at meezon.com (Costas Menico) writes:

> I have a class like this:
> 
> # class stored in c:\fooclass.py
> class fooClass:
> 	nm = 1
> 	def __init__(self):
> 		pass
> 
> 
> # Typed in interactive window
> import sys
> sys.path.append('c:\\')
> import fooclass
> f1 = fooclass.fooClass()
> f1.nm + = 1   # increment to 2
> 
> f2 = fooclass.fooClass()
> f2.nm  # Still gives 1
> 
> I thought here f2.nm would be a 2

Ah, good point - default handling of assignment at the instance level is
different in Python from, say C++ in that it creates new instance
attributes rather than traversing up to the class level object.

What's happening is that neither the f1 nor f2 instance initially have
an "nm" attribute - but they inherit it dynamically from their class
when accessed (in fact, it's no different than how method inheritance
works - both are just attributes in the object dictionaries).  But when
you assign to "f1.nm" you actually create a new attribute in the fm
instance, at which point you "hide" the class level attribute.  But
f2.nm is still inheriting from its class.

The assignment creating the attribute is the same mechanism that let's
you use an empty class to contain arbitrary stuff, ala:

    class junk:
        pass

    a = junk()
    a.foo = 10
    a.bar = 20

To observe the creation of the new attribute:

    >>> import fooclass
    >>> f1 = fooclass.fooClass()
    >>> f2 = fooclass.fooClass()
    >>> id(fooclass.fooClass.nm),id(f1.nm),id(f2.nm)
    (8142816, 8142816, 8142816)
    >>> f1.nm += 1
    >>> id(fooclass.fooClass.nm),id(f1.nm),id(f2.nm)
    (8142816, 8142792, 8142816)

Note that all references were to the same object until the increment, at
which point the result of the increment was a new integer object to
which a reference was placed in the f1 instance namespace.

If instead, the increment was done directly to the class object via
the class reference, then both instances would see it, ala:

    >>> f1 = fooclass.fooClass()
    >>> f2 = fooclass.fooClass()
    >>> f1.nm,f2.nm
    (1, 1)
    >>> fooclass.fooClass.nm += 1
    >>> f1.nm,f2.nm
    (2, 2)

This holds true whether the assignment is occurring external to the
object (as above) or within the object itself, say in a method.

So it's more appropriate to say that Python offers class-level
attributes that can be manipulated at the class level and which all
instances of that class will inherit from dynamically, but which can
be overridden at the instance level for any instance by creating an
attribute at that level (which normal assignment does).  This would be
different than C++ where a class (static) variable assignment within
the object goes to that class variable.

But you can still mimic the C++ behavior by just using class references
where appropriate.  If your object is using a setter/getter framework,
then it's easy enough to enforce within the object as well by just
referencing the class object explicitly, for example:

    class fooClass:
        nm = 1

        def __init__(self):
            pass

        def getnm(self):
            return fooClass.nm

        def setnm(self, value):
            fooClass.nm = value

    >>> import fooclass
    >>> f1 = fooclass.fooClass()
    >>> f2 = fooclass.fooClass()
    >>> f1.getnm(),f2.getnm()
    (1, 1)
    >>> f1.setnm(10)
    >>> f1.getnm(),f2.getnm()
    (10, 10)

If you want to use the more direct Python attribute access, then you can
trap __setattr__ and redirect the reference to the class level (you
could also override __getattr__ but normal inheritance is probably fine
for that), with something like:

    class fooClass:
        nm = 1

        def __init__(self):
            pass

        def __setattr__(self, name, value):
            if name == 'nm':
               fooClass.nm = value
            else:
               self.__dict__[name] = value


    >>> import fooclass
    >>> f1 = fooclass.fooClass()
    >>> f2 = fooclass.fooClass()
    >>> f1.nm,f2.nm
    (1, 1)
    >>> f1.nm += 10
    >>> f1.nm,f2.nm
    (11, 11)

You can get fancier and have __setattr__ just check any name against the
existing fooClass.__dict__ to dynamically adjust to any class level
additional attributes rather than hardcoding them.

I'm not sure if the Google URLs are persistent and postable yet, but if
you search on groups.google.com for a thread entitled "Class static
variables" there's a bunch of discussion there along these veins.

--
-- David
-- 
/-----------------------------------------------------------------------\
 \               David Bolen            \   E-mail: db3l at fitlinxx.com  /
  |             FitLinxx, Inc.            \  Phone: (203) 708-5192    |
 /  860 Canal Street, Stamford, CT  06902   \  Fax: (203) 316-5150     \
\-----------------------------------------------------------------------/



More information about the Python-list mailing list