Open 379dc349-3a10-424f-b9d2-a0104f092359 opened 7 years ago
Python 3.5.2 (default, Nov 7 2016, 11:31:36)
[GCC 6.2.1 20160830] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class C:
... def f(self): pass
...
>>> C.f.attr = 42
>>> print(dir(C.f))
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'attr']
>>> print(dir(C().f))
['__call__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__func__', '__ge__', '__get__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'attr']
>>>
Note that dir(C().f)
does include the custom attr
attribute, but is missing some of the dunder attributes (e.g. __annotations__
), which are actually accessible directly from the boun method.
I tested your last claim and it is true as far as I went.
>>> C.f.__annotations__
{'a': <class 'int'>}
>>> C().f.__annotations__
{'a': <class 'int'>}
>>> C.f.__code__
<code object f at 0x000002610BDB5150, file "<pyshell#7>", line 2>
>>> C().f.__code__
<code object f at 0x000002610BDB5150, file "<pyshell#7>", line 2>
This is not a bug. According to the documentation the list dir
returns "is not necessarily complete and may be inaccurate when the object has a custom __getattr__()
".
In this case, C.f
is of function type while C().f
is of method type, and you're able to access attributes of a function from a method because the method type has a custom __getattr__
defined to delegate missing attribute lookups to its underlying function:
https://github.com/python/cpython/blob/030b452e34bbb0096acacb70a31915b9590c8186/Objects/classobject.c#L206
It is therefore technically impractical if not impossible for dir
to deduce from the custom logics of MethodType.__getattr__
that it's really defaulting attribute lookups to a function.
Perhaps it makes sense for MethodType
to have been designed as a subclass of FunctionType
to begin with instead of relying on the hackier attribute delagation logics but it's too late to make that change now for compatibility reasons.
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields: ```python assignee = None closed_at = None created_at =
labels = ['interpreter-core', 'type-bug', '3.7']
title = 'dir() should include dunder attributes of the unbound method'
updated_at =
user = 'https://github.com/anntzer'
```
bugs.python.org fields:
```python
activity =
actor = 'terry.reedy'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = ['Interpreter Core']
creation =
creator = 'Antony.Lee'
dependencies = []
files = []
hgrepos = []
issue_num = 29117
keywords = []
message_count = 2.0
messages = ['284347', '284859']
nosy_count = 3.0
nosy_names = ['terry.reedy', 'Antony.Lee', 'xiang.zhang']
pr_nums = []
priority = 'normal'
resolution = None
stage = 'test needed'
status = 'open'
superseder = None
type = 'behavior'
url = 'https://bugs.python.org/issue29117'
versions = ['Python 3.6', 'Python 3.7']
```