How do I call setattr() on the current module?
Solution 1
import sys
thismodule = sys.modules[__name__]
setattr(thismodule, name, value)
or, without using setattr
(which breaks the letter of the question but satisfies the same practical purposes;-):
globals()[name] = value
Note: at module scope, the latter is equivalent to:
vars()[name] = value
which is a bit more concise, but doesn't work from within a function (vars()
gives the variables of the scope it's called at: the module's variables when called at global scope, and then it's OK to use it R/W, but the function's variables when called in a function, and then it must be treated as R/O -- the Python online docs can be a bit confusing about this specific distinction).
Solution 2
In Python 3.7, you will be able to use __getattr__
at the module level (related answer).
Per PEP 562:
def __getattr__(name):
if name == "SOME_CONSTANT":
return 42
raise AttributeError(f"module {__name__} has no attribute {name}")
Solution 3
If you must set module scoped variables from within the module, what's wrong with global
?
# my_module.py
def define_module_scoped_variables():
global a, b, c
a, b, c = 'a', ['b'], 3
thus:
>>> import my_module
>>> my_module.define_module_scoped_variables()
>>> a
NameError: name 'a' is not defined
>>> my_module.a
'a'
>>> my_module.b
['b']
Related videos on Youtube
Matt Joiner
About Me I like parsimonious code, with simple interfaces and excellent documentation. I'm not interested in enterprise, boiler-plate, or cookie-cutter nonsense. I oppose cruft and obfuscation. My favourite languages are Go, Python and C. I wish I was better at Haskell. Google+ GitHub Bitbucket Google code My favourite posts http://stackoverflow.com/questions/3609469/what-are-the-thread-limitations-when-working-on-linux-compared-to-processes-for/3705919#3705919 http://stackoverflow.com/questions/4352425/what-should-i-learn-first-before-heading-to-c/4352469#4352469 http://stackoverflow.com/questions/6167809/how-much-bad-can-be-done-using-register-variables-in-c/6168852#6168852 http://stackoverflow.com/questions/4141307/c-and-c-source-code-profiling-tools/4141345#4141345 http://stackoverflow.com/questions/3463207/how-big-can-a-malloc-be-in-c/3486163#3486163 http://stackoverflow.com/questions/4095637/memory-use-of-stl-data-structures-windows-vs-linux/4183178#4183178
Updated on March 18, 2020Comments
-
Matt Joiner over 4 years
What do I pass as the first parameter "
object
" to the functionsetattr(object, name, value)
, to set variables on the current module?For example:
setattr(object, "SOME_CONSTANT", 42);
giving the same effect as:
SOME_CONSTANT = 42
within the module containing these lines (with the correct
object
).I'm generate several values at the module level dynamically, and as I can't define
__getattr__
at the module level, this is my fallback. -
unutbu about 14 yearsThe docs give a warning about modifying vars(). docs.python.org/library/functions.html#vars . When is it okay to do this?
-
msw about 14 yearsYep,
SOME_CONSTANT
computed at run-time isn't exactly constant. And ifglobals()
isn't available to you then you must be reaching into another module to modify its attributes; that's bound to get people wondering. -
Mike Graham about 14 years@~unutbu, I wouldn't really say that it's quite "okay", but it will work when you call
vars()
at module-level scope rather than inside of a function. -
unutbu about 14 yearsThanks for the information, @Mike. Is there an easy way to understand why
vars()
behaves this way (okay at module-level but not in functions)? Was it a restriction by design, or something else? -
Alex Martelli about 14 years
vars()
is equivalent toglobals()
at module scope (and so returns a true, modifiable dict) but tolocals()
at function scope (and so returns a never-to-be-modified pseudodict). I usevars()
at module scope as it saves 3 characters, one syllable, vs its synonym-in-that-scopeglobals()
;-) -
unutbu about 14 yearsOkay, that's helpful, @Alex; thanks. But why should
locals()
at function scope return a never-to-be-modified pseudodict? Would there have been something wrong with exposing a modifiable dict here? -
Alex Martelli about 14 yearsYes, it would have destroyed the single most important optimization the Python compiler does: a function's local variables are not kept in a dict, they're in a tight vector of values, and each local variable access uses the index in that vector, not a name lookup. To defeat the optimization, forcing the dict you desire to exist, start the function with
exec ''
: time a function with a couple substantial loops each way, and you'll see the importance of this core optimization to Python's performance. -
Matt Joiner about 14 yearsHm is there any reason I can't just do
globals()[name] = value
, keeping in mind that "This is always the dictionary of the current module", and thatvars()
is equivalent toglobals()
in your answer? Is it safe to do this? -
Matt Joiner about 14 yearsConstant and mutable are mutually exclusive. Constant and dynamically generated are not. The values I'm generating are always the same, and determined based on further "constants", to save on arithmetic and typing on my part.
-
msw about 14 yearsYeah, I've always (where "always" is defined as the "last few months I've been learning Python") found that
global but not really
declaration puzzling. I suppose it may be a historical relic that predates module namespaces. -
Alex Martelli about 14 years@Matt, sure, it's safe (
vars
andglobals
are equivalent at module top level, and if you're in a function it'sglobals
you want to use to set a module-level variable anyway). Though you can usesetattr
, as you chose to ask in this question, you can also get the same effect with the indexed assignment in question. And, by the way, you can also have a__getattr__
on what behaves just about like a module (can be imported etc), but, I guess that's yet another issue. -
Matt Joiner about 14 years@Alex Martelli: As there is no way for me to message you here, perhaps you might take a look at stackoverflow.com/questions/2447353/getattr-on-a-module, which is of great interest to me.
-
msw about 14 yearsBeautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Readability counts. Special cases aren't special enough to break the rules. There should be one-- and preferably only one --obvious way to do it. If the implementation is hard to explain, it's a bad idea.
-
Alex Martelli about 14 years@msw, I think you forgot "practicality beats purity";-).
-
Alex Martelli about 14 years@Matt, ah yes, @Håvard S's solution in that Q is what I had in mind (having originally published it myself in the Cookbook, I upvoted when I saw it given on SO;-) -- that it doesn't work after
import *
I see as one of the zillion problems withimport *
, not with the solution in question; that it doesn't work on barenames ("within the current module" as you say) is true, but then barenames are so entirely different from qualified names that it shouldn't be expected to. -
msw about 14 yearsFair nuff, so what's practical about
vars()[name] = value
other than "it saves 3 characters, one syllable" that makes it special enough to break the rules, be implicit, be unreadable, be hard to explain, and depends heavily on the knowledge of the particular implementation. Yeah, it's clever, so is the C constructi++-++j
and if it happens to work the way you want on your platform, does anything else really matter? Do note how much explanation this so-called practical example made to an intelligent, interested reader. -
Alex Martelli about 14 years@msw, oh, I thought you were commenting on my several few comments (about how
locals()
can't practically be a dict), not one from 12 hours ago - hard to keep track when you give no reference. There's nothing implicit or unreadable aboutvars
, it's not especially clever, it works uniformly across platforms, and the only thing that makes it confusing is that it's documented wrong in the online docs. Guess I'll edit the answer to point this out since this appears to really make you go off the deep end;-). -
msw about 14 years@matt: assuming that your question is an honest one - I'm new to Python and was attracted to PEP 20 "Zen of Python" principles that make well written Python code almost self-evidently trivial. I find that overuse of
__setattr__
is apparently very seductive yet has the net effect of making code mysterious. Overuse of meta-syntactic constructs tends to make code reading difficult for exactly the reasons the C preprocessor is presently shunned for past abuses. -
Matt Joiner about 14 years@msw: Okay now your comments make sense. I'm just happy that it works, and that Alex's description has removed confusion on my part. I can see however, that having both
vars()
andglobals()
, and even the fact thatglobals()
is a misleading name... not ideal, but who's counting? -
Curt over 8 yearsThe original question is asking how to set an attribute whose name is given by a string (the same thing I was presently searching for), so this would not help.