On Tue, Dec 29, 2020 at 09:02:10AM -0800, Guido van Rossum wrote:
On Tue, Dec 29, 2020 at 8:11 AM Steven D'Aprano <steve@pearwood.info> wrote:
To the contrary, vars() is something I added to the language for the benefit of REPL users (like dir()), and other usages look suspect to me. I find that using `__dict__` is more direct about the purpose, and also it is the prevailing style.
I cannot argue with your historical perspective on this, and I agree that `vars()` is not as well known as I believe it should be. So you are right on the bare facts. I still think you are wrong on the aesthetics :-) Your comment also shines some light on why `vars()` with no argument returns `locals()`, which otherwise seems strange to me. Nevertheless, I have to ask what could possibly be "suspect" about using vars() programmatically? It isn't like dir(). dir() is certainly a convenience function for interactive use, and is documented as returning "the most relevant, rather than complete, information". This note is repeated again later in the docs: "Because dir() is supplied primarily as a convenience for use at an interactive prompt, it tries to supply an interesting set of names more than it tries to supply a rigorously or consistently defined set of names, and its detailed behavior may change across releases." On the other hand, `vars()` has no such warnings. There's no wiggle- room: it either returns the instance `__dict__` or it raises TypeError. So aside from the difference in exceptions (AttributeError versus TypeError) I don't think that there is any possible difference between direct attribute access and the output of vars(). Am I wrong? Speaking of slots, I've often been annoyed that there is no abstraction that hides the difference between instances that use a dict as symbol table, and those that use slots. (And those that use both.) If you need an object's symbol table, for introspection or otherwise, you're out of luck if it uses slots. There doesn't seem to be any way to handle these two implementations in the same way, and objects with both slots and a dict can give surprising results if naive code expects `__dict__` to be the symbol table:
class A: ... __slots__ = ('spam', '__dict__') ... obj = A() obj.spam = True 'spam' in obj.__dict__ False obj.__dict__.update(spam=False) obj.spam True
So there's no way to get an object's symbol table in an implementation- independent way. Whether you use `obj.__dict__` or `vars(obj)` it only gives you the symbol table for objects that use a dict. There's nothing that works for objects that use slots. So far I've worked around this in an ad-hoc fashion by testing for `__slots__` and treating that case as special, but it would be nice to ignore the implementation details and just have a "symbol table" object to work with. What do you think?
Do you prefer to write `mylist.__len__()` over `len(mylist)`? Then you will probably prefer `obj.__dict__` over `vars(obj)` too :-)
Not a valid analogy.
I think it is. Apart from a matter of taste, what part of the analogy do you feel is invalid? -- Steve