믹스 인이란 무엇이며 왜 유용합니까? 달리 클래스를 확장하기 위해 다중 상속을 사용하는

Programming Python “에서 Mark Lutz는 “mixins”를 언급합니다. 나는 C / C ++ / C # 배경에서 왔으며 이전 용어를 듣지 못했습니다. 믹스 인이란 무엇입니까?

이 예제 의 행 사이를 읽으면 (매우 길기 때문에 연결되어 있음), ‘상당한’하위 클래스와 달리 클래스를 확장하기 위해 다중 상속을 사용하는 경우라고 가정합니다. 이게 옳은 거니?

새로운 기능을 서브 클래스에 넣는 대신 왜 그렇게하고 싶습니까? 그 점에서 왜 믹스 인 / 멀티 상속 방법이 컴포지션을 사용하는 것보다 낫습니까?

믹스 인과 다중 상속을 분리하는 것은 무엇입니까? 의미론의 문제 일까?



답변

믹스 인은 특별한 종류의 다중 상속입니다. 믹스 인이 사용되는 두 가지 주요 상황이 있습니다.

  1. 수업에 많은 옵션 기능을 제공하려고합니다.
  2. 많은 다른 클래스에서 하나의 특정 기능을 사용하려고합니다.

첫 번째 예는 werkzeug의 요청 및 응답 시스템을 고려 하십시오 . 다음과 같이 말하면 오래된 요청 객체를 만들 수 있습니다.

from werkzeug import BaseRequest

class Request(BaseRequest):
    pass

수락 헤더 지원을 추가하려면

from werkzeug import BaseRequest, AcceptMixin

class Request(AcceptMixin, BaseRequest):
    pass

헤더, etags, 인증 및 사용자 에이전트 지원을 지원하는 요청 오브젝트를 작성하려면 다음을 수행하십시오.

from werkzeug import BaseRequest, AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin

class Request(AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin, BaseRequest):
    pass

차이점은 미묘하지만 위의 예에서 믹스 인 클래스는 독자적으로 만들어지지 않았습니다. 보다 전통적인 다중 상속에서 AuthenticationMixin(예를 들어)는 아마도 더 비슷할 것 Authenticator입니다. 즉, 수업은 아마도 독자적으로 설 수 있도록 설계되었을 것입니다.


답변

먼저 믹스 인은 다중 상속 언어로만 존재합니다. Java 또는 C #에서는 믹스 인을 수행 할 수 없습니다.

기본적으로 믹스 인은 하위 클래스에 대해 제한된 기능과 다형성 공명을 제공하는 독립형 기본 유형입니다. C #으로 생각하고 있다면 이미 구현 되었기 때문에 실제로 구현할 필요가없는 인터페이스를 생각해보십시오. 당신은 그것에서 상속하고 그 기능으로부터 이익을 얻습니다.

믹스 인은 일반적으로 범위가 좁으며 확장되지 않습니다.

[편집-이유에 관해서 :]

당신이 요청한 이후 왜 그런지 설명해야한다고 생각합니다. 가장 큰 장점은 반복해서 스스로 할 필요가 없다는 것입니다. C #에서 믹스 인이 혜택을 얻을 수있는 가장 큰 장소는 Disposal 패턴 일 수 있습니다 . IDisposable을 구현할 때마다 거의 항상 동일한 패턴을 따르고 싶지만 약간의 변형으로 동일한 기본 코드를 작성하고 다시 작성하게됩니다. 확장 가능한 폐기 믹스 인이 있다면 추가 타이핑을 많이 줄일 수 있습니다.

[편집 2-다른 질문에 대답하기 위해]

믹스 인과 다중 상속을 분리하는 것은 무엇입니까? 의미론의 문제 일까?

예. 믹스 인과 표준 다중 상속의 차이점은 의미론의 문제 일뿐입니다. 다중 상속이있는 클래스는 다중 상속의 일부로 믹스 인을 활용할 수 있습니다.

믹스 인의 요점은 상속 유형에 영향을주지 않으면 서 상속을 통해 다른 유형에 “혼합”될 수있는 유형을 생성하는 동시에 해당 유형에 유용한 기능을 제공하는 것입니다.

다시 한 번 이미 구현 된 인터페이스를 생각해보십시오.

