믹스 인과 다중 상속을 분리하는 것은 무엇입니까? 의미론의 문제 일까?
믹스 인은 제한된 형태의 다중 상속입니다. 일부 언어에서는 클래스에 믹스 인을 추가하는 메커니즘이 상속과 약간 다릅니다 (구문의 관점에서).
특히 파이썬과 관련하여 믹스 인은 서브 클래스에 기능을 제공하지만 인스턴스화되지는 않는 상위 클래스입니다.
"실제로 믹스 인이 아닌 다중 상속에 불과하다"고 말할 수있는 것은 믹스 인에 대해 혼란 스러울 수있는 클래스가 실제로 인스턴스화되어 사용될 수 있다면 실제로 의미 론적이며 매우 실질적인 차이입니다.
다중 상속의 예
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
모듈.
모두 Counter
와 OrderedDict
인스턴스 자신에 사용하기위한 것입니다. 그러나 두 클래스를 모두 서브 클래 싱하면 카운터가 정렬되어 각 개체의 코드를 재사용 할 수 있습니다.
이것은 코드를 재사용하는 강력한 방법이지만 문제가 될 수도 있습니다. 객체 중 하나에 버그가있는 것으로 밝혀지면주의없이 수정하면 서브 클래스에 버그가 발생할 수 있습니다.
믹스 인의 예
믹스 인은 일반적으로 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)