Best way to dynamically get an attribute from a module from withinthe same module

R

Rafe

What are the pros and cons of these two patterns (and are there any
other)? Which is the best way to dynamically get an attribute from a
module from within the same module?

1) Using the name of the module
this_module = sys.modules[__name__]
attr = getattr(this_module, "whatever", None)

2) using globals
globals()["whatever"]


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__". 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
for a class in another module, the module where the sub-class is.

I am not familiar with the scope, pros or cons of globals() so I would
love to hear comments on this subject.


Cheers,

- Rafe
 
G

Gabriel Genellina

What are the pros and cons of these two patterns (and are there any
other)? Which is the best way to dynamically get an attribute from a
module from within the same module?

1) Using the name of the module
this_module = sys.modules[__name__]
attr = getattr(this_module, "whatever", None)

2) using globals
globals()["whatever"]

3) using the bare name:
whatever

1) and 2) are useful when the desired name is variable, not a constant
like "whatever".
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__)
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
for a class in another module, the module where the sub-class is.

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).
I am not familiar with the scope, pros or cons of globals() so I would
love to hear comments on this subject.

Perhaps if you explain in more detail your use case, somebody else may
have further comments...
I don't have the need to use globals()[name] very often.
 
R

Rafe

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.

(note that it works even with __main__)

Nice. Thanks.
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.
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.<module 'tmp2' from '\\nas6tb\PROJECTS\tech\users\rafe.sacks\python
\tmp2.py'>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
 
J

Jeremy Sanders

Rafe said:
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.

Why not store your individual classes inside another class or keep them in a
dict? That would be clearer, would not mess around with global namespace,
and more pythonic IMHO.

Jeremy
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top