On Wed, Dec 30, 2020 at 5:01 PM Steven D'Aprano <st...@pearwood.info> wrote:
> 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 <st...@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. > This is the first hint that vars() is not what it seems. Nevertheless, I have to ask what could possibly be "suspect" about using > vars() programmatically? It isn't like dir(). > But it is dir()'s cousin, and the fact that its meaning hasn't changed doesn't mean they couldn't: Christopher Barker is already asking for such a change. This is the second hint. > 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? > That's just because vars() didn't turn out to be so useful, or perhaps because people didn't think of improving it when dir() was improved. I suspect that if you look at the original docs, dir() and vars() had pretty similar documentation. (And according to PEP 361, `__dir__` was originally added in 3.0 -- though it seems to have been backported to 2.x at some point.) > 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? > That you're providing an excellent argument to evolve vars() independently from `__dict__`. :-) > > > 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? > len() is an important abstraction for containers, and its usage deserves a short name (just like unary minus and abs() for numbers). This is crucial even though you have to use its "true name" (https://xkcd.com/2381/) to define the implementation for a particular class. OTOH, `__dict__` is the opposite of an abstraction -- whether you spell it vars(x) or `x.__dict__`, the matter remains that you're looking inside the implementation of the object, and what you get is not an abstraction -- as you've pointed out for `__slots__`, and as is also apparent for e.g. namedtuple or fundamental objects like numbers, strings and built-in container types. By making the dominant spelling `__dict__`, we remind people that when they use this, they're tinkering with the implementation. Don't get me wrong, this can be fun and useful, but it's not a clean abstraction. The more fundamental abstraction is getattr()/setattr(), since it is supported by *all* objects, not just most classes. -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/T2RL47EI3NNJ3AOYGHVCWQA4HLDQZ2E5/ Code of Conduct: http://python.org/psf/codeofconduct/