Best way to dynamically get an attribute from a module from within the same module
Rafe
rafesacks at gmail.com
Mon Dec 1 05:29:55 EST 2008
<snip>
> 3) using the bare name:
> whatever
> 1) and 2) are useful when the desired name is variable, not a constant like "whatever".
I thought that went without saying.
> > I have been using #1 for two reasons. First, I will never run this
> > module directly, so __name__ will always be the module name and not "__main__".
>
> (note that it works even with __main__)
Nice. Thanks.
> > Second, I can use this in a class to decide whether I want
> > the module where the class came from or, if I make the class a base
> I don't completely understand your use case. In the expression:
> getattr(some_module, attribute_name)
> you may use any module as the first argument (the current module, or any other).
Right, I was just confused about the effects of inheritance and scope.
If I put a method in a baseclass, which is inherited in another
module, and then run the method from an instance of the sub-class...
- "sys.modules[__name__]" returns the baseclass module.
- "sys.modules[self.__class__.__module__]" returns the subclass
module.
in the end I found it felt more logical to put the code in a module-
level function and call it from the class. All of this was part of a
fairly large factory method implementation.
I now know that globals() refers to module-level names. The pros and
cons were the main point of this thread and so far I have...
1) getattr(module, "whatever") seems the most pythonic way to do it
but it takes more than one line and requires a little more thought
about scope and inheritance.
2) globals()["whatever"] is concise, but it seems a little like a
shortcut which requires special knowledge (though a very small
amount).
I did a quick benchmark test:
< tmp2.py >
import time
import sys
import tmp
class A(tmp.A): pass
class B(tmp.A): pass
class C(tmp.A): pass
class D(tmp.A): pass
class E(tmp.A): pass
class F(tmp.A): pass
class G(tmp.A): pass
class H(tmp.A): pass
class I(tmp.A): pass
class J(tmp.A): pass
def test_globals_vs_gettattr():
t1 = time.time()
for i in range(0, 1000000):
H = globals()["H"]
t2 = time.time()
print "globals() too %s seconds." % str(t2-t1)
t1 = time.time()
mod = sys.modules[__name__]
for i in range(0, 1000000):
H = getattr(mod, "H")
t2 = time.time()
print "getattr() too %s seconds." % str(t2-t1)
< /tmp2.py >
tmp.py just has a simple class in it. I just wanted to add some
complexity, but I doubt this had any affect on the times.
>>> import tmp2
>>> tmp2.test_globals_vs_gettattr()
globals() too .146900010109 seconds.
getattr() too .434299993515 seconds.
Just to see how much the call to sys.modules was affecting the test, I
moved it outside the loop and reloaded the module for a second test.
>>> reload(tmp2)
<module 'tmp2' from '\\nas6tb\PROJECTS\tech\users\rafe.sacks\python
\tmp2.py'>
>>> tmp2.test_globals_vs_gettattr()
globals() too .139100003242 seconds.
getattr() too .254600000381 seconds.
This second test is pointless in practice since I would be calling
sys.modules each time anyway.
Even though the getattr() way is around 3.5 times slower, I had to run
the code 1,000,000 times before the difference became humanly
recognizable. I also realize benchmarks should be taken with a grain
of salt since my setup may differ greatly from others'.
I guess, in the end, I'd use getattr() because it feels more pythonic,
and more basic. I got pretty deep in to learning python before I had
to learn what the globals() dict could do for me.
Cheers,
- Rafe
More information about the Python-list
mailing list