Classes are objects. In particular, they are (by default) instances of
class 'type'. Unless 'scopes' were instances of some other metaclass,
the statement has to be true. I understand 'scope' as referring to a
section of code, as opposed to a runtime object.
Class statements introduce a new local namespace used to define the
class. Whether one considers that as introducing a new 'scope' depends,
I suppose, on one's exact definition of scope.
This looks to me like a major wart, on two counts.
It is a 'wart' that a Python object is not a 'scope', whatever that is
to you? I have trouble comprehending that claim.
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 really do not see how your claim follows from the comment. The irony
of your 'two counts' is that the example of 'count 2' fails precisely
because of the encapsulation that you claim does not exist as 'count 1'.
Second, my example shows that Python puts some peculiar restrictions
on recursion.
I claim it does not. Name-based recursion inherently requires that a
function be able to access itself by name at the time it is called. This
can be a bit tricky, especially in a language with dynamic rather than
static name binding and resolution, as it requires that code within the
function be able to access a scope outside itself in which the function
name is defined. In other words, it requires that function code *not* be
completely encapsulated. It also require that the appropriate name be
used when there is one. Neither of these is a 'peculiar restriction'
imposed by Python.
class Demo(object):
def fact_rec(n):
if n < 2:
return 1
else:
return n * fact_rec(n - 1)
This function is just a function. It is not an instance method. It is
not even a class method. It does not belong here and should not be here.
If you insist on putting it where it does not belong, then you have to
call it by a name that works. If you only call it after the class
statement has finished, then 'Demo.fact_rec' works, as I believe someone
else pointed out.
If you want to call the function during class creation, before (in this
case) Demo exists, then binding it to a local name works. With 3.1
class Demo:
def f1(n):
if n < 2: return 1
else: return n * Demo.f1(n - 1)
def f2(n,f):
if n < 2: return 1
else: return n * f(n - 1, f)
cvar = f2(5, f2)
print(Demo.f1(5), Demo.cvar, Demo.f2(5,Demo.f2))
# prints120 120 120
Recursive functions should be OK wherever functions are OK.
Iteration can and has been viewed as within-frame recursion. When
iterative rather than recursive syntax is used, the naming issue is
avoided.
Is there any good reason (from the point of view of Python's overall
design) for not fixing this?
After reading the above, what, if anything, do you think still needs to
be fixed?
Before 2.2, Python functions were more encapsulated than they are today
in that they could only access local and global namespaces but not outer
function namespaces. It would be possible to further de-encapsulate
them by giving them direct access to lexically surrounding class
namespaces, but this would increase the problem of name clashes without
solving any real problems in proper Python code. It could also break the
intentional design principle that function code should mean the same
thing whether placed within or without a class statement. This principle
allows functions to be added to existing classes as attributes and work
as methods that same as if they had been defined with the class.
Terry Jan Reedy