Comment on PEP 562 (Module __getattr__ and __dir__)
Hi, Just one comment. Could the new behaviour of attribute lookup on a module be spelled out more explicitly please? I'm guessing it is now something like: `module.__getattribute__` is now equivalent to: def __getattribute__(mod, name): try: return object.__getattribute__(mod, name) except AttributeError: try: getter = mod.__dict__["__getattr__"] except KeyError: raise AttributeError(f"module has no attribute '{name}'") return getter(name) Cheers, Mark.
19.11.17 22:24, Mark Shannon пише:
Just one comment. Could the new behaviour of attribute lookup on a module be spelled out more explicitly please?
I'm guessing it is now something like:
`module.__getattribute__` is now equivalent to:
def __getattribute__(mod, name): try: return object.__getattribute__(mod, name) except AttributeError: try: getter = mod.__dict__["__getattr__"] except KeyError: raise AttributeError(f"module has no attribute '{name}'") return getter(name)
I think it is better to describe in the terms of __getattr__. def ModuleType.__getattr__(mod, name): try: getter = mod.__dict__["__getattr__"] except KeyError: raise AttributeError(f"module has no attribute '{name}'") return getter(name) The implementation of ModuleType.__getattribute__ will be not changed (it is inherited from the object type).
On 19/11/17 20:41, Serhiy Storchaka wrote:
19.11.17 22:24, Mark Shannon пише:
Just one comment. Could the new behaviour of attribute lookup on a module be spelled out more explicitly please?
I'm guessing it is now something like:
`module.__getattribute__` is now equivalent to:
def __getattribute__(mod, name): try: return object.__getattribute__(mod, name) except AttributeError: try: getter = mod.__dict__["__getattr__"] except KeyError: raise AttributeError(f"module has no attribute '{name}'") return getter(name)
I think it is better to describe in the terms of __getattr__.
def ModuleType.__getattr__(mod, name): try: getter = mod.__dict__["__getattr__"] except KeyError: raise AttributeError(f"module has no attribute '{name}'") return getter(name)
The implementation of ModuleType.__getattribute__ will be not changed (it is inherited from the object type).
Not quite, ModuleType overrides object.__getattribute__ in order to provide a better error message. So with your suggestion, the change would be to *not* override object.__getattribute__ and provide the above ModuleType.__getattr__ Cheers, Mark.
Serhiy's definition sounds recursive (defining __getattr__ to define the behavior of __getattr__) but Mark's suggestion makes his intention unclear since the error message is still the same. Also the word "now" is confusing (does it mean "currently, before the PEP" or "once this PEP is accepted"?) It would be clearer to first state that Module.__getattribute__ is currently (before the PEP) essentially defined as class Module(object): def __getattribute__(self, name): try: return object.__getattribute__(self, name) except AttributeError: if hasattr(self, '__dict__'): mod_name = self.__dict__.get(name) if isinstance(mod_name, str): raise AttributeError("module '%s' has no attribute '%s'" % (mod_name, name)) raise AttributeError("module has no attribute '%s'" % name) The PEP changes the contents of the except clause to: if hasattr(self, '__dict__'): if '__getattr__' in self.__dict__: getter = self.__dict__['__getattr__'] if not callable(getter): raise TypeError("module __getattr__ must be callable") return getter(name) # Unchanged from here on mod_name = self.__dict__.get(name) if isinstance(mod_name, str): raise AttributeError("module '%s' has no attribute '%s'" % (mod_name, name)) raise AttributeError("module has no attribute '%s'" % name) (However exception chaining makes the equivalency still not perfect. And we ignore threading. But how far do we need to go when specifying "equivalent code" to what every implementation should implement natively?) On Sun, Nov 19, 2017 at 12:48 PM, Mark Shannon wrote:
On 19/11/17 20:41, Serhiy Storchaka wrote:
19.11.17 22:24, Mark Shannon пише:
Just one comment. Could the new behaviour of attribute lookup on a module be spelled out more explicitly please?
I'm guessing it is now something like:
`module.__getattribute__` is now equivalent to:
def __getattribute__(mod, name): try: return object.__getattribute__(mod, name) except AttributeError: try: getter = mod.__dict__["__getattr__"] except KeyError: raise AttributeError(f"module has no attribute '{name}'") return getter(name)
I think it is better to describe in the terms of __getattr__.
def ModuleType.__getattr__(mod, name): try: getter = mod.__dict__["__getattr__"] except KeyError: raise AttributeError(f"module has no attribute '{name}'") return getter(name)
The implementation of ModuleType.__getattribute__ will be not changed (it is inherited from the object type).
Not quite, ModuleType overrides object.__getattribute__ in order to provide a better error message. So with your suggestion, the change would be to *not* override object.__getattribute__ and provide the above ModuleType.__getattr__
Cheers, Mark.
_______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/guido% 40python.org
-- --Guido van Rossum (python.org/~guido)
20.11.17 03:02, Guido van Rossum пише:
Serhiy's definition sounds recursive (defining __getattr__ to define the behavior of __getattr__) but Mark's suggestion makes his intention unclear since the error message is still the same.
It is recursive only when the '__dict__' attribute is not defined. I assumed that it is defined for simplicity. And if isn't defined hasattr(self, '__dict__') will cause a recursion too. In any case the real C code handles this more carefully and effectively.
Yeah, I don't think there's an action item here except *maybe* changes to
the wording of the PEP. Ivan?
On Mon, Nov 20, 2017 at 12:33 AM, Serhiy Storchaka
20.11.17 03:02, Guido van Rossum пише:
Serhiy's definition sounds recursive (defining __getattr__ to define the behavior of __getattr__) but Mark's suggestion makes his intention unclear since the error message is still the same.
It is recursive only when the '__dict__' attribute is not defined. I assumed that it is defined for simplicity. And if isn't defined hasattr(self, '__dict__') will cause a recursion too.
In any case the real C code handles this more carefully and effectively.
_______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/guido% 40python.org
-- --Guido van Rossum (python.org/~guido)
On Sun, Nov 19, 2017 at 08:24:00PM +0000, Mark Shannon wrote:
Hi,
Just one comment. Could the new behaviour of attribute lookup on a module be spelled out more explicitly please?
I'm guessing it is now something like:
`module.__getattribute__` is now equivalent to:
def __getattribute__(mod, name): try: return object.__getattribute__(mod, name) except AttributeError: try: getter = mod.__dict__["__getattr__"]
A minor point: this should(?) be written in terms of the public interface for accessing namespaces, namely: getter = vars(mod)["__getattr__"] -- Steve
On Sun, Nov 19, 2017 at 4:57 PM, Steven D'Aprano
On Sun, Nov 19, 2017 at 08:24:00PM +0000, Mark Shannon wrote:
Just one comment. Could the new behaviour of attribute lookup on a module be spelled out more explicitly please?
I'm guessing it is now something like:
`module.__getattribute__` is now equivalent to:
def __getattribute__(mod, name): try: return object.__getattribute__(mod, name) except AttributeError: try: getter = mod.__dict__["__getattr__"]
A minor point: this should(?) be written in terms of the public interface for accessing namespaces, namely:
getter = vars(mod)["__getattr__"]
Should it? The PEP is not proposing anything for other namespaces. What difference do you envision this way of specifying it would make? -- --Guido van Rossum (python.org/~guido)
On Sun, Nov 19, 2017 at 05:34:35PM -0800, Guido van Rossum wrote:
On Sun, Nov 19, 2017 at 4:57 PM, Steven D'Aprano
wrote:
A minor point: this should(?) be written in terms of the public interface for accessing namespaces, namely:
getter = vars(mod)["__getattr__"]
Should it? The PEP is not proposing anything for other namespaces. What difference do you envision this way of specifying it would make?
I don't know if it should -- that's why I included the question mark. But my idea is that __dict__ is the implementation and vars() is the interface to __dir__, and we should prefer using the interface rather than the implementation unless there's a good reason not to. (I'm not talking here about changing the actual name lookup code to go through vars(). I'm just talking about how we write the equivalent recipe.) Its not a big deal either way, __dict__ is already heavily used and vars() poorly known. Call it a matter of taste, if you like, but in my opinion the fewer times we directly reference dunders, the better. -- Steve
Given that we're also allowing customization of __dir__ I wouldn't want to
link this to __dir__. But maybe you meant to say that vars() is the public
interface for __dict__. Even if it were, in the case of specifying this
particular customization for this PEP, I strongly prefer to write it in
terms of __dict__.
On Sun, Nov 19, 2017 at 6:34 PM, Steven D'Aprano
On Sun, Nov 19, 2017 at 05:34:35PM -0800, Guido van Rossum wrote:
On Sun, Nov 19, 2017 at 4:57 PM, Steven D'Aprano
wrote: A minor point: this should(?) be written in terms of the public interface for accessing namespaces, namely:
getter = vars(mod)["__getattr__"]
Should it? The PEP is not proposing anything for other namespaces. What difference do you envision this way of specifying it would make?
I don't know if it should -- that's why I included the question mark.
But my idea is that __dict__ is the implementation and vars() is the interface to __dir__, and we should prefer using the interface rather than the implementation unless there's a good reason not to.
(I'm not talking here about changing the actual name lookup code to go through vars(). I'm just talking about how we write the equivalent recipe.)
Its not a big deal either way, __dict__ is already heavily used and vars() poorly known. Call it a matter of taste, if you like, but in my opinion the fewer times we directly reference dunders, the better.
-- Steve _______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/ guido%40python.org
-- --Guido van Rossum (python.org/~guido)
participants (5)
-
Guido van Rossum
-
Ivan Levkivskyi
-
Mark Shannon
-
Serhiy Storchaka
-
Steven D'Aprano