2012-01-15 3 views
6

기본 클래스의 __metaclass__을 변경 한 후 해당 하위 클래스가 자동으로 새 __metaclass__을 사용하도록 메타 캐 이드에 대한 이상하고 비정상적인 사용 사례가 있습니다. 하지만 그건 이상한 작동하지 않습니다클래스의 __metaclass__ 속성을 변경할 수없는 이유는 무엇입니까?

class MetaBase(type): 
    def __new__(cls, name, bases, attrs): 
     attrs["y"] = attrs["x"] + 1 
     return type.__new__(cls, name, bases, attrs) 

class Foo(object): 
    __metaclass__ = MetaBase 
    x = 5 

print (Foo.x, Foo.y) # prints (5, 6) as expected 

class MetaSub(MetaBase): 
    def __new__(cls, name, bases, attrs): 
     attrs["x"] = 11 
     return MetaBase.__new__(cls, name, bases, attrs) 

Foo.__metaclass__ = MetaSub 

class Bar(Foo): 
    pass 

print(Bar.x, Bar.y) # prints (5, 6) instead of (11, 12) 
내가 잘 정의되지 않은// 지혜가 지원되지 않는 수 있습니다 뭘하는지

하지만, 기존의 메타 클래스가 호출되고 어떻게 내 인생을 알아낼 수 없습니다를 들어, 그게 가능한지 적어도 이해하고 싶습니다.

편집 :jsbueno에 의해 제안을 바탕으로, 나는 내가 원하는 정확히 한 다음 라인으로 라인 Foo.__metaclass__ = MetaSub, 대체 :

Foo = type.__new__(MetaSub, "Foo", Foo.__bases__, dict(Foo.__dict__)) 

답변

2

클래스에 대한 메타 클래스 정보는 클래스가 생성 될 때 사용되며 (클래스 블록으로 구문 분석되거나 동적으로 메타 클래스를 명시 적으로 호출 함) 사용됩니다. 메타 클래스가 대개 클래스 생성시 변경을 가하기 때문에 변경할 수 없습니다. 생성 된 클래스 유형은 메타 클래스입니다. 그것의 __metaclass__ 속성은 일단 생성되면 무의미합니다.

그러나 주어진 클래스의 복사본을 만들고 복사본에 원래 클래스와 다른 메타 클래스를 사용할 수 있습니다. 경우에 대신 일을 당신의 예에

:

Foo.__metaclass__ = MetaSub

당신이 할 : 당신은 당신의 의도를 달성 할

Foo = Metasub("Foo", Foo.__bases__, dict(Foo.__dict__))

. 새로운 Foo은 모든 효과가 전임자와 같지만 다른 메타 클래스가 적용됩니다.

그러나 기존의 인스턴스 인 Foo은 새로운 Foo의 인스턴스로 간주되지 않습니다. 필요한 경우 Foo 사본을 다른 이름으로 생성하는 것이 좋습니다.

+0

팁을 주셔서 고마워요. 정확히 내가 원하는 것을하지 않았습니다. 왜냐하면 여전히'Foo'의 서브 클래스가 메타 클래스를 갖기를 원하기 때문입니다. 그러나 필자는 여러분이 원하는대로했던 솔루션을 포함하도록 내 질문을 편집했습니다. 암시. –

3

문제는 __metaclass__ 속성을 사용하지 않는입니다 때 상속 된, 당신이 예상 할 수있는 것과 반대. '오래된'메타 클래스는 Bar에 대해 호출되지 않습니다.

  • 하면 딕셔너리는 [ '__ metaclass__'은, 그것이 사용 존재 :

    적절한 메타 클래스는 다음과 같은 우선 순위 규칙에 의해 결정된다 : 워드 프로세서는 메타 클래스가 발견 방법에 대해 다음과 말한다.

  • 그렇지 않으면 적어도 하나의 기본 클래스가있는 경우 해당 메타 클래스가 사용됩니다.이 클래스는 __class__ 특성을 먼저 찾으며 찾을 수없는 경우 은 해당 형식을 사용합니다.
  • 그렇지 않으면 __metaclass__이라는 전역 변수가 있으면 사용됩니다.
  • 그렇지 않으면 이전 스타일의 고전적인 메타 클래스 (types.ClassType)가 사용됩니다. 실제로 Bar 클래스의 메타 클래스로 사용됩니다 그래서

는 부모의 __class__ 속성에 아닌 부모의 __metaclass__ 속성에서 발견된다.

자세한 내용은 this StackOverflow answer에서 확인할 수 있습니다.

1

하위 클래스는 부모 중 __metaclass__을 사용합니다.

사용 사례에 대한 해결책은 부모의 하위 클래스보다 다른 동작을 갖도록 부모의 __metaclass__을 프로그래밍하는 것입니다. 아마도 클래스 변수에 대한 클래스 사전을 검사하고 해당 값에 따라 다른 동작을 구현해야합니다 (유형__slots__이 정의되었는지 여부에 따라 인스턴스에 사전이 지정되는지 여부를 제어하는 ​​데 사용됩니다.).

+0

실제 예제에서 상위 클래스는 타사 모듈에서 가져온 것이므로 해당 모듈에서 클래스를 확장하려고하지만 제 3 자 모듈의 메타 클래스 동작을 재정의하는 자체 메타 클래스가 필요합니다. 그렇지 않으면 나는 분명히 당신이 제안한 것을 할 것입니다. –

+0

@EliCourtwright 아마 제 3 자 모듈을 상속하지 않고 위임하는 자신의 클래스를 롤 할 수 있습니다. 코드 재사용을 극대화하는 동시에 클래스 생성 프로세스를 완벽하게 제어 할 수 있어야합니다. –

관련 문제