Instancemethod로 호출 할 수 있습니까?
문제
메타 클라스가 있다고 가정 해 봅시다 CallableWrappingMeta
새로운 클래스의 본문을 걸어 수업으로 방법을 감싸고, InstanceMethodWrapper
:
import types
class CallableWrappingMeta(type):
def __new__(mcls, name, bases, cls_dict):
for k, v in cls_dict.iteritems():
if isinstance(v, types.FunctionType):
cls_dict[k] = InstanceMethodWrapper(v)
return type.__new__(mcls, name, bases, cls_dict)
class InstanceMethodWrapper(object):
def __init__(self, method):
self.method = method
def __call__(self, *args, **kw):
print "InstanceMethodWrapper.__call__( %s, *%r, **%r )" % (self, args, kw)
return self.method(*args, **kw)
class Bar(object):
__metaclass__ = CallableWrappingMeta
def __init__(self):
print 'bar!'
우리의 더미 래퍼는 그들이 들어올 때 인수를 인쇄합니다. 그러나 당신은 눈에 띄는 것을 알게 될 것입니다. InstanceMethodWrapper
호출 가능합니다. 클래스 제작 중에 인스턴스 방법으로 변환 될 목적으로 기능으로 취급되지 않습니다 (메타 클래스가 완료된 후).
잠재적 인 해결책은 클래스 대신 데코레이터를 사용하여 메소드를 래핑하는 것입니다. 해당 기능은 인스턴스 방법이됩니다. 그러나 현실 세계에서 InstanceMethodWrapper
훨씬 더 복잡합니다. API를 제공하고 방법 용도 이벤트를 게시합니다. 클래스는 더 편리합니다 (그리고 더 중요한 것은 아닙니다).
나는 또한 데드 엔드를 시도했다. 서브 클래싱 types.MethodType
그리고 types.UnboundMethodType
아무데도 가지 않았다. 약간의 성찰, 그리고 그들은 type
. 그래서 나는 둘 다 메타 클래스로 사용하려고 시도했지만 운이 좋지 않았습니다. 그들이 메타 클래스로서 특별한 요구를 가지고있는 경우 일 수도 있지만,이 시점에서 우리는 문서화되지 않은 영토에있는 것 같습니다.
어떤 아이디어?
해결책
당신을 풍요롭게하십시오 InstanceMethodWrapper
a __get__
(완벽하게 잘 할 수 있습니다 return self
) - 즉, 그 수업을 설명자 인스턴스가 설명자 객체가되도록 유형. 보다 http://users.rcn.com/python/download/descriptor.htm 배경과 세부 사항.
BTW, Python 2.6 이상에 있다면, 메타 클래스 대신 클래스 디코레이터를 사용하는 것을 고려하십시오. 우리는 많은 메타 클라스가 그러한 장식 목적으로 만 사용 되었기 때문에 클래스 데코레이터를 정확하게 추가했으며, 데코레이터는 사용하기가 훨씬 간단합니다. .
다른 팁
편집하다: 나는 다시 거짓말을한다. 그만큼 __?attr__
함수의 속성은 가독적이지만 항상 AttributeException
할당 할 때 예외? 나는 몰라. 원점으로 돌아가다!
편집하다: 래핑 함수가 속성 요청을 프록시하지 않기 때문에 실제로 문제를 해결하지 못합니다. InstanceMethodWrapper
. 물론 오리 펀치를 할 수있었습니다 __?attr__
데코레이터의 속성은 내가 지금하고있는 일입니다. 그러나 그것은 못 생겼습니다. 더 나은 아이디어는 매우 환영합니다.
물론, 나는 간단한 데코레이터를 수업과 결합하는 것이 트릭을 수행한다는 것을 즉시 깨달았습니다.
def methodize(method, callable):
"Circumvents the fact that callables are not converted to instance methods."
@wraps(method)
def wrapper(*args, **kw):
return wrapper._callable(*args, **kw)
wrapper._callable = callable
return wrapper
그런 다음 콜에 데코레이터를 추가합니다 InstanceMethodWrapper
메타 클래스에서 :
cls_dict[k] = methodize(v, InstanceMethodWrapper(v))
푸프. 약간의 비스듬하지만 작동합니다.
나는 당신이 클래스의 모든 방법을 사용자 정의 함수로 랩핑하는 메타 클라스를 만들려고한다고 생각합니다.
여기 내 버전이 조금 덜 비스듬히 생각합니다.
import types
class CallableWrappingMeta(type):
def __new__(mcls, name, bases, cls_dict):
instance = type.__new__(mcls, name, bases, cls_dict)
for k in dir(instance):
v = getattr(instance, k)
if isinstance(v, types.MethodType):
setattr(instance, k, instanceMethodWrapper(v))
return instance
def instanceMethodWrapper(function):
def customfunc(*args, **kw):
print "instanceMethodWrapper(*%r, **%r )" % (args, kw)
return function(*args, **kw)
return customfunc
class Bar(object):
__metaclass__ = CallableWrappingMeta
def method(self, a, b):
print a,b
a = Bar()
a.method("foo","bar")
나는 당신이 당신의 문제에 대해 더 구체적이어야한다고 생각합니다. 원래의 질문은 함수 포장에 대해 이야기하지만, 후속 답변은 기능 속성을 보존하는 것에 대해 이야기하는 것 같습니다. 이는 새로운 요소 인 것 같습니다. 디자인 목표를 더 명확하게 설명하면 질문에 대답하기가 더 쉬울 수 있습니다.