Это может быть сделано с помощью описателя объекта + класса обертка объявления явно объявляя классы, которые нужно обернуть на этом пути на целевом классе.
Объект дескриптора - это любой объект, определяющий метод __get__
, который позволяет настраивать извлечение атрибута, когда дескриптор является частью класса. В этом случае мы хотим, чтобы этот атрибут, который является классом «Y», извлекается из экземпляра, всякий раз, когда метод извлекается из этого класса, экземпляр вставляется в список параметров.
Для этого требуется, чтобы полученный атрибут был сам по себе «прокси-классом» с доступом к пользовательским атрибутам, чтобы позволить динамической упаковке принимать к сведению.
Переводя все это в Python, мы имеем:
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)
#Example usage:
x = X()
x.Y.method(1,2,3)
(печатает <class '__main__.Y'> <__main__.X object at 0x18ad090> (1, 2, 3)
при запуске)
Но я полагаю, вы не хотите, чтобы нужно написать
Y = APIWrapper(Y)
для каждый из классов, которые вы хотите обернуть таким образом. (И имеют эти классы, определенные после обернутого класса, так что Y уже был проанализирован при анализе тела X).
Это можно сделать с помощью метаклассов, декораторов классов, которые должны быть определены для каждого класса, который вы хотите применить методы, вместо этого я создал функцию, которая должна быть вызвана в конце определения модуля , где вы определяете свой класс «X» - эта функция добавит нужные классы в качестве атрибутов для каждого определенного класса (в моем примере, я хочу, чтобы класс был помечен атрибутом «auto_api», но вам нужно подобрать себя) - Таким образом, функция «auto_api», определение классов х и Y становится, как это (с использованием той же APIProperty и APIWrapper, как указано выше)
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())
#Example
x = X()
x.Y.method(1,2,3)
В 'х(). Y.foo', будет' Foo' всегда класс-метод 'Y', который должен иметь свой первый аргумент nt заполнено? Или вы хотите иметь доступ к произвольным атрибутам 'Y' из экземпляров' X'? –
@benw будут методы на Y, которые не должны иметь x_inst как есть первый параметр, хотя в настоящее время это все методы экземпляра, а не методы класса. –