New submission from Michael Foord <mich...@voidspace.org.uk>: As discussed on python-dev, a version of getattr that does static lookups - bypassing the descriptor protocol, __getattr__, and __getattribute__. Initial implementation by Nick Coghlan, amended and tests added by me.
Phillip Eby objects to this code existing at all as it doesn't play well with proxy objects. The purpose of getattr_static is for "passive introspection" without triggering code execution (as hasattr and getattr both do). Use cases include debugging and fetching docstrings from objects. Caveats with the current implementation are: Cases that will break `getattr_static`, all pathological enough not to worry about (i.e. if you do any of these then you deserve to have everything break anyway): * `__dict__` existing (e.g. as a property) but not returning a dictionary * classes created with `__slots__` that then have the `__slots__` member deleted from the class (or otherwise monkeyed with) Cases handled incorrectly: 1. where a descriptor with a `__set__` method is shadowed by an instance member we return the instance member in preference to the descriptor, unlike `getattr` 2. types implemented in C may have neither `__dict__` nor `__slots__`, in this case we will be unable to find instance members and return the attribute descriptor instead 3. classes that inherit from a class with `__slots__` (whether or not they use `__slots__` themselves) will return the slot descriptor for instance members 'owned' by a slot on a base class 4. objects that lie about being a type by having __class__ as a descriptor (we traverse the mro of whatever type `obj.__class__` returns instead of the real type) 1 could be fixed but the code would be annoying. Is it worth fixing? 2 could be detected and where fetching an attribute from an instance fails but an attribute descriptor is found on the type we could try it's __get__ method. Worth it? 3 could be detected if we find a slot descriptor on a type trying its __get__ method. Worth it? 4 could be fixed by using type everywhere instead of __class__. We also can't use isinstance that uses __class__. If an object is lying about __class__ then it obviously *intends* us to look at the 'faked' version. However, this breaks the 'no code execution' purpose of getattr_static and is inconsistent with the rest of our behaviour. Worth fixing? Fixing *all* of these (or any) will significantly complicate the implimentation. Fetching an uninitialized instance member from an instance of a class with __slots__ returns the slot descriptor rather than raising an AttributeError as the descriptor does. As the slot descriptor is a Python implementation detail perhaps we are better off propagating the exception here. (?) On the other hand, the descriptor is available on the class and the job of this function is to fetch members when they are available... I'm not aware of any other caveats / potential pitfalls. Please point them out to me. :-)Cases that will break `getattr_static`, all pathological enough not to worry about (i.e. if you do any of these then you deserve to have everything break anyway): * `__dict__` existing (e.g. as a property) but not returning a dictionary * classes created with `__slots__` that then have the `__slots__` member deleted from the class (or otherwise monkeyed with) Cases handled incorrectly: 1. where a descriptor with a `__set__` method is shadowed by an instance member we return the instance member in preference to the descriptor, unlike `getattr` 2. types implemented in C may have neither `__dict__` nor `__slots__`, in this case we will be unable to find instance members and return the attribute descriptor instead 3. classes that inherit from a class with `__slots__` (whether or not they use `__slots__` themselves) will return the slot descriptor for instance members 'owned' by a slot on a base class 4. objects that lie about being a type by having __class__ as a descriptor (we traverse the mro of whatever type `obj.__class__` returns instead of the real type) 1 could be fixed but the code would be annoying. Is it worth fixing? 2 could be detected and where fetching an attribute from an instance fails but an attribute descriptor is found on the type we could try it's __get__ method. Worth it? 3 could be detected if we find a slot descriptor on a type trying its __get__ method. Worth it? 4 could be fixed by using type everywhere instead of __class__. We also can't use isinstance that uses __class__. If an object is lying about __class__ then it obviously *intends* us to look at the 'faked' version. However, this breaks the 'no code execution' purpose of getattr_static and is inconsistent with the rest of our behaviour. Worth fixing? Fixing *all* of these (or any) will significantly complicate the implimentation. Fetching an uninitialized instance member from an instance of a class with __slots__ returns the slot descriptor rather than raising an AttributeError as the descriptor does. As the slot descriptor is a Python implementation detail perhaps we are better off propagating the exception here. (?) On the other hand, the descriptor is available on the class and the job of this function is to fetch members when they are available... I'm not aware of any other caveats / potential pitfalls. Please point them out to me. :-) ---------- assignee: michael.foord components: Library (Lib) files: static.py keywords: needs review messages: 115296 nosy: benjamin.peterson, michael.foord, ncoghlan priority: normal severity: normal status: open title: Addition of getattr_static for inspect module versions: Python 3.2 Added file: http://bugs.python.org/file18699/static.py _______________________________________ Python tracker <rep...@bugs.python.org> <http://bugs.python.org/issue9732> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com