문제

메타 클라스가 있다고 가정 해 봅시다 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")

나는 당신이 당신의 문제에 대해 더 구체적이어야한다고 생각합니다. 원래의 질문은 함수 포장에 대해 이야기하지만, 후속 답변은 기능 속성을 보존하는 것에 대해 이야기하는 것 같습니다. 이는 새로운 요소 인 것 같습니다. 디자인 목표를 더 명확하게 설명하면 질문에 대답하기가 더 쉬울 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top