나는 개인적으로 믹스 인을 지원하지 않는 언어로 개발하기 때문에 개인적으로 믹스 인을 사용하지 않기 때문에 “ahah”를 제공하는 훌륭한 예를 생각해내는 데 정말 어려운 시간을 보내고 있습니다. 당신을위한 순간. 하지만 다시 시도하겠습니다. 나는 대부분의 언어가 이미 어떤 방식 으로든 그 기능을 제공하는 것으로 고안된 예제를 사용할 것입니다. 그러나 믹스 인이 어떻게 만들어지고 사용되는지를 설명 할 것입니다. 간다 :

XML로 직렬화하거나 XML에서 직렬화 할 수있는 유형이 있다고 가정하십시오. 형식에 형식의 데이터 값이있는 XML 조각이 포함 된 문자열을 반환하는 “ToXML”메서드와 형식이 문자열의 XML 조각에서 데이터 값을 재구성 할 수있는 “FromXML”형식을 제공하려고합니다. 다시 한 번, 이것은 고안된 예이므로 아마도 언어의 런타임 라이브러리에서 파일 스트림 또는 XML Writer 클래스를 사용할 것입니다. 요점은 객체를 XML로 직렬화하고 XML에서 새 객체를 가져오고 싶다는 것입니다.

이 예제에서 다른 중요한 점은 일반적인 방법으로이 작업을 수행한다는 것입니다. 직렬화하려는 모든 유형에 대해 “ToXML”및 “FromXML”메소드를 구현할 필요가 없으며, 유형이이를 수행하고 작동하도록하는 일반적인 수단을 원합니다. 코드 재사용을 원합니다.

언어가 지원하는 경우 XmlSerializable 믹스 인을 만들어서 작업을 수행 할 수 있습니다. 이 유형은 ToXML 및 FromXML 메소드를 구현합니다. 예제에 중요하지 않은 메커니즘을 사용하면 ToXML이 반환 한 XML 조각을 작성하기 위해 혼합 된 모든 유형에서 필요한 모든 데이터를 수집 할 수 있으며 FromXML이 전화했다.

그리고 그게 다야. 이를 사용하려면 XmlSerializable에서 상속 된 XML로 serialize해야하는 모든 유형이 있습니다. 해당 유형을 직렬화 또는 역 직렬화해야 할 때마다 ToXML 또는 FromXML을 호출하면됩니다. 실제로 XmlSerializable은 본격적인 유형이며 다형성이기 때문에 원본 유형에 대해 전혀 모르는 XmlSerializable 유형의 배열 만 받아들이는 문서 시리얼 라이저를 작성할 수 있습니다.

이제이 시나리오를 사용하여 믹스에서 모든 클래스를 혼합하는 모든 클래스 또는이를 혼합하는 유형에 트랜잭션 성을 제공하는 믹스 인을 작성하는 믹스 인 작성과 같은 다른 상황에 대해이 시나리오를 사용한다고 상상해보십시오.

믹스 인을 다른 유형에 영향을주지 않고 유형에 소량의 기능을 추가하도록 설계된 작은 기본 유형으로 생각하면 황금색입니다.

잘만되면 🙂


답변

이 답변은 다음 과 같은 예제와 믹스 인을 설명하는 것을 목표로합니다 .

  • 자체 포함 : 짧고 예제를 이해하기 위해 라이브러리를 알 필요가 없습니다.

  • 다른 언어가 아닌 Python .

    Ruby와 같은 다른 언어의 예제가 있다는 것이 이해할 만합니다. 왜냐하면 용어는 해당 언어에서 훨씬 일반적이지만 파이썬 스레드입니다.

또한 논란의 여지가있는 질문을 고려해야한다.

믹스 인을 특성화하기 위해 다중 상속이 필요합니까?

정의

파이썬에서 믹스 인이 무엇인지 명확하게 말하는 “권한있는”출처의 인용을 아직 보지 못했습니다.

믹스 인에 대한 두 가지 가능한 정의를 보았으며 (추상적 인 기본 클래스와 같은 다른 유사한 개념과 다른 것으로 간주되는 경우) 사람들은 어느 것이 올바른지에 전적으로 동의하지 않습니다.

합의는 언어마다 다를 수 있습니다.

정의 1 : 다중 상속 없음

믹스 인은 클래스의 일부 메소드가 클래스에 정의되지 않은 메소드를 사용하도록 클래스입니다.

따라서이 클래스는 인스턴스화가 아니라 기본 클래스 역할을합니다. 그렇지 않으면 인스턴스에는 예외를 발생시키지 않고 호출 할 수없는 메소드가 있습니다.

