This can be done using the Descriptor object + declaration of the container class explicitly declaring the classes that you need to wrap in this way in your target class.
A descriptor object is any object that defines the __get__ method, which allows you to configure attribute retrieval when the descriptor is part of a class. In this case, we want this attribute, which is the class "Y", to be retrieved from the instance, whenever the method is retrieved from this class, the instance is inserted into the parameter list.
This requires that the resulting attribute itself be a "proxy class" with access to user attributes to allow dynamic packaging to take note.
Having translated all this into Python, we have:
import types from functools import partial class APIWrapper(object): def __init__(self, apicls, instance): self._apicls = apicls self._instance = instance def __getattribute__(self, attr): apicls = object.__getattribute__(self, "_apicls") instance = object.__getattribute__(self,"_instance") obj = getattr(apicls, attr) if isinstance(obj, types.MethodType): return partial(obj,instance) return obj class APIProperty(object): def __init__(self, cls): self.cls = cls def __get__(self, instance, cls): return APIWrapper(self.cls, instance) class Y(object): @classmethod def method(cls, x, *args): print cls, x, args class X(object): Y = APIProperty(Y)
(prints <class '__main__.Y'> <__main__.X object at 0x18ad090> (1, 2, 3) at startup)
But I suppose you do not want to write
Y = APIWrapper(Y)
for each of the classes you want to wrap in this way. (And they have these classes defined after the wrapped class, so Y has already been analyzed when analyzing the body of X).
This can be done using metaclasses, class decorators that must be defined for each class that you want to apply to the methods - instead, I created a function that should be called at the end of the module definition, where you define your class “X” - this function will add the required classes as attributes for each specific class (in my example, I want the class to be marked with the attribute "auto_api", but it will come in handy) Thus, the function "auto_api", the definition of the classes X and Y becomes the same ( using the same APIProperty and APIWrapper as above)
def auto_api(api_classes, glob_dict): for key, value in glob_dict.items(): if isinstance(value, type) and hasattr(value, "auto_api"): for api_class in api_classes: setattr(value, api_class.__name__, APIProperty(api_class)) class X(object): auto_api = True class Y(object): @classmethod def method(cls, x, *args): print cls, x, args auto_api((Y,), globals())