Need help with Python scoping rules

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Thu Aug 27 05:14:41 EDT 2009


On Thu, 27 Aug 2009 08:38:29 +0200, Hendrik van Rooyen wrote:

> On Wednesday 26 August 2009 17:14:27 kj wrote:
> 
>> As I described at length in another reply, the function in question is
>> not intended to be "callable outside the class".  And yes,
> 
> I think this might go to nub of your problem - It might help you to
> think as follows:
> 
> A Python class, even after it has been executed, does not really exist
> except as a kind of template or pattern - it is mostly useless until an
> instance of the class is made by calling it with whatever it needs to
> set up the instance.  And once you have an instance, you can do stuff
> with that particular instance.  Before that time, the class is mostly
> just a promise of things to come.

Oh my! I couldn't disagree more strongly! I think the above is totally 
incorrect.

Classes and types are first class objects, you can treat them like 
anything else in Python. In fact, classes themselves are instances of 
type, so you can say:

>>> class C(object):  # must inherit from object
...     pass
...
>>> issubclass(C, object)
True
>>> isinstance(C, type)
True

Classes are themselves instances of their metaclass. By default, classes 
have a metaclass of type, but you can easily change that. Metaclass 
programming is advanced but very powerful.

Because classes are themselves objects, you can (with a bit of metaclass 
jiggery-pokery) make them do all sorts of interesting things. For 
instance, huge amounts of effort are often put into creating a Singleton 
class, a class that has a single instance. Well, okay... but why not just 
use the class object itself, instead of an instance? There's already one 
of those, and you can't (easily) make a copy of it, and even if you did, 
it would be an independent class. Instead of this:

singleton = SingletonClass(args)
do_something_with(singleton)

just do this:

do_something_with(SingletonClass)

Of course SingletonClass needs to be designed to work that way, which 
will probably need some metaclass magic. It would be interesting to see 
which requires less effort.

When it comes to built-in classes (types), I often use the class object 
itself as an object. E.g. I might do something like this:

def convert(seq):
    t = type(seq)  # remember the original type
    result = process(seq)  # always produces a list
    if t is list:
        return result  # don't bother making a copy of the result
    elif t is str or t is unicode:
        empty = t()
        return empty.join(result)
    else:
        return t(result)  # return the original type


>> recursive functions in Python *are* restricted in ways that
>> non-recursive functions aren't.  The examples I've posted prove this
>> point unambiguously.
> 
> Yes and no - mostly no -  your examples just illustrate the point I
> tried to make above.

Completely no. You may have missed the examples I've given, but the 
problems the Original Poster were having had nothing to do with recursion.


> Pythons object model, and its classes, are different from what you are
> used to.  A bare class is mostly useless without an instance, which is
> ultimately why accessing a function in a class from itself like you are
> doing, without reference to an instance, does not work - the function
> does not exist yet to a degree that it can be referenced.

That is incorrect. What's going on is more subtle.


>>> class Demo:
...     def function(x):
...         print "Calling function with argument %s" % x
...     function(None)
...     function(1)
...     function(function)
...
Calling function with argument None
Calling function with argument 1
Calling function with argument <function function at 0xb7d495dc>
>>> Demo
<class __main__.Demo at 0xb7d4e0ec>



-- 
Steven



More information about the Python-list mailing list