(newbie) Is there a way to prevent "name redundancy" in OOP ?

Martin Miller ggrp1.20.martineau at dfgh.net
Sat Jan 6 19:49:20 EST 2007


Carl Banks wrote:

> Martin Miller wrote:
> > ### non-redundant example ###
> > import sys
> >
> > class Pin:
> >     def __init__(self, name, namespace=None):
> >         self.name = name
> >         if namespace == None:
> >             # default to caller's globals
> >             namespace = sys._getframe(1).f_globals
> >         namespace[name] = self
> >
> > Pin('aap')      # create a Pin object named 'aap'
> > Pin('aap2')     # create a Pin object named 'aap2'
> > print aap.name
> > print aap2.name
>
> The problem with this is that it only works for global namespaces,
> while failing silently and subtly if used in a local namespace:

Oh, contrair. It would work fine with local namespaces simply by
overriding the default value of the optional 'namepace' parameter (see
below).

> def fun():
>     Pin('aap')
>     aap1 = aap
>     fun2()
>     aap2 = aap
>     print aap1 is aap2
>
> def fun2():
>     Pin('aap')
>
> If it's your deliberate intention to do it with the global namespace,
> you might as well just use globals() and do it explicitly, rather than
> mucking around with Python frame internals.  (And it doesn't make the
> class unusable for more straightforward uses.)

You could be more explicit by just passing 'globals()' as a second
parameter to the __init__ constructor (which is unnecessary, since
that's effectively the default).

It's not clear to me how the example provided shows the technique
"failing silently and subtly if used in a local namespace" because what
happens is exactly what I would expect if the constructor is called
twice with the same string and defaulted namespace -- namely create
another object and make the existing name refer to it. If one didn't
want the call to Pin in fun2 to do this, just change fun2 to this:

def fun2():
    Pin('aap', locals())

This way the "print aap1 is aap2" statement in fun() would output
"true" since the nested call to Pin would now (explicitly) cause the
name of the new object to be put into fun2's local namespace leaving
the global one created by the call in fun() alone.

Obviously, this was not an objection I anticipated. An important one I
would think is the fact that the current documentation says that
f_globals is a special *read-only* attribute of a frame object implying
that it shouldn't be changed (even though doing so 'works' as my
example illustrates).

I think other valid arguments against this practice might include
whether it's an example of good OOP, or a good programming practice at
all, since it involves possibly subtle side-effects, the use of global
variables, and/or is 'unpythonic'.

Certainly the approach is not without caveats. Despite them, I believe
it can be useful in some contexts, as long as what is going on is
clearly understood. The point of my reply to the OP was mainly just to
illustrate the power and flexibility of Python to the newbie. I guess
to that I should have also added that it gives you "enough rope to
shoot yourself" as Allen Holub said regarding C++.

Cheers,
-Martin




More information about the Python-list mailing list