__module__ (was Re: Deprecate self)

Alex Martelli aleaxit at yahoo.com
Thu Apr 19 12:42:11 EDT 2001


"Rainer Deyke" <root at rainerdeyke.com> wrote in message
news:vQpD6.47756$J%5.15806884 at news2.rdc2.tx.home.com...
    [snip]
> "Alex Martelli" <aleaxit at yahoo.com> wrote in message
> news:9bkvi30uf8 at news1.newsguy.com...
> > "Rainer Deyke" <root at rainerdeyke.com> wrote in message
> > news:OLlD6.46125$J%5.15304817 at news2.rdc2.tx.home.com...
> > How do you stop a class from having subclasses in Python?
>
> def f():
>   class C:
>     pass
>   C()

Ok, it's now clearer what you mean, thanks.  It doesn't
STOP somebody sufficiently determined from subclassing
it, of course:

class OhYeah(f().__class__):
    pass

but it does provide a rather good hint that "being
subclassed" is not the class's design intention:-).


> This is, incidentially, the idiom I had to use extensively to deal with
the
> lack of nested scoping in Python.  More generally, you write a class for

How does a local class help you there in ways nested
scoping will make obsolete?  Sounds interesting.


> > what is the supposed benefit of that -- assuming you can find any
> > benefits for the singleton DP anywhere, of course).
>
> The benefit of enforcing lack of inheritance?  There is none, unless you
> believe in the C++/Java way of preventing abuse through access
restrictions.

Java does enforce that, but in Python you get no "abuse
protection" (and no access restrictions) unless via
restricted execution, bastions &c (and C++, notoriously,
only "makes believe" any security accrues -- actually the
language standard makes it pretty clear that no abuse is
really prevented, but few practitioners seem to get it).

> The benefit of singletons?  Consider the following module:
>
> # spam.py
> def set_variable(name, value):
>   do_something()
>
> def get_variable(name):
>   return do_something_else()
>
> def del_variable(name):
>   do_something_completely_different()
>
> To facilitate easier access to these functions, I introduce the following
> wrapper:
>
> class VariableAccess:
>   def __setattr__(self, name, value):
>     set_variable(name, value)
>   def __getattr__(self, name):
>     return get_variable(name)
>   def __delattr__(self, name):
>     return del_variable(name)
> variables = VariableAccess()
>
>
> Now the client can access the revealed variables through a more natural
> interface.

Nice -- a specifically Pythonic benefit.  Of course, it's no
problem if VariableAccess gets multiply instantiated, so I
would consider this an example of the pattern "Featherweight"
(a class whose instances share all state) rather than one of
the pattern "Singleton" (a class that is protected against
being multiply instantiated), and I like FW as much as I
dislike Singleton, so there's still no benefit to the singleton
design pattern, but that's another issue.


> Consider the following hypothetical Python-like language:
>
> def f():
>   print 'spam'
>
> class C:
>   def f(): # Note lack of 'self'
>     print 'eggs'
>   def g():
>     __instance__.f()
>     __module__.f()
>
> I'm not sure I like this myself (the __magic__ names are too long, the
> result of a 'def' statement depends on context, there's no clear way to
> refer to the outer class from a method in an inner class, magically
> appearing variables have the potential to cause trouble, and the
> 'C.f(instance_of_C)' conventions seems to be broken), but at least it's
> better than the strawman against which you seem to have been arguing.

Actually, I think _this_ is "a strawman proposal" -- one with some
admitted defects but that at some level realizes design intentions.
Earlier, I saw complaints but no pointer to resolving them.

Thanks for posting it at last.  I fully agree with all of your
criticisms, and furthermore don't see how this will support the
useful idiom of assigning an existing function to serve as a method,
but then, pointing out such issues _IS_ a strawman proposal's role.

I do see one nugget here -- allowing access to a module object
through one of its own magic attributes may indeed be handier
than using globals(), sys.modules[__name__], and other existing
idioms.  The 'reference loop' it implies may be less terrible
today (what with weak references, garbage collection, etc) than
it may once have appeared.  Having each module object possess
a __module__ attribute that references the object itself seems
feasible, if the need to use that object is indeed frequent.

A somewhat related issue is somehow getting easy access to the
function object from that function's code -- particularly likely
to be interesting now that function objects have arbitrary
attributes.  Presumably harder as the __function__ (or
whatever) would have to be stuck in (the locals...?).  Just
an aside, anyway.


> I'm saying specifically that C++ is right in providing a way to qualify
> names as global - no more.

OK, I accept that's what you intended to say right from the
start.  Now, "global" in C++ means "global across all sources"
rather than "specific to this source".  Object specific to
this module would be in the unnamed namespace (since the
use of 'static' for that is [informally speaking only, I
believe] deprecated in C++) and thus non-qualifiable; other
(non-unnamed) namespaces are shared across sources.  Are
you expressing admiration for THIS trait of C++?  Or do you
actually wish to keep things Pythonically simple and is
the C++ reference some sort of red herring?  It's starting
to look that way to me.


> def factorial(n):
>   if n <= 1:
>     return 1
>   else:
>     return globals()['factorial'](n - 1)
>
> Do you actually write like that, or do you mean "I am too lazy to explitly
> qualify global names, explicit-better-than-implicit be damned, so
'globals'
> is good enough for me"?

I don't write like that, although my lack of qualification
for (module) globals stems from desire for simplicity and
clarity, rather than from laziness.  I do use globals() in
those rare instances where I feel I need it -- only one
that comes to mind readily is a function which is documented
to have a parameter named 'feep' (can't change that without
breaking client code) living in a module that is also
documented to have an attribute named 'feep' (ditto); then,
from within that function, accessing globals() is one
possibility if the global 'feep' is needed (there are
others, of course, such as a module-level
    _feep = feep
to provide handier internal access).

You _have_ convinced me that, if every module had a magic
attribute __module__ returning itself, some cases of such
explicit-to-global access would be facilitated wrt the
present situation.  And, although such need is rare in
my code, I have no basis for asserting that it would be
also rare in others' -- e.g., maybe somebody _IS_ designing
libraries where module-level attributes and function
optional arguments systematically share names, and has
data to show that this makes his clients' life easier.


> > What would the "over-specialized syntax" you are attacking be
> > in this case?  Please be specific.
>
> In this case, the 'global' statement.

I think I see -- if we had __module__, then the global
statement might eventually be deprecated in favor of
suggesting the idiom
    __module__.feep = 23
to rebind globals, rather than the present
    global feep
    feep = 23

An interesting possibility, and one worth thinking about
(I'm not sure I like it, but I'm also far from sure I
dislike it).  Discussion would have been shorter if you
had indicated this a TAD more explicitly from the start
rather than "deprecating self", lauding C++, etc, but
I guess that's just another explicit/implicit thing:-).
It _does_ look "more pythonic" than 'global', in a sense.

Why don't you do a PEP on this?  It seems definitely
worthwhile to discuss, and I don't think it will get
the attention it deserves when buried at the end of
a long post in a subthread of a long thread with a
title not very clearly related to it (though I've
tried to change subject in case this does help it get
read:-).


Alex






More information about the Python-list mailing list