Overriding variables used by base classes

Corey Lubin google_mail at aristoweb.net
Tue Nov 18 02:41:31 EST 2003


[grr, had trouble posting via my own newsserver: "Done. Waiting for
confirmation"]

hungjunglu at yahoo.com (Hung Jung Lu) wrote in
news:8ef9bea6.0311150153.213d6de2 at posting.google.com: 

> Use
> 
> [tainted.py]
> import original
> original.someGlobal=2
> 
> class Tainted(original.Original):
>     pass
> [/tainted.py]
> 
> -------------------------

I discarded this idea very early on for a couple of reasons, one of
which may not be very important and another which might not have been
valid after all.

First of all, I wanted my tainted module to completely mimic the
interface of the original module. Importing in the style that you have
would not do so, as all names other than "Tainted" would have to be
prefixed by "original". I don't blame you for that, as my simplified
example only mentioned the class "Original" and didn't make it clear
that there may be other names in the original interface. Furthermore,
in this particular case, there probably /aren't/ any other names that
I would want to have carried over into my tainted module.

My second reason for not following that path was that I had the
impression that a particular module can only be imported once; any
further imports of the same module would just be implemented by
binding new names to the first copy of that module. When you import
"original" in the code above, does "tainted" get it's own copy of the
"original" module, or would other imports of the module be referring
to the same thing? If the answer is the former, then my concerns over
this approach were not valid. If the answer is the latter, then this
approach isn't acceptable.

To further expand upon my concerns raised in the last paragraph, I
want to have the choice to use either or both of tainted.Tainted and
original.Original; and when I use them I want them to have distinct
behaviour. The way I understand things, the "original.someGlobal=2"
line in your suggestion would forever scar the "original" module in
the memory of the python interpreter instance running that code. Ok,
the "forever" wasn't necessary, but I believe my point was made: we
would no longer just be making changes to "tainted", but also to
"original", which other user code may depend upon to act in it's
original way. In actuality this may not be an issue and I may only
need to use the modified version, but I tend to think in terms of
principles rather than whether something happens to work out in a
particular instance.

Just incase there is any ambiguity over my intentions, I've provided
code below:

[user.py]
import tainted
t = tainted.Tainted()
t.foo() # should behave in the altered/tainted way

import original
o = original.Original
o.foo() # should behave in the original way

tainted.someGlobal # should exist (not as important or hard to fix)
tainted.original.someGlobal # as opposed to this; AND...
tainted.someGlobal == original.someGlobal # should be false
[/user.py]

> (a) Python's namespace mechanism is hard to understand for newcomers.
> It is a fact, no matter how hard people try to deny it: your question
> has been asked a few hundred times before. But once you understand
> that assignment in Python is name binding and is very different from
> assignment in other languages like C/C++, you'll get used to it. Same
> with import and from ... import ... statements.
> 
> Namespace mechanism is the heart and soul of Python. When you have
> more time, try to read more and understand it. Otherwise you'll run
> into surprises in many places. When writing each line of Python code,
> you need to keep in mind what namespaces you are dealing with: an
> object's namespace? local dictionary? global dictionary? built-in?

Thanks for understanding my perspective, rather than working around it
or trying to change it. I'm taking your advice and have already
[re]read the related sections in the official Python tutorial and the
language reference.

> (b) Stay with your present approach. There is still no need for exec.
> Python is powerful enough to allow you to tweak many aspects of
> existing modules/classes/functions/methods without needing to evaluate
> code strings. What you are doing is called "patching". You are making
> a patch for existing module/class. If the changes are like adding
> attributes, surround a method with some around codes, those can be
> done easily with inheritance. If you need to override a foreign class
> method because you want to change the code in some spots inside the
> method, and the foreign class is used by other foreign
> classes/modules, you can write your code in your own module/class and
> replace the foreign implementation. Look into the documentation for
> the "new" module. In short, there are many ways to dynamically modify
> Python modules/classes/functions/methods.

You may or may not completely get my drift -- in that I'd like to
preserve the behaviour of the original code -- but this is all,
nonetheless, relevant and helpful.

> (c) More generally, what you want to do falls into the arena of
> Aspect-Oriented Programming. No need to understand it, now. But keep
> it in mind.

Will do.

Thanks,
Corey Lubin




More information about the Python-list mailing list