Re: [Python-ideas] Enhancing vars()
On Wed, Dec 14, 2016 at 12:12:39AM +, Emanuel Barry wrote: > > From Steven D'Aprano > > Sent: Tuesday, December 13, 2016 6:49 PM > > To: python-ideas@python.org > > Subject: Re: [Python-ideas] Enhancing vars() > > > > But if the object has __slots__, with or without a __dict__, then vars > > should return a proxy which direct reads and writes to the correct slot > > or dict. > > > > It might be helpful to have a slotsproxy object which provides a > > dict-like interface to an object with __slots__ but no __dict__, and > > build support for both __slots__ and a __dict__ on top of that. > > That might be a bit tricky, for example, it's possible that a class has a > `foo` slot *and* a `foo` instance attribute (by virtue of subclasses). What > would you do in that case? vars() shouldn't need to care about inheritance: it only cares about the object's own individual namespace, not attributes inherited from the class or superclasses. That's how vars() works now: py> class C: ... cheese = 1 ... py> obj = C() py> ns = vars(obj) py> 'cheese' in ns False The only difference here is that if the direct parent class has __slots__, the instance will use them instead of (or in addition to) a __dict__. We don't need to care about superclass __slots__, because they aren't inherited. > Or what if there's a slot that doesn't have any > value (i.e. raises AttributeError on access, but exists on the class > nonetheless), but an instance attribute with the same name exists? And so > on. Only the *list of slot names* exists on the class. The slots themselves are part of the instance. Nevertheless, you are right: a slot can be defined, but not assigned to. That has to be treated as if the slot didn't exist: py> class D: ... __slots__ = ['spam'] ... py> d = D() py> hasattr(d, 'spam') False So I would expect that 'spam' in vars(d) should likewise return False, until such time that d.spam is assigned too. The same applies even if the object has a __dict__. The slot always takes precedence, even if the slot isn't filled in. py> class E: ... __slots__ = ['spam', '__dict__'] ... py> e = E() py> e.__dict__['spam'] = 1 py> hasattr(e, 'spam') False > > If the objects has *neither* __slots__ nor __dict__, vars can probably > > raise a TypeError. > > Is that even possible in pure Python? The only object I know that can do > this is `object`, but some other C objects might do that too. I don't think pure Python classes can do this, at least not without some metaclass trickery, but certainly `object` itself lacks both __slots__ and instance __dict__, and C objects can do the same (so I'm told). -- Steve ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Enhancing vars()
> From Steven D'Aprano > Sent: Tuesday, December 13, 2016 6:49 PM > To: python-ideas@python.org > Subject: Re: [Python-ideas] Enhancing vars() > > But if the object has __slots__, with or without a __dict__, then vars > should return a proxy which direct reads and writes to the correct slot > or dict. > > It might be helpful to have a slotsproxy object which provides a > dict-like interface to an object with __slots__ but no __dict__, and > build support for both __slots__ and a __dict__ on top of that. That might be a bit tricky, for example, it's possible that a class has a `foo` slot *and* a `foo` instance attribute (by virtue of subclasses). What would you do in that case? Or what if there's a slot that doesn't have any value (i.e. raises AttributeError on access, but exists on the class nonetheless), but an instance attribute with the same name exists? And so on. > If the objects has *neither* __slots__ nor __dict__, vars can probably > raise a TypeError. Is that even possible in pure Python? The only object I know that can do this is `object`, but some other C objects might do that too. -Emanuel ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Enhancing vars()
On Tue, Dec 13, 2016 at 11:53:44AM +, Paul Moore wrote: [...] > There's obviously a speed-up from avoiding repeated getattr calls, but > is speed the key here? Not for me. > The advantage of an "enhanced vars" is more likely to be ease of > discoverability, and I'm not sure dict.fromattrs gives us that > benefit. Also, the dict constructor gives a *copy* of the namespace, > where the proposal was for the proxy returned by vars() to provide > update capability (if I understand the proposal correctly). Correct. -- Steve ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Enhancing vars()
On Mon, Dec 12, 2016 at 10:45:39PM -0500, Alexander Belopolsky wrote: > On Mon, Dec 12, 2016 at 6:45 PM, Steven D'Aprano > wrote: > > > Proposal: enhance vars() to return a proxy to the object namespace, > > regardless of whether said namespace is __dict__ itself, or a number of > > __slots__, or both. > > > > How do you propose dealing with classes defined in C? Their objects don't > have __slots__. I don't see any clean way to do so. Maybe we should have a convention that such objects provide a __slots__ attribute listing public attributes, but I'm not too concerned. Let vars(weird_c_object) raise TypeError, just as it does now. > One possibility is to use __dir__ or dir(), but those can return anything > and in the past developers > were encouraged to put only "useful" attributes in __dir__. Indeed. -- Steve ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Enhancing vars()
On Wed, Dec 14, 2016 at 12:58:16AM +0200, Serhiy Storchaka wrote: > On 13.12.16 01:45, Steven D'Aprano wrote: > >One of the lesser-known ones is vars(obj), which should be used in place > >of obj.__dict__. > > > >Unfortunately, vars() is less useful than it might be, since not all > >objects have a __dict__. Some objects have __slots__ instead, or even > >both. That is considered an implementation detail of the object. > > http://bugs.python.org/issue13290 > http://mail.python.org/pipermail/python-dev/2012-October/122011.html Thanks Serhiy! Glad to see I'm not the only one with this idea. I think: - the behaviour of locals() (and vars() when given no argument, where it returns locals()) is anomalous and should not be copied unless we really need to. - Other Python implementations don't always emulate the weird behaviour of locals(), for example I think IronPython locals() is writeable, and the local variables do change. steve@orac:~$ ipy IronPython 2.6 Beta 2 DEBUG (2.6.0.20) on .NET 2.0.50727.1433 Type "help", "copyright", "credits" or "license" for more information. >>> def test(): ... a = 1 ... locals()['a'] = 99 ... print a ... >>> test() 99 CPython will print 1 instead. So CPython locals() is an implementation detail and we shouldn't feel the need to copy it's weird behaviour. When given an object, vars(obj) should return a dict-like object which is a read/write proxy to the object's namespace. If the object has a __dict__ but no __slots__, then there's no need to change anything: it can keep the current behaviour and just return the dict itself: assert vars(obj) is obj.__dict__ But if the object has __slots__, with or without a __dict__, then vars should return a proxy which direct reads and writes to the correct slot or dict. It might be helpful to have a slotsproxy object which provides a dict-like interface to an object with __slots__ but no __dict__, and build support for both __slots__ and a __dict__ on top of that. If the objects has *neither* __slots__ nor __dict__, vars can probably raise a TypeError. -- Steve ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Enhancing vars()
On 13.12.16 01:45, Steven D'Aprano wrote: One of the lesser-known ones is vars(obj), which should be used in place of obj.__dict__. Unfortunately, vars() is less useful than it might be, since not all objects have a __dict__. Some objects have __slots__ instead, or even both. That is considered an implementation detail of the object. http://bugs.python.org/issue13290 http://mail.python.org/pipermail/python-dev/2012-October/122011.html ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Enhancing vars()
> It also refers to local and global variables, as vars() is effectively > an alias for locals() if you don't pass an argument, and locals() is > effectively an alias for globals() at module level: > > https://www.getpattern.com/meetpattern> to sign up! ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Enhancing vars()
Nick Coghlan writes: > (With the lack of an underscore being due to the precedent set by > dict.fromkeys()) > > Armed with those, the "give me all the attributes from __dir__" > command would be: > > attrs = dict.from_attrs(obj, dir(obj)) A Urk + You sure you want to follow precedent? My fingers really like that typo, too! ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Enhancing vars()
On 13 December 2016 at 11:28, Nick Coghlan wrote: > Armed with those, the "give me all the attributes from __dir__" > command would be: > > attrs = dict.from_attrs(obj, dir(obj)) Which of course can already be spelled as attrs = { attr: getattr(obj, attr) for attr in dir(obj) } There's obviously a speed-up from avoiding repeated getattr calls, but is speed the key here? The advantage of an "enhanced vars" is more likely to be ease of discoverability, and I'm not sure dict.fromattrs gives us that benefit. Also, the dict constructor gives a *copy* of the namespace, where the proposal was for the proxy returned by vars() to provide update capability (if I understand the proposal correctly). Paul ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Enhancing vars()
On 13 December 2016 at 20:02, Steven D'Aprano wrote: > On Tue, Dec 13, 2016 at 10:29:38AM +0100, Marco Buttu wrote: > >> +1. Would it be possible in the future (Py4?) to change the name `vars` >> to a more meaningful name? Maybe `namespace`, or something more appropriate. > > I'm not keen on the name vars() either, but it does make a certain > sense: short for "variables", where "variable" here refers to attributes > of an instance rather than local or global variables. It also refers to local and global variables, as vars() is effectively an alias for locals() if you don't pass an argument, and locals() is effectively an alias for globals() at module level: >>> locals() is globals() True >>> vars() is globals() True >>> def f(): return vars() is locals() ... >>> f() True To be honest, rather than an enhanced vars(), I'd prefer to see a couple more alternate dict constructors: dict.fromattrs(obj, attributes) dict.fromitems(obj, keys) (With the lack of an underscore being due to the precedent set by dict.fromkeys()) Armed with those, the "give me all the attributes from __dir__" command would be: attrs = dict.from_attrs(obj, dir(obj)) Cheers, Nick. -- Nick Coghlan | ncogh...@gmail.com | Brisbane, Australia ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Enhancing vars()
On Tue, Dec 13, 2016 at 10:29:38AM +0100, Marco Buttu wrote: > +1. Would it be possible in the future (Py4?) to change the name `vars` > to a more meaningful name? Maybe `namespace`, or something more appropriate. I'm not keen on the name vars() either, but it does make a certain sense: short for "variables", where "variable" here refers to attributes of an instance rather than local or global variables. I'm not sure that namespace is a better name: namespace, it seems to me, it likely to be used as the name of the target: namespace = vars(obj) But if there is a lot of popular demand for a name change, then I suppose it could happen. Ask again around Python 3.9 :-) -- Steve ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Enhancing vars()
On 13/12/2016 00:45, Steven D'Aprano wrote: In general, directly accessing dunders is a bit of a code smell. (I exclude writing dunder methods in your classes, of course.) There's usually a built-in or similar to do the job for you, e.g. instead of iterator.__next__() we should use next(iterator). One of the lesser-known ones is vars(obj), which should be used in place of obj.__dict__. [...] Proposal: enhance vars() to return a proxy to the object namespace, regardless of whether said namespace is __dict__ itself, or a number of __slots__, or both. +1. Would it be possible in the future (Py4?) to change the name `vars` to a more meaningful name? Maybe `namespace`, or something more appropriate. -- Marco Buttu INAF-Osservatorio Astronomico di Cagliari Via della Scienza n. 5, 09047 Selargius (CA) Phone: 070 711 80 217 Email: mbu...@oa-cagliari.inaf.it ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/