On Mon, Oct 7, 2019 at 6:00 PM Peter Otten <__pete...@web.de> wrote: > > Chris Angelico wrote: > > > I'm not sure what's going on here, and it's probably not actually > > enum-specific, but that's where I saw it. > > > > If you create a plain class and have an attribute with an annotation, > > you can see that: > > > >>>> class Foo: > > ... spam: "ham" = 1 > > ... > >>>> Foo.__a > > Foo.__abstractmethods__ Foo.__annotations__ > >>>> Foo.__annotations__ > > {'spam': 'ham'} > > > > Note that __annotations__ shows up when tab-completing "__a". > > > > Now consider an enumeration: > > > >>>> from enum import Flag, auto > >>>> class Bar(Flag): > > ... quux: "asdf" = auto() > > ... > >>>> Bar.__ > > Bar.__abstractmethods__ Bar.__getattr__( Bar.__ne__( > > Bar.__base__( Bar.__getattribute__( Bar.__new__( > > Bar.__bases__ Bar.__getitem__( Bar.__prepare__( > > Bar.__basicsize__ Bar.__gt__( Bar.__qualname__ > > Bar.__bool__( Bar.__hash__( Bar.__reduce__( > > Bar.__call__( Bar.__init__( Bar.__reduce_ex__( > > Bar.__class__( Bar.__init_subclass__( Bar.__repr__( > > Bar.__contains__( Bar.__instancecheck__( Bar.__reversed__( > > Bar.__delattr__( Bar.__itemsize__ Bar.__setattr__( > > Bar.__dict__ Bar.__iter__( Bar.__sizeof__( > > Bar.__dictoffset__ Bar.__le__( Bar.__str__( > > Bar.__dir__( Bar.__len__( Bar.__subclasscheck__( > > Bar.__doc__ Bar.__lt__( Bar.__subclasses__( > > Bar.__eq__( Bar.__members__ Bar.__subclasshook__( > > Bar.__flags__ Bar.__module__ Bar.__text_signature__ > > Bar.__format__( Bar.__mro__ Bar.__weakrefoffset__ > > Bar.__ge__( Bar.__name__ > >>>> Bar.__annotations__ > > {'quux': 'asdf'} > > > > Double-tabbing "__" shows everything but, and double-tabbing "__ann" > > has nothing... but the attribute is most definitely there. > > > > Perhaps notable is dir(): > > > >>>> dir(Foo) > > ['__annotations__', '__class__', '__delattr__', '__dict__', '__dir__', > > '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', > > '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', > > '__lt__', '__module__', '__ne__', '__new__', '__reduce__', > > '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', > > '__subclasshook__', '__weakref__', 'spam'] > >>>> dir(Bar) > > ['__class__', '__doc__', '__members__', '__module__', 'quux'] > > > > But that's not the whole story, since tab completing "Bar.__" will > > still show "__class__" and "__init__" that aren't in dir(). > > > > Tested with the default REPL CPython 3.6, 3.7, 3.8, and 3.9. Tested > > also in IDLE on 3.9 but tab completion of dunders behaves differently > > there (it ONLY seems to want to tab complete __class__, for some > > reason) so it's not comparable. > > > > What's actually going on here? > > With Python 3.7: > > >>> from enum import Flag > >>> import inspect > >>> print(inspect.getsource(Flag.__dir__)) > def __dir__(self): > added_behavior = [ > m > for cls in self.__class__.mro() > for m in cls.__dict__ > if m[0] != '_' and m not in self._member_map_ > ] > return (['__class__', '__doc__', '__module__'] + added_behavior) > > Looks like everything starting with an underscore (except class, doc, and > module) is suppressed, probably to suppress some noise... >
That's why dir() shows what it does, but tab completion seems to have some other source, as it's able to find a lot of other attributes but not __annotations__. Very strange. ChrisA -- https://mail.python.org/mailman/listinfo/python-list