일부 소스가 추가하는 제약 조건은 클래스에 데이터가없고 메서드 만 포함될 수 있지만 이것이 왜 필요한지 알 수 없다는 것입니다. 그러나 실제로 많은 유용한 믹스 인에는 데이터가 없으며 데이터가없는 기본 클래스는 사용하기가 더 쉽습니다.

전형적인 예는 모든 비교 연산자의 구현 <===:

class ComparableMixin(object):
    """This class has methods which use `<=` and `==`,
    but this class does NOT implement those methods."""
    def __ne__(self, other):
        return not (self == other)
    def __lt__(self, other):
        return self <= other and (self != other)
    def __gt__(self, other):
        return not self <= other
    def __ge__(self, other):
        return self == other or self > other

class Integer(ComparableMixin):
    def __init__(self, i):
        self.i = i
    def __le__(self, other):
        return self.i <= other.i
    def __eq__(self, other):
        return self.i == other.i

assert Integer(0) <  Integer(1)
assert Integer(0) != Integer(1)
assert Integer(1) >  Integer(0)
assert Integer(1) >= Integer(1)

# It is possible to instantiate a mixin:
o = ComparableMixin()
# but one of its methods raise an exception:
#o != o 

이 특별한 예는 functools.total_ordering()데코레이터 를 통해 달성 할 수 있었지만 여기서 게임은 바퀴를 재발 명하는 것이 었습니다

import functools

@functools.total_ordering
class Integer(object):
    def __init__(self, i):
        self.i = i
    def __le__(self, other):
        return self.i <= other.i
    def __eq__(self, other):
        return self.i == other.i

assert Integer(0) < Integer(1)
assert Integer(0) != Integer(1)
assert Integer(1) > Integer(0)
assert Integer(1) >= Integer(1)

정의 2 : 다중 상속

믹스 인은 기본 클래스의 일부 메소드가 정의하지 않은 메소드를 사용하는 디자인 패턴이며, 해당 메소드는 정의 1에서 파생 된 것이 아니라 다른 기본 클래스에 의해 구현되어야합니다 .

mixin 클래스 라는 용어 는 해당 디자인 패턴에 사용되는 기본 클래스 (메소드를 사용하는 클래스 또는 메소드를 구현하는 클래스)를 나타냅니다.

주어진 클래스가 믹스 인인지 아닌지를 결정하는 것은 쉽지 않습니다. 메소드는 파생 클래스에서 구현 될 수 있습니다.이 경우 정의 1로 돌아갑니다. 저자의 의도를 고려해야합니다.

이 패턴은 다른 기본 클래스 선택으로 기능을 재결합 할 수 있기 때문에 흥미 롭습니다.

class HasMethod1(object):
    def method(self):
        return 1

class HasMethod2(object):
    def method(self):
        return 2

class UsesMethod10(object):
    def usesMethod(self):
        return self.method() + 10

class UsesMethod20(object):
    def usesMethod(self):
        return self.method() + 20

class C1_10(HasMethod1, UsesMethod10): pass
class C1_20(HasMethod1, UsesMethod20): pass
class C2_10(HasMethod2, UsesMethod10): pass
class C2_20(HasMethod2, UsesMethod20): pass

assert C1_10().usesMethod() == 11
assert C1_20().usesMethod() == 21
assert C2_10().usesMethod() == 12
assert C2_20().usesMethod() == 22

# Nothing prevents implementing the method
# on the base class like in Definition 1:

class C3_10(UsesMethod10):
    def method(self):
        return 3

assert C3_10().usesMethod() == 13

권위있는 파이썬 어커런스

collections.abc에 대한 공식 문서 에서 설명서는 Mixin Methods 라는 용어를 명시 적으로 사용합니다 .

그것은 클래스라면 :

  • 구현하다 __next__
  • 단일 클래스에서 상속 Iterator

그런 다음 클래스는 무료 로 __iter__ mixin 메소드 를 얻습니다 .

따라서 최소한이 문서의 시점에서 mixin은 다중 상속을 요구하지 않으며 정의 1과 일치합니다.

물론 문서는 다른 시점에서 모순 될 수 있으며 다른 중요한 Python 라이브러리는 문서에서 다른 정의를 사용하고있을 수 있습니다.

이 페이지는 또한 용어를 사용합니다.이 용어 Set mixin는 클래스를 Mixin 클래스 Set와 같고 Iterator호출 할 수 있음을 명확하게 제안합니다 .

