On Mon, Dec 21, 2020 at 04:36:21PM +0300, Paul Sokolovsky wrote:
I posted on python-dev a question regarding builtin vars() vs .__dict__ attribute dichotomy: https://firstname.lastname@example.org/thread/JAFIBBUU5...
It could as well be one among the earliest cases of the violation of "There should be one-- and preferably only one --obvious way to do it."
(1) `vars` predates the Zen of Python (vars goes back to at least Python 1.4 in 1996; the Zen dates back to 1999);
(2) and `vars` *is* the "one obvious way" to access an object's internal namespace (dunder names are reserved for the Python interpreter; the public API to access an object's symbol table is `vars(obj)`)
I don't think that it counts as a violation. But even if it does, well, the Zen is mostly intended to be light-hearted, almost a joke, and not as gospel; we take the koans overly seriously at our peril.
(Seriously, how much *more obvious* can we get than a builtin function? You don't have to import it, it is always available.)
On the other hand, *obvious* is not the same as *well known*. I expect that many people aren't aware of, or forget, the existence of `vars` and use `obj.__dict__` directly. That's so common that I expect we have no hope of making `__dict__` a *private* implementation detail, even though not all objects, or even all classes, have a `__dict__`.
Such earlier, that it could as well turn out that this principle was never thoroughly followed by Python at all.
Anyway, how the question pops up, is that there's very rare when there's a need to access *writable* object namespace as dictionary. One of such cases is executing code in a module context, where you need to pass module's globals to exec(), and so I wonder what's "the most canonical way" of getting that - var(mod) or mod.__dict__.
I expect the most common way is `globals()`.
But thinking about it, the problem lies on the exec()'s side. If exec could take a module object directly as its "globals" param, there wouldn't be a need to expose internal namespace implementation of the module object.
I expect that there is plenty of third-party code that expects to be able to access `module.__dict__` either directly or via `vars`, since that is something that has been documented as working for many releases.
So, I wonder what old-timers would think of the following signature:
exec(object[, globals_or_module[, locals]])
I don't hate it, I just don't see any advantage to adding such complexity to the signature just for the sake of avoiding a function call or dot lookup.