(Apologies if this has already been discussed. I tried to search and didn't find
anything relevant.)
I was playing around with 3.12.0b4 this evening and noticed an odd (to me, at least) behavior with types.get_original_bases(). I hesitate to call it a bug because I think I understand *why* it's behaving this way—I'm just not sure it's
desirable.
T = typing.TypeVar("T")
class FirstBase(typing.Generic[T]):
... pass
...
class SecondBase(typing.Generic[T]):
... pass
...
class First(FirstBase[int]):
... pass
...
class Second(SecondBase[int]):
... pass
...
class Example(First, Second):
... pass
...
types.get_original_bases(Example)
(FirstBase[int],)
Example.__bases__
(First, Second)
types.get_original_bases(First)
(FirstBase[int],)
In other words, types.get_original_bases(Example) is returning the original base
types for First, rather than its own.
I believe this happens because __orig_bases__ is only set when one or more bases
are not types. In this case both bases are types, so Example doesn't get its own
__orig_bases__. Then when types.get_original_bases() tries to get __orig_bases__
with getattr(cls, "__orig_bases__") or something morally equivalent, it searches
the MRO and finds __orig_bases__ on First.
The same thing also happens if all the bases are "bare" generic types.
class First(typing.Generic[T]):
... pass
...
class Second(typing.Generic[T]):
... pass
...
class Example(First, Second):
... pass
...
types.get_original_bases(Example)
(typing.Generic[~T],)
As I said, I'm not clear if this is a bug, or just an unfortunate but intended behavior. I would personally expect types.get_original_bases() to check if the type has its *own* __orig_bases__ attribute, and to fall back to __bases__ otherwise. The way it works today makes it unnecessarily difficult to write a function that, for example, recurses down a type's inheritance tree inspecting the original bases—I currently have to work around this behavior via hacks like
checking "__orig_bases__" in cls.__dict__ or any(types.get_original_bases(cls) == types.get_original_bases(base) for base in cls.__bases__). (Unless I'm missing some simpler solution.)
Is this something that could (should?) be addressed before 3.12 lands?
Thanks,
Chris Bouchard
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)