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