2012-05-09 4 views
2

간단한 TRS (Triumper Rewriting System)/Symbolic Algebra System을 Python으로 구현하는 방법을 실험하고 있습니다. 이 경우 클래스 인스턴스 인스턴스화 프로세스 중에 특정 경우에 피연산자를 가로 채고 수정할 수 있어야합니다. 필자가 생각해 낸 해결책은 클래스 객체 (type 'type')의 동작을 수정하는 메타 클래스를 만드는 것이 었습니다.Python : 클래스 인스턴스 초기화 전에 전달 된 인수 수정

class Preprocess(type): 
    """ 
    Operation argument preprocessing Metaclass. 
    Classes using this Metaclass must implement the 
     _preprocess_(*operands, **kwargs) 
    classmethod. 
    """ 

    def __call__(cls, *operands, **kwargs): 
     pops, pargs = cls._preprocess_(*operands, **kwargs) 
     return super(Preprocess, cls).__call__(*pops, **pargs) 

예 케이스 중첩 연산 F 밖으로 확장하는 것 (F를 (a, b), c) -> F (A, B, C)

class Flat(object): 
    """ 
    Use for associative Operations to expand nested 
    expressions of same Head: F(F(x,y),z) => F(x,y,z) 
    """ 
    __metaclass__ = Preprocess 
    @classmethod 
    def _preprocess_(cls, *operands, **kwargs): 
     head = [] 
     for o in operands: 
      if isinstance(o, cls): 
       head += list(o.operands) 
      else: 
       head.append(o) 
     return tuple(head), kwargs 

그래서 지금 동작은 상속을 통해 실현 될 수있다 :

print F(F(1,2,3),4,5).operands 
(1,2,3,4,5) 
:

class Operation(object): 
    def __init__(self, *operands): 
     self.operands = operands 

class F(Flat, Operation): 
    pass 

이 원하는 동작에 이르게

그러나 이러한 전처리 클래스를 여러 개 결합하여 자연스러운 클래스 mro에 따라 피연산자를 순차적으로 처리하도록하겠습니다.

class Orderless(object): 
    """ 
    Use for commutative Operations to bring into ordered, equivalent 
    form: F(*operands) => F(*sorted(operands)) 
    """ 
    __metaclass__ = Preprocess 

    @classmethod 
    def _preprocess_(cls, *operands, **kwargs): 

     return sorted(operands), kwargs 

그리고 원하는대로 작동하지 않는 것 같습니다. 평평한 주문형 작업 유형 정의

class G(Flat, Orderless, Expression): 
    pass 

결과는 첫 번째 전처리 슈퍼 클래스가 '활성'이됩니다.

print G(G(3,2,1),-1,-3).operands 
(3,2,1,-1,-3) 

어떻게 모든 전처리 클래스 '전처리 방법은 클래스 인스턴스화 전에 호출되도록 할 수 있습니다?

업데이트 :

나는 때문에 새로운 유래 사용자로 내 상태에 공식적으로 아직 내 질문에 대답 할 수없는 것.

class Preprocess(type): 
    """ 
    Abstract operation argument preprocessing class. 
    Subclasses must implement the 
     _preprocess_(*operands, **kwargs) 
    classmethod. 
    """ 

    def __call__(cls, *operands, **kwargs): 
     for cc in cls.__mro__: 
      if hasattr(cc, "_preprocess_"): 
       operands, kwargs = cc._preprocess_(*operands, **kwargs) 

     return super(Preprocess, cls).__call__(*operands, **kwargs) 

나는 문제가 예상대로 super(Preprocess, cls).__call__(*operands, **kwargs)는 CLS의 MRO를 통과하지 않는 것 같다 : 그래서, 나는 이것이 아마 내가 가지고 올 수있는 최고의 솔루션입니다 생각합니다.

+0

할당자를 재정의하고 기준자를 검사하게하십시오. –

+0

흠, 정확히 어떻게 작동할까요? Preprocess .__ call__ 메서드에서 cls 개체의 __bases__를 출력하면 (예상대로) (<클래스 '__main __. Flat'>, <클래스> __main __, 주문 없음>, <클래스 '__main __. 작업'>) – Nikolas

+0

동적 유형의 객체를 반환해야합니다. 그래서 당신은 할당 자에서 그것을합니다. –

답변

1

나는 이것이 잘못된 방향으로 가고 있다고 생각합니다. 메타 클래스를 삭제하고 대신 클래스 및 메서드 데코레이터를 사용하십시오.

@init_args_preprocessor 
def flat(operands, kwargs): # No need for asterisks 
    head = [] 
    for o in operands: 
     if isinstance(o, cls): 
      head += list(o.operands) 
     else: 
      head.append(o) 
    return tuple(head), kwargs 
클래스 장식으로 해당 기능을 선회 init_args_preprocessor 데코레이터와

:

: 지금

def init_args_preprocessor(preprocessor): 
    def class_decorator(cls): 
     orig_init = cls.__init__ 
     def new_init(self, *args, **kwargs): 
      args, kwargs = preprocessor(args, kwargs) 
      orig_init(self, *args, **kwargs) 
     cls.__init__ = new_init 
     return cls 
    return class_decorator 

그리고, 대신 유지 mixin 장식을 사용

예를 들어, 평면으로 정의

class Operation(object): 
    def __init__(self, *operands): 
     self.operands = operands 

@flat 
class F(Operation): 
    pass 

그리고 클래스 수정자를 결합해도 아무런 문제가 없어야합니다. 깔끔하게 :

@init_args_preprocessor 
def orderless(args, kwargs): 
    return sorted(args), kwargs 

@orderless 
@flat 
class G(Expression): 
    pass 

위의 모든 코드는 엄격히 테스트되지 않았습니다.

+0

안녕하세요. 매우 훌륭한 솔루션 인 것처럼 보입니다. 실제로 지금은 그 라인을 따라 뭔가를하고 있습니다. 이 문제의 한가지 문제는 'G'객체가 더 이상 클래스가 아니라 함수가 될 것이므로 isinstance() 검사가 더 이상 조정하지 않고 실패 할 것입니다. – Nikolas

+1

'G '가 왜 기능합니까? 클래스 데코레이터에 의해서만 수정됩니다. '@ init_args_preprocessor'는'flat'을 클래스를 취하여 클래스를 반환하는 함수로 만듭니다. –

+0

제 잘못, 당신 말이 맞아요. 사실, 이것이 내가했던 일과 정확히 같습니다. – Nikolas

관련 문제