Reputation: 2292
How can I apply a "subclassing pattern", but have the class "show up" (as in module/name) as coming with the name I gave it, from the module I made it and not from the module I made the maker.
No doubt, and example is warranted here. Say I have a modules:
# module_with_wrapper.py
from functools import wraps
def my_wrap(cls, name=None):
assert isinstance(cls, type)
class WrappedClass(cls):
@wraps(cls.__init__)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.something_else = 42
WrappedClass.__name__ = name or f"{cls.__name__}Wrapped"
return WrappedClass
used in the following module:
# a_module.py
from functools import wraps
class A:
def __init__(self, a):
self.a = a
class B(A):
@wraps(A.__init__)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.something_else = 42
from module_with_wrapper import my_wrap
BB = my_wrap(A, 'BB') # define class BB, expected to be equivalent to B
The intent is to be able to reuse the subclassing pattern exampled by B
, anywhere I want, with any class I want.
And it works, but the module/name is not what I expect.
I expect my BB
to show up as a_module.BB
, not from module_with_wrapper.my_wrap.<locals>.WrappedClass
!
>>> from a_module import B, BB
>>>
>>> B
<class 'a_module.B'>
>>> b = B(a=0)
>>> b
<a_module.B object at 0x10e40eb50>
>>>
>>> BB # what the?! I thought I told it it's name was BB!!
<class 'module_with_wrapper.my_wrap.<locals>.WrappedClass'>
>>> bb = BB(a=0)
>>> bb
<module_with_wrapper.my_wrap.<locals>.WrappedClass object at 0x10e40ebd0>
>>> BB.__name__ # okay, at least it got THAT right!
'BB'
Upvotes: 0
Views: 408
Reputation: 1711
While repr
used the __name__
attribute in python 2, in python 3 (>=3.3) it uses the new __qualname__
attribute to provide more context. If you override __qualname__
in your decorator, you should get the desired result.
See this question for further information on the __qualname__
attribute.
Upvotes: 1