Class-level variables - a scoping issue

Chris Torek nospam at torek.net
Sun Oct 10 13:11:58 CEST 2010


In article <4cb14f8c$0$1627$742ec2ed at news.sonic.net>
John Nagle  <nagle at animats.com> wrote:
>    Here's an obscure bit of Python semantics which
>is close to being a bug:

[assigning to instance of class creates an attribute within
the instance, thus obscuring the class-level version of the
attribute]

This is sort of a feature, but one I have been reluctant to use:
you can define "default values" for instances within the class,
and only write instance-specific values into instances as needed.
This would save space in various cases, for instance.

>     Python protects global variables from similar confusion
>by making them read-only when referenced from an inner scope
>without a "global" statement.  But that protection isn't
>applied to class-level variables referenced through 'self'.
>Perhaps it should be.  

It's not really clear to me how one would distinguish between
"accidental" and "deliberate" creation of these variables,
syntactically speaking.

If you want direct, guaranteed access to the class-specific variable,
using __class__ is perhaps the Best Way right now:

    >>> class K:
    ...     x = 42
    ...     def __init__(self): pass
    ... 
    >>> inst = K()
    >>> inst.x # just to show that we're getting K.x here
    42
    >>> inst.x = 'hah'
    >>> inst.x
    'hah'
    >>> inst.__class__.x
    42
    >>>

One could borrow the "nonlocal" keyword to mean "I know that
there is potential confusion here between instance-specific
attribute and class-level attribute", but the implication seems
backwards:

    nonlocal self.foo

implies that you want self.foo to be shorthand for self.__class__.foo,
not that you know that self.__class__.foo exists but you *don't*
want to use that.

If Python had explicit local variable declarations, then:

    local self.foo

would be closer to the implied semantics here.

As it is, I think Python gets this pretty much right, and if you
think this is more a bug than a feature, you can always insert
assert statements in key locations, e.g.:

    assert 'foo' not in inst.__class__.__dict__, \
        'overwriting class var "foo"'

(you can even make that a function using introspection, although
it could get pretty hairy).
-- 
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W)  +1 801 277 2603
email: gmail (figure it out)      http://web.torek.net/torek/index.html



More information about the Python-list mailing list