Need help with Python scoping rules
Steven D'Aprano
steve at REMOVE-THIS-cybersource.com.au
Wed Aug 26 11:32:38 EDT 2009
On Wed, 26 Aug 2009 10:57:32 +0000, kj wrote:
> In <7figv3F2m3p0dU1 at mid.uni-berlin.de> "Diez B. Roggisch"
> <deets at nospam.web.de> writes:
>
>>Classes are not scopes.
>
> This looks to me like a major wart, on two counts.
>
> First, one of the goals of OO is encapsulation, not only at the level of
> instances, but also at the level of classes. Your comment suggests that
> Python does not fully support class-level encapsulation.
I don't even know what that is supposed to mean. If anything, your
problem could be because Python has TOO MUCH "class-level encapsulation"
compared to what you are expecting: functions inside a class don't see
the class attributes you expect them too.
Actually, I think your problem is that you are interpreting what you're
seeing in terms of C++ or Java, and assuming that whatever they do is the
One True Definition of OO. That's hardly valid -- if any language
deserves the label of the One True OO Design, it might be Smalltalk, on
the basis that it was the first OO language. But even that is silly --
just because something was the first, that doesn't make it the best
example of something.
> Second, my example shows that Python puts some peculiar restrictions on
> recursion.
Incorrect. Recursive calls are just like any other function call in
Python: when you call *any* function from the body of a function, it must
be in scope at runtime.
def fact(n):
print g() # g must be in scope when fact is called
if n < 2: return 1
return n*fact(n-1) # fact must be in scope when fact is called
Python doesn't treat recursive functions specially in any way. It is
*classes*, not functions, that are special. This is explained in the docs:
http://docs.python.org/reference/executionmodel.html
It is also discussed in the PEP introducing nested scopes to Python:
http://www.python.org/dev/peps/pep-0227/
It's even eluded to in the tutorial:
http://docs.python.org/tutorial/classes.html
> Recursion! One of the central concepts in the theory of
> functions! This is shown most clearly by the following elaboration of
> my original example:
>
> class Demo(object):
> def fact_rec(n):
> if n < 2:
> return 1
> else:
> return n * fact_rec(n - 1)
Why are you defining a method without a self parameter?
In any case, the problem has nothing to do with recursion:
>>> class Broken:
... def f():
... return g()
... def g():
... return "gee"
... x = f()
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in Broken
File "<stdin>", line 3, in f
NameError: global name 'g' is not defined
> def fact_iter(n):
> ret = 1
> for i in range(1, n + 1):
> ret *= i
> return ret
>
> classvar1 = fact_iter(5)
> classvar2 = fact_rec(5)
>
> This code won't compile as shown,
That's nonsense. It compiles, and then it suffers a runtime error when
you *execute* it. (NameError occurs at runtime, not at compile time.)
You can prove this for yourself by putting that above class definition
inside a string, s:
>>> x = compile(s, '', 'exec')
>>> exec(x)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "", line 1, in <module>
File "", line 15, in Demo
File "", line 6, in fact_rec
NameError: global name 'fact_rec' is not defined
If you expect us to take your criticisms seriously, at least get your
basic facts right.
[...]
> Is there any good reason (from the point of view of Python's overall
> design) for not fixing this?
It doesn't need to be "fixed" because it's not broken. The question is,
should it be *changed* to match C++ programmers' expectations?
--
Steven
More information about the Python-list
mailing list