다른 언어로

  • Ruby : Programming Ruby 및 The Ruby programming Language와 같은 주요 참고서에서 언급 한 것처럼 mixin에 대해 다중 상속이 필요하지 않습니다.

  • C ++ : 구현되지 않은 메소드는 순수한 가상 메소드입니다.

    정의 1은 추상 클래스 (순수 가상 메서드가있는 클래스)의 정의와 일치합니다. 해당 클래스는 인스턴스화 할 수 없습니다.

    정의 2는 가상 상속으로 가능합니다. 두 개의 파생 클래스에서 다중 상속


답변

나는 그것들을 다중 상속을 사용하는 훈련 된 방법으로 생각합니다. 궁극적으로 mixin은 mixin이라는 클래스에 대한 규칙을 따르는 다른 파이썬 클래스이기 때문입니다.

Mixin이라고 부르는 것을 지배하는 규칙에 대한 나의 이해는 Mixin입니다.

  • 메소드를 추가하지만 인스턴스 변수는 추가하지 않습니다 (클래스 상수는 정상 임)
  • 만 상속 object(파이썬)

그렇게하면 다중 상속의 잠재적 복잡성을 제한하고, 전체 다중 상속과 비교하여 볼 위치를 제한하여 프로그램 흐름을 합리적으로 쉽게 추적 할 수 있습니다. 그것들은 루비 모듈 과 비슷 합니다 .

인스턴스 변수를 추가하려면 (단일 상속으로 허용되는 것보다 유연성이 높음) 컴포지션을 선호합니다.

말했듯이 인스턴스 변수가있는 XYZMixin이라는 클래스를 보았습니다.


답변

믹스 인은 프로그래밍에서 클래스가 기능을 제공하는 개념이지만 인스턴스화에는 사용되지 않습니다. 믹스 인의 주요 목적은 독립형 기능을 제공하는 것이며 믹스 인 자체가 다른 믹스 인과 상속되지 않고 상태를 피하는 것이 가장 좋습니다. Ruby와 같은 언어에는 직접적인 언어 지원이 있지만 Python의 경우에는 지원되지 않습니다. 그러나 다중 클래스 상속을 사용하여 Python에서 제공하는 기능을 실행할 수 있습니다.

믹스 인의 기본 사항을 이해하기 위해 http://www.youtube.com/watch?v=v_uKI2NOLEM 비디오를 보았습니다 . 초보자는 믹스 인의 기본 사항과 믹스 인의 작동 방식 및이를 구현할 때 직면 할 수있는 문제를 이해하는 것이 매우 유용합니다.

Wikipedia는 여전히 최고입니다 : http://en.wikipedia.org/wiki/Mixin


답변

믹스 인과 다중 상속을 분리하는 것은 무엇입니까? 의미론의 문제 일까?

믹스 인은 제한된 형태의 다중 상속입니다. 일부 언어에서는 클래스에 믹스 인을 추가하는 메커니즘이 상속과 약간 다릅니다 (구문의 관점에서).

특히 파이썬과 관련하여 믹스 인은 서브 클래스에 기능을 제공하지만 인스턴스화되지는 않는 상위 클래스입니다.

“실제로 믹스 인이 아닌 다중 상속에 불과하다”고 말할 수있는 것은 믹스 인에 대해 혼란 스러울 수있는 클래스가 실제로 인스턴스화되어 사용될 수 있다면 실제로 의미 론적이며 매우 실질적인 차이입니다.

다중 상속의 예

documentation 의이 예제 는 OrderedCounter입니다.

class OrderedCounter(Counter, OrderedDict):
     'Counter that remembers the order elements are first encountered'

     def __repr__(self):
         return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))

     def __reduce__(self):
         return self.__class__, (OrderedDict(self),)

그것은 모두 서브 클래스 Counter와를 OrderedDict으로부터 collections모듈.

모두 CounterOrderedDict인스턴스 자신에 사용하기위한 것입니다. 그러나 두 클래스를 모두 서브 클래 싱하면 카운터가 정렬되어 각 개체의 코드를 재사용 할 수 있습니다.

이것은 코드를 재사용하는 강력한 방법이지만 문제가 될 수도 있습니다. 객체 중 하나에 버그가있는 것으로 밝혀지면주의없이 수정하면 서브 클래스에 버그가 발생할 수 있습니다.

믹스 인의 예

믹스 인은 일반적으로 OrderedCounter와 같은 협동 다중 상속이 가질 수있는 잠재적 인 커플 링 문제없이 코드 재사용을 얻는 방법으로 홍보됩니다. 믹스 인을 사용할 때는 데이터와 밀접한 관련이없는 기능을 사용합니다.

위의 예와 달리 믹스 인은 단독으로 사용하도록 의도되지 않았습니다. 새롭거나 다른 기능을 제공합니다.

예를 들어, 표준 라이브러리에는 라이브러리에 두 개의 믹스 인이 socketserver있습니다 .

이러한 혼합 클래스를 사용하여 각 서버 유형의 포크 및 스레딩 버전을 작성할 수 있습니다. 예를 들어 ThreadingUDPServer는 다음과 같이 생성됩니다.

class ThreadingUDPServer(ThreadingMixIn, UDPServer):
    pass

믹스 인 클래스는 UDPServer에 정의 된 메소드를 대체하므로 믹스 클래스가 우선합니다. 다양한 속성을 설정하면 기본 서버 메커니즘의 동작도 변경됩니다.

이 경우 mixin 메소드 UDPServer는 동시성을 허용하기 위해 오브젝트 정의 의 메소드를 대체합니다 .

재정의 된 메서드가있는 것처럼 보이며 process_request다른 메서드도 제공합니다 process_request_thread. 다음은 소스 코드 에서 가져온 것입니다 .

class ThreadingMixIn:
        """Mix-in class to handle each request in a new thread."""

        # Decides how threads will act upon termination of the
        # main process
        daemon_threads = False

        def process_request_thread(self, request, client_address):
            """Same as in BaseServer but as a thread.
            In addition, exception handling is done here.
            """
            try:
                self.finish_request(request, client_address)
            except Exception:
                self.handle_error(request, client_address)
            finally:
                self.shutdown_request(request)

        def process_request(self, request, client_address):
            """Start a new thread to process the request."""
            t = threading.Thread(target = self.process_request_thread,
                                 args = (request, client_address))
            t.daemon = self.daemon_threads
            t.start()

고안된 예

이것은 대부분 데모 목적으로 사용되는 믹스 인입니다. 대부분의 객체는이 repr의 유용성을 넘어서 진화 할 것입니다.

class SimpleInitReprMixin(object):
    """mixin, don't instantiate - useful for classes instantiable
    by keyword arguments to their __init__ method.
    """
    __slots__ = () # allow subclasses to use __slots__ to prevent __dict__
    def __repr__(self):
        kwarg_strings = []
        d = getattr(self, '__dict__', None)
        if d is not None:
            for k, v in d.items():
                kwarg_strings.append('{k}={v}'.format(k=k, v=repr(v)))
        slots = getattr(self, '__slots__', None)
        if slots is not None:
            for k in slots:
                v = getattr(self, k, None)
                kwarg_strings.append('{k}={v}'.format(k=k, v=repr(v)))
        return '{name}({kwargs})'.format(
          name=type(self).__name__,
          kwargs=', '.join(kwarg_strings)
          )

사용법은 다음과 같습니다.

class Foo(SimpleInitReprMixin): # add other mixins and/or extend another class here
    __slots__ = 'foo',
    def __init__(self, foo=None):
        self.foo = foo
        super(Foo, self).__init__()

그리고 사용법 :

>>> f1 = Foo('bar')
>>> f2 = Foo()
>>> f1
Foo(foo='bar')
>>> f2
Foo(foo=None)

답변

나는 여기에 좋은 설명이 있다고 생각하지만 다른 관점을 제공하고 싶었습니다.

스칼라에서는 여기에 설명 된대로 믹스 인을 수행 할 수 있지만 매우 흥미로운 점은 믹스 인이 실제로 ‘융합되어’상속 할 새로운 종류의 클래스를 생성한다는 것입니다. 본질적으로 여러 클래스 / 믹스 인에서 상속하는 것이 아니라 상속 할 믹스 인의 모든 속성을 사용하여 새로운 종류의 클래스를 생성합니다. Scala는 다중 상속이 현재 지원되지 않는 JVM을 기반으로하기 때문에 의미가 있습니다 (Java 8 기준). 그건 그렇고,이 믹스 인 클래스 유형은 스칼라의 특성이라고하는 특수 유형입니다.

클래스가 정의 된 방식으로 암시되었습니다 : NewClass 클래스는 ThirdMixin으로 FirstMixin을 ThirdMixin으로 확장합니다 …

CPython 인터프리터가 동일한 작업을 수행하는지 확실하지 않지만 (mixin class-composition) 놀라지 않을 것입니다. 또한 C ++ 배경에서 나는 믹스 인에 해당하는 ABC 또는 ‘인터페이스’를 호출하지 않습니다. 유사한 개념이지만 사용 및 구현이 다양합니다.