Need help with Python scoping rules

Ulrich Eckhardt eckhardt at satorlaser.com
Wed Aug 26 13:17:22 EDT 2009


kj wrote:
> class Demo(object):
>     def fact_iter(n):
>         ret = 1
>         for i in range(1, n + 1):
>             ret *= i
>         return ret
> 
>     def fact_rec(n):
>         if n < 2:
>             return 1
>         else:
>             return n * fact_rec(n - 1)
> 
>     classvar1 = fact_iter(5)
>     classvar2 = fact_rec(5)
> 
> 
> In the initialization of classvar1, fact_iter is invoked without
> any problem even though the class is not yet created: no need to
> qualify it with the name of the class.  This is completely inconsistent
> with the requirement that fact_rec be so qualified when invoked
> within fact_rec.

Let me take a shot at explaining this, maybe it helps that I'm mostly a C++
guy....


Firstly, if Python sees a name, it looks up that name first in the local
scope and then in the global scope. This is very simple (especially
compared to C++ when adding ADL there...), but it is something most people
can live with. So, even inside a class function (static or member), you
have to qualify a function call like 'ClassName.function_name', because
neither is 'function_name' a local nor is it a global.

Secondly, and that is due to the very dynamic nature of Python's types, the
class doesn't exist until its definition is finished. Therefore, any
attempt (directly or indirectly) to access a class member will usually fail
before that time. The exception is that inside the class definition you can
access the members directly, because they are in the same scope (access to
locals). Note that the scope already seems to exist but that it is not yet
available under any name! Looking at your example, you can not
write 'classvar1 = Demo.fact_iter(42)', because the lookup of 'Demo' will
fail.

Now, what actually causes problems is that 'fact_rec' is not universally
accessible until class 'Demo' is fully defined, but you need this in order
to fully define it. Here comes a drawback of the dynamic nature of Python,
that the declaration phase (compiling) is not separate from the execution.

I fully agree that this case is rather vexing to my (and obviously your)
biased brain. I wouldn't call this a bug before fully understanding why
e.g. you can not access a class before its definition is finished. I think
someone mentioned one or two PEPs, which are the design documents that
explain Python including the rationale, I'd use that as a starting point.


Suggestion: someone mentioned that you should make the function a normal
function. You can mark it as private using an underscore as prefix. If you
want to make it foolproof, you could even delete ("del fact_rec") the
function after use. Other alternatives would be to put it into a separate
baseclass, use a local function as implementation or to add the class
attributes after defining the class. Neither of these provide the 'perfect'
encapsulation of things in a class that you might be used to from e.g.
Java, but they have proven to be very useful nonetheless.


Uli

-- 
Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932




More information about the Python-list mailing list