एक मिक्सिन क्या है, और वे क्यों उपयोगी हैं?


951

" प्रोग्रामिंग पायथन " में, मार्क लुत्ज़ ने "मिक्सिन्स" का उल्लेख किया है। मैं C / C ++ / C # बैकग्राउंड से हूं और मैंने इससे पहले शब्द नहीं सुना है। मिक्सचर क्या है?

इस उदाहरण की पंक्तियों के बीच पढ़ना (जो मैंने इसे बहुत लंबा होने के कारण लिंक किया है), मैं मान रहा हूं कि 'उचित' उपवर्ग के विपरीत एक वर्ग का विस्तार करने के लिए एकाधिक वंशानुक्रम का उपयोग करने का मामला है। क्या यह सही है?

मैं नई कार्यक्षमता को उपवर्ग में रखने के बजाय ऐसा क्यों करना चाहूंगा? उस मामले के लिए, एक मिक्सिन / मल्टीपल इनहेरिटेंस एप्रोच रचना का उपयोग करने से बेहतर क्यों होगा?

क्या एक मिश्रण को कई विरासत से अलग करता है? क्या यह सिर्फ शब्दार्थ की बात है?

जवाबों:


706

एक मिश्रण एक विशेष प्रकार की कई विरासत है। दो मुख्य परिस्थितियाँ हैं जहाँ मिश्रण का उपयोग किया जाता है:

  1. आप एक वर्ग के लिए बहुत सारी वैकल्पिक सुविधाएँ प्रदान करना चाहते हैं।
  2. आप विभिन्न वर्गों में एक विशेष सुविधा का उपयोग करना चाहते हैं।

नंबर एक के उदाहरण के लिए, werkzeug के अनुरोध और प्रतिक्रिया प्रणाली पर विचार करें । मैं यह कहकर एक सादे पुराने अनुरोध की वस्तु बना सकता हूं:

from werkzeug import BaseRequest

class Request(BaseRequest):
    pass

अगर मैं स्वीकार शीर्ष लेख समर्थन जोड़ना चाहता हूं, तो मैं इसे बनाऊंगा

from werkzeug import BaseRequest, AcceptMixin

class Request(AcceptMixin, BaseRequest):
    pass

अगर मैं एक अनुरोध ऑब्जेक्ट बनाना चाहता हूं जो हेडर, एटिग, प्रमाणीकरण और उपयोगकर्ता एजेंट समर्थन का समर्थन करता है, तो मैं यह कर सकता हूं:

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

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

अंतर सूक्ष्म है, लेकिन उपरोक्त उदाहरणों में, मिक्सिन वर्ग को अपने दम पर खड़ा नहीं किया गया था। अधिक पारंपरिक एकाधिक वंशानुक्रम में, AuthenticationMixin(उदाहरण के लिए) संभवतः कुछ अधिक पसंद किया जाएगा Authenticator। यही है, वर्ग शायद अपने दम पर खड़ा करने के लिए डिज़ाइन किया जाएगा।


123
एक तीसरी स्थिति यह है: आप एक वर्ग के लिए बहुत सारी (नहीं-वैकल्पिक) सुविधाएँ प्रदान करना चाहते हैं, लेकिन आप अलग-अलग वर्गों (और अलग-अलग मॉड्यूल) में सुविधाएँ चाहते हैं, इसलिए प्रत्येक मॉड्यूल एक विशेषता (व्यवहार) IOW के बारे में नहीं है। पुन: उपयोग के लिए, लेकिन डिब्बे में बंद करने के लिए।
बूटक

60
संभवतः इस उदाहरण में कोई समस्या नहीं है, लेकिन आप आम तौर पर मुख्य आधार वर्ग को मूल तत्व के भीतर अंतिम तत्व के रूप में रखना चाहते हैं ताकि विरासत श्रृंखला बनाने के लिए अनुरोध करें: अनुरोध ==> मिक्सिन ==> ... ==> बेसरप्सेस्ट। यहां देखें: ianlewis.org/en/mixins-and-python
hillel

10
@ हिलेल अच्छी बात है, लेकिन ध्यान रखें कि पायथन बाएं से दाएं (जब आपको कंस्ट्रक्टर को ओवरराइड करने की आवश्यकता होती है, तो सुपरक्लासेस के तरीकों को कहेंगे)।
एलिसु मोनार डॉस सैंटोस

9
यह डेकोरेटर डिजाइन पैटर्न जैसा लगता है।
D-जोन्स

4
एक 4 स्थिति है: वहाँ पहले से ही के एक मौजूदा परिवार है Parentवर्ग और Child1, Child2, ChildNएक 3 पार्टी पुस्तकालय के अंदर उपवर्गों, और आप पूरे परिवार के लिए एक स्वनिर्धारित व्यवहार चाहते हैं। आदर्श रूप से आप इस तरह के व्यवहार को जोड़ना चाहेंगे Parent, और आशा करते हैं कि 3rd पार्टी लाइब्रेरी डेवलपर आपका Pull Request लेगा। अन्यथा आपको अपना खुद का कार्यान्वयन करना होगा class NewBehaviorMixin, और फिर रैपर कक्षाओं जैसे कि class NewParent(NewBehaviorMixin, Parent): passऔर class NewChildN(NewBehaviorMixin, ChildN): passआदि के एक पूर्ण सेट को परिभाषित करना होगा (PS: क्या आप एक बेहतर तरीका जानते हैं?)
RayLuo

240

सबसे पहले, आपको ध्यान देना चाहिए कि मिश्रण केवल कई-विरासत भाषाओं में मौजूद हैं। आप जावा या C # में एक मिक्सिन नहीं कर सकते।

मूल रूप से, एक मिक्सिन एक स्टैंड-अलोन बेस टाइप है जो एक चाइल्ड क्लास के लिए सीमित कार्यक्षमता और बहुरूपी प्रतिध्वनि प्रदान करता है। यदि आप C # में सोच रहे हैं, तो एक ऐसे इंटरफ़ेस के बारे में सोचें जिसे आपको वास्तव में लागू नहीं करना है क्योंकि यह पहले से ही लागू है; आप बस इसे विरासत में लेते हैं और इसकी कार्यक्षमता से लाभ उठाते हैं।

मिश्रण आमतौर पर दायरे में संकीर्ण होते हैं और विस्तारित होने के लिए नहीं होते हैं।

[संपादित करें - क्यों:]

मुझे लगता है मुझे पता होना चाहिए कि क्यों, जब से आपने पूछा। बड़ा लाभ यह है कि आपको इसे बार-बार करने की जरूरत नहीं है। C # में, सबसे बड़ी जगह जहां एक मिक्सिन को फायदा हो सकता है वह डिस्पोज़ल पैटर्न से हो सकता है । जब भी आप आईडीसोपायरी को लागू करते हैं, आप लगभग हमेशा एक ही पैटर्न का पालन करना चाहते हैं, लेकिन आप मामूली बदलावों के साथ एक ही मूल कोड लिखना और फिर से लिखना शुरू करते हैं। अगर एक विस्तार योग्य प्रस्ताव मिश्रण होता, तो आप अपने आप को कई अतिरिक्त टाइपिंग से बचा सकते थे।

[संपादित 2 - अपने अन्य सवालों के जवाब देने के लिए]

क्या एक मिश्रण को कई विरासत से अलग करता है? क्या यह सिर्फ शब्दार्थ की बात है?

हाँ। एक मिश्रण और मानक कई विरासत के बीच का अंतर सिर्फ शब्दार्थ का विषय है; एक वर्ग जिसमें एकाधिक वंशानुक्रम होता है, उस एकाधिक वंशानुक्रम के भाग के रूप में एक मिश्रण का उपयोग कर सकता है।

एक मिक्सिन का बिंदु एक प्रकार बनाना है जो विरासत के प्रकार के माध्यम से किसी अन्य प्रकार में "मिश्रित" किया जा सकता है, जबकि उस प्रकार के लिए कुछ लाभकारी कार्यक्षमता की पेशकश करते हुए, विरासत के प्रकार को प्रभावित किए बिना।

फिर से, एक इंटरफ़ेस के बारे में सोचें जो पहले से ही लागू है।

मैं व्यक्तिगत रूप से मिक्सिन्स का उपयोग नहीं करता हूं क्योंकि मैं मुख्य रूप से एक भाषा में विकसित करता हूं जो उनका समर्थन नहीं करता है, इसलिए मुझे एक सभ्य उदाहरण के साथ आने वाला वास्तव में मुश्किल समय आ रहा है जो कि "अहा!" आपके लिए पल। लेकिन मैं फिर से कोशिश करूँगा। मैं एक ऐसे उदाहरण का उपयोग करने जा रहा हूँ जो कि वंचित है - अधिकांश भाषाएँ पहले से ही किसी न किसी तरह से सुविधा प्रदान करती हैं - लेकिन वह, उम्मीद है, यह बताएगी कि कैसे मिश्रण का निर्माण और उपयोग किया जाना चाहिए। यहाँ जाता हैं:

मान लीजिए कि आपके पास एक प्रकार है जिसे आप XML से और उसके लिए क्रमबद्ध करना चाहते हैं। आप "टोक्सएमएल" विधि प्रदान करने का प्रकार चाहते हैं जो एक स्ट्रिंग को डेटा के मान के साथ XML टुकड़ा युक्त लौटाता है, और एक "FromXML" जो स्ट्रिंग में अपने डेटा मानों को XML टुकड़े से पुनर्निर्माण करने की अनुमति देता है। फिर, यह एक विरोधाभासी उदाहरण है, इसलिए शायद आप अपनी भाषा की रनटाइम लाइब्रेरी से फ़ाइल स्ट्रीम, या एक्सएमएल राइटर क्लास का उपयोग करें। मुद्दा यह है कि आप अपनी वस्तु को XML में क्रमबद्ध करना चाहते हैं और XML से एक नई वस्तु प्राप्त करना चाहते हैं।

इस उदाहरण में दूसरा महत्वपूर्ण बिंदु यह है कि आप इसे सामान्य तरीके से करना चाहते हैं। आप प्रत्येक प्रकार के लिए "ToXML" और "FromXML" पद्धति को लागू नहीं करना चाहते हैं जिसे आप क्रमबद्ध करना चाहते हैं, आप यह सुनिश्चित करने के कुछ सामान्य साधन चाहते हैं कि आपका प्रकार यह करेगा और यह सिर्फ काम करता है। आप कोड का पुन: उपयोग चाहते हैं

यदि आपकी भाषा ने इसका समर्थन किया है, तो आप आपके लिए अपना काम करने के लिए XmlSerializable मिक्सिन बना सकते हैं। यह प्रकार ToXML और FromXML विधियों को लागू करेगा। यह, उदाहरण के लिए महत्वपूर्ण नहीं है कि कुछ तंत्र का उपयोग करना, किसी भी प्रकार से सभी आवश्यक डेटा को इकट्ठा करने में सक्षम होना चाहिए जो कि टोक्सएमएल द्वारा लौटाए गए XML टुकड़े का निर्माण करने के लिए इसमें मिलाया जाता है और यह उस डेटा को पुनर्स्थापित करने में समान रूप से सक्षम होगा जब FromXML बुलाया।

और बस। इसका उपयोग करने के लिए, आपके पास कोई भी प्रकार होगा जिसे XML से अनुक्रमित करने की आवश्यकता होगी XmlSerializable से विरासत में। जब भी आपको उस प्रकार को क्रमबद्ध या deserialize करने की आवश्यकता होती है, आप बस ToXML या FromXML को कॉल करेंगे। वास्तव में, चूंकि XmlSerializable एक पूरी तरह से विकसित प्रकार और बहुरूपी है, आप एक ऐसे दस्तावेज़ धारावाहिक का निर्माण कर सकते हैं, जो आपके मूल प्रकार के बारे में कुछ भी नहीं जानता हो, केवल, कहे, तो XmlSerializable प्रकारों की एक सरणी।

अब अन्य चीजों के लिए इस परिदृश्य का उपयोग करने की कल्पना करें, जैसे कि एक मिक्सिन बनाना जो यह सुनिश्चित करता है कि हर वर्ग जो इसे हर विधि कॉल में लॉग में मिलाता है, या एक मिक्सिन जो उस मिश्रण में टाइप करने के लिए ट्रांजेक्शनलिटी प्रदान करता है। सूची पर और पर जा सकती है।

यदि आप मिक्सिन को केवल एक छोटा आधार प्रकार मानते हैं, जो कि उस प्रकार को प्रभावित किए बिना एक प्रकार की कार्यक्षमता की एक छोटी मात्रा को जोड़ने के लिए डिज़ाइन किया गया है, तो आप सुनहरे हैं।

उम्मीद है कि। :)


25
अरे, क्या आपको वह वाक्यांश "बहुरूपी प्रतिध्वनि" पसंद है? इसे खुद बनाया। मुझे लगता है। शायद मैंने इसे भौतिकी में कहीं सुना ...
Randolpho

50
मैं आपके पहले वाक्य पर थोड़ा असहमत हूं। रूबी एक एकल-विरासत भाषा है और मिक्सिन्स किसी दिए गए वर्ग w / o को दूसरी श्रेणी से विरासत में जोड़ने के तरीके हैं।
केल्टिया

23
@ केल्टिया: मुझे लगता है कि मिक्सिन हैं - परिभाषा के अनुसार - मल्टीपल-इनहेरिटेंस। रूबी मामले में, वे एक बंदर (या कुछ और) एक उचित मिश्रण नहीं हैं। रूबी लोग इसे मिक्सी कह सकते हैं, लेकिन यह एक अलग तरह की बात है।
S.Lott

10
वास्तव में, एक सच्चा मिश्रण एकाधिक वंशानुक्रम का उपयोग नहीं कर सकता है। एक मिश्रण में एक वर्ग से दूसरे वर्ग के तरीके, गुण आदि शामिल हैं, जो उसे विरासत में नहीं मिले। यह कोड पुन: उपयोग का लाभ देने के लिए जाता है बहुरूपता के साथ लगता है, लेकिन पेरेंटेज (मृत्यु का हीरा, आदि) का निर्धारण करने वाली समस्याओं को छोड़ देता है मिक्सिन सहायक भाषाएं भी मिक्सिन वर्ग के आंशिक समावेश की अनुमति देती हैं (चीजें थोड़ी सी लगने लगी हैं पहलुओं अब)।
ट्रेवर

8
रिकॉर्ड के लिए, जावा अब डिफ़ॉल्ट विधियों के साथ मिश्रण का समर्थन करता है।
shmosel

169

इस उत्तर का उद्देश्य मिश्रणों को उन उदाहरणों से समझाना है :

  • आत्म-निहित : लघु, उदाहरण को समझने के लिए किसी भी पुस्तकालय को जानने की आवश्यकता नहीं है।

  • पायथन में , अन्य भाषाओं में नहीं।

    यह समझा जा सकता है कि रूबी जैसी अन्य भाषाओं के उदाहरण थे क्योंकि यह शब्द उन भाषाओं में बहुत अधिक सामान्य है, लेकिन यह पायथन धागा है।

यह विवादास्पद प्रश्न पर भी विचार करेगा:

एक मिश्रण की विशेषता के लिए एकाधिक वंशानुक्रम आवश्यक है या नहीं?

परिभाषाएं

मुझे अभी तक "आधिकारिक" स्रोत से प्रशस्ति पत्र देखने को नहीं मिला है, जो स्पष्ट रूप से कह रहा है कि पायथन में एक मिश्रण है।

मैंने एक मिक्सिन की 2 संभावित परिभाषाएं देखी हैं (यदि उन्हें अन्य समान अवधारणाओं जैसे अमूर्त आधार वर्गों से अलग माना जाता है), और लोग पूरी तरह से सहमत नहीं हैं, जिस पर एक सही है।

विभिन्न भाषाओं के बीच आम सहमति अलग-अलग हो सकती है।

परिभाषा 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 के लिए सरकारी documentatiton प्रलेखन स्पष्ट रूप से इस शब्द का इस्तेमाल Mixin के तरीके

यह बताता है कि यदि एक वर्ग:

  • औजार __next__
  • एक ही वर्ग से विरासत में मिला है Iterator

तब वर्ग को मुफ्त में एक मिश्रण __iter__ विधि मिलती है ।

इसलिए कम से कम प्रलेखन के इस बिंदु पर, मिक्सिन को कई विरासत की आवश्यकता नहीं है , और परिभाषा 1 के साथ सुसंगत है।

प्रलेखन विभिन्न बिंदुओं पर विरोधाभासी हो सकता है, और अन्य महत्वपूर्ण पायथन पुस्तकालय अपने प्रलेखन में अन्य परिभाषा का उपयोग कर सकते हैं।

यह पृष्ठ भी शब्द का उपयोग करता है Set mixin, जो स्पष्ट रूप से यह बताता है कि कक्षाएं Setऔर Iteratorमिक्सिन कक्षाएं कहला सकती हैं।

अन्य भाषाओं में

  • रूबी: स्पष्ट रूप से मिक्सिन के लिए कई वंशानुक्रम की आवश्यकता नहीं है, जैसा कि प्रमुख संदर्भ पुस्तकों में वर्णित है जैसे कि प्रोग्रामिंग रूबी और द रूब प्रोग्रामिंग भाषा

  • C ++: एक विधि जो कार्यान्वित नहीं की जाती है वह एक शुद्ध आभासी विधि है।

    परिभाषा 1 एक सार वर्ग (एक वर्ग जिसमें एक शुद्ध आभासी विधि है) की परिभाषा के साथ मेल खाता है। उस वर्ग को तत्काल नहीं किया जा सकता है।

    आभासी विरासत के साथ परिभाषा 2 संभव है: दो व्युत्पन्न वर्गों से एकाधिक वंशानुक्रम


37

मैं उन्हें कई वंशानुक्रम का उपयोग करने के एक अनुशासित तरीके के रूप में सोचता हूं - क्योंकि अंततः एक मिक्सिन सिर्फ एक और अजगर वर्ग है जो वर्गों के बारे में सम्मेलनों का पालन कर सकता है (जिन्हें मिक्सिन कहा जाता है)।

सम्मेलनों के बारे में मेरी समझ जो आपको कुछ मिलाकर बताती है, वह एक मिश्रण है:

  • तरीकों को जोड़ता है लेकिन उदाहरण चर नहीं (वर्ग स्थिरांक ठीक हैं)
  • केवल विरासत से object(पायथन में)

इस तरह यह कई उत्तराधिकार की संभावित जटिलता को सीमित करता है, और यह आपके कार्यक्रम के प्रवाह को सीमित करने को आसान बनाता है जहां आपको देखना है (पूर्ण एकाधिक विरासत की तुलना में)। वे रूबी मॉड्यूल के समान हैं ।

अगर मैं उदाहरण चर (एकल वंशानुक्रम के लिए अनुमति से अधिक लचीलेपन के साथ) जोड़ना चाहता हूं, तो मैं रचना के लिए जाना चाहता हूं।

ऐसा कहने के बाद, मैंने XYZMixin नाम की कक्षाएं देखीं, जिनके उदाहरण चर हैं।


30

मिक्सिंस प्रोग्रामिंग में एक अवधारणा है जिसमें कक्षा कार्यात्मकता प्रदान करती है लेकिन इसका उपयोग तात्कालिकता के लिए नहीं किया जाता है। मिक्सिंस का मुख्य उद्देश्य कार्यात्मकता प्रदान करना है जो स्टैंडअलोन हैं और यह सबसे अच्छा होगा यदि मिक्सिंस स्वयं अन्य मिश्रणों के साथ विरासत में नहीं होते हैं और राज्य से भी बचते हैं। रूबी जैसी भाषाओं में, कुछ प्रत्यक्ष भाषा समर्थन है लेकिन पायथन के लिए, वहाँ नहीं है। हालांकि, आप पायथन में प्रदान की गई कार्यक्षमता को निष्पादित करने के लिए बहु-श्रेणी की विरासत का उपयोग कर सकते हैं।

मैंने मिक्सिन्स की मूल बातें समझने के लिए यह वीडियो http://www.youtube.com/watch?v=v_uKI2NOLEM देखा । शुरुआती लोगों के लिए मिश्रणों की मूल बातें और वे कैसे काम करते हैं और उन्हें लागू करने में आपको किन समस्याओं का सामना करना पड़ता है, यह समझना काफी उपयोगी है।

विकिपीडिया अभी भी सबसे अच्छा है: http://en.wikipedia.org/wiki/Mixin


29

क्या एक मिश्रण को कई विरासत से अलग करता है? क्या यह सिर्फ शब्दार्थ की बात है?

एक मिश्रण कई वंशानुक्रम का एक सीमित रूप है। कुछ भाषाओं में एक वर्ग में मिक्सिन जोड़ने की व्यवस्था विरासत से थोड़ी अलग (वाक्य रचना के संदर्भ में) है।

विशेष रूप से पायथन के संदर्भ में, एक मिश्रण एक मूल वर्ग है जो उपवर्गों को कार्यक्षमता प्रदान करता है, लेकिन स्वयं को त्वरित बनाने का इरादा नहीं है।

आपको यह कहने के लिए क्या कारण हो सकता है, "यह सिर्फ एक ही विरासत है, वास्तव में एक मिश्रण नहीं है" यदि एक मिश्रण के लिए भ्रमित होने वाला वर्ग वास्तव में तात्कालिक और उपयोग किया जा सकता है - तो वास्तव में यह एक अर्थपूर्ण, और बहुत वास्तविक, अंतर है।

एकाधिक वंशानुक्रम का उदाहरण

यह उदाहरण, दस्तावेज़ीकरण से , एक ऑर्डरेड मुठभेड़ है:

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और उप-वर्ग को उपवर्गित करता है ।OrderedDictcollections

दोनों Counterऔर OrderedDictinstantiated और अपने दम पर इस्तेमाल किया जा करने का इरादा कर रहे हैं। हालांकि, उन दोनों को उपवर्गित करके, हमारे पास एक काउंटर हो सकता है जो आदेश दिया गया है और प्रत्येक ऑब्जेक्ट में कोड का पुन: उपयोग करता है।

यह कोड का पुन: उपयोग करने का एक शक्तिशाली तरीका है, लेकिन यह समस्याग्रस्त भी हो सकता है। अगर यह पता चला है कि वस्तुओं में से एक में एक बग है, तो देखभाल के बिना इसे ठीक करना उपवर्ग में बग बना सकता है।

एक मिक्सिन का उदाहरण

मिक्सिंस को आमतौर पर संभावित युग्मन मुद्दों के बिना कोड पुन: उपयोग करने के तरीके के रूप में प्रचारित किया जाता है, जो कि आदेशात्मक मुठभेड़ जैसे सहकारी बहु विरासत, हो सकता है। जब आप मिक्सिंस का उपयोग करते हैं, तो आप कार्यक्षमता का उपयोग करते हैं जो डेटा के साथ कसकर युग्मित नहीं है।

ऊपर दिए गए उदाहरण के विपरीत, एक मिक्सिन का उपयोग करने का इरादा नहीं है। यह नई या अलग कार्यक्षमता प्रदान करता है।

उदाहरण के लिए, मानक पुस्तकालय की एक जोड़ी है में mixins socketserverपुस्तकालय

इन मिक्स-इन कक्षाओं का उपयोग करके प्रत्येक प्रकार के सर्वर के फोर्किंग और थ्रेडिंग संस्करण बनाए जा सकते हैं। उदाहरण के लिए, थ्रेडिंगसपर्सवर निम्नानुसार बनाया गया है:

class ThreadingUDPServer(ThreadingMixIn, UDPServer):
    pass

मिक्स-इन क्लास पहले आता है, क्योंकि यह UDPServer में परिभाषित एक विधि को ओवरराइड करता है। विभिन्न विशेषताओं को सेट करना अंतर्निहित सर्वर तंत्र के व्यवहार को भी बदलता है।

इस स्थिति में, मिक्स्ड मेथड्स 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()

एक कंट्रास्टेड उदाहरण

यह एक मिश्रण है जो ज्यादातर प्रदर्शन के उद्देश्यों के लिए है - अधिकांश वस्तुएँ इस रीप्रोसेस की उपयोगिता से परे विकसित होंगी:

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)

11

मुझे लगता है कि यहां कुछ अच्छी व्याख्याएं हुई हैं लेकिन मैं एक और परिप्रेक्ष्य प्रदान करना चाहता था।

स्काला में, आप यहाँ वर्णित के रूप में मिश्रण कर सकते हैं, लेकिन जो बहुत ही दिलचस्प है वह यह है कि मिश्रण वास्तव में 'फ्यूज़्ड' होते हैं ताकि एक नई तरह की कक्षा बनाई जा सके। संक्षेप में, आप कई वर्गों / मिश्रणों से विरासत में नहीं मिलते हैं, बल्कि मिश्रण के सभी गुणों के साथ एक नई तरह की कक्षा उत्पन्न करते हैं। यह समझ में आता है क्योंकि स्काला JVM पर आधारित है, जहां कई-वंशानुक्रम वर्तमान में समर्थित नहीं हैं (जावा 8 के अनुसार)। यह मिक्सिन वर्ग प्रकार, वैसे, एक विशेष प्रकार है जिसे स्काला में एक विशेषता कहा जाता है।

यह उस तरह से संकेत दिया जाता है जिस तरह से एक वर्ग को परिभाषित किया जाता है: क्लास न्यूक्लास फर्स्टमिक्सिन को थर्डमिक्सिन के साथ सेकंडमिक्सिन के साथ विस्तारित करता है ...

मुझे यकीन नहीं है कि अगर CPython दुभाषिया समान (मिक्सिन वर्ग-रचना) करता है, लेकिन मुझे आश्चर्य नहीं होगा। इसके अलावा, एक C ++ बैकग्राउंड से आने पर, मैं एक ABC या 'इंटरफ़ेस' को मिक्सिन के बराबर नहीं कहूंगा - यह एक समान अवधारणा है लेकिन उपयोग और कार्यान्वयन में भिन्न है।


9

मैं नए पायथन कोड में मिक्स-इन के खिलाफ सलाह दूंगा, यदि आप इसके आसपास कोई अन्य तरीका पा सकते हैं (जैसे कि कंपोजीशन-इन-ऑफ-इनहेरिटेंस, या सिर्फ बंदर-पैचिंग विधियों को अपनी कक्षाओं में) जो बहुत अधिक नहीं है प्रयास है।

पुरानी शैली की कक्षाओं में आप मिक्स-इन का उपयोग दूसरी कक्षा के कुछ तरीकों को हथियाने के तरीके के रूप में कर सकते हैं। लेकिन नई शैली की दुनिया में सब कुछ, यहां तक ​​कि मिक्स-इन से भी विरासत में मिला है object। इसका मतलब है कि कई विरासत के किसी भी उपयोग स्वाभाविक रूप से एमआरओ मुद्दों का परिचय देते हैं

पायथन में बहु-विरासत एमआरओ काम करने के तरीके हैं, सबसे विशेष रूप से सुपर () फ़ंक्शन, लेकिन इसका मतलब है कि आपको सुपर () का उपयोग करके अपने पूरे वर्ग पदानुक्रम को करना होगा, और नियंत्रण के प्रवाह को समझना काफी मुश्किल है।


3
चूंकि संस्करण 2.3 पायथन ने पायथन 2.3 विधि संकल्प आदेश या विधि संकल्प आदेश में वर्णित "C3 विधि संकल्प" का उपयोग करता है ।
वेबवार्स्ट

11
निजी तौर पर, मैं ज्यादातर मामलों में बंदर-पैचिंग पर मिश्रण ले जाऊंगा; कोड के बारे में तर्क करना और उसका पालन करना आसान है।
tdammers

5
Downvoted। हालांकि आपका जवाब विकास शैलियों की एक मान्य राय व्यक्त करता है, आप वास्तव में वास्तविक प्रश्न को संबोधित नहीं करते हैं।
रयान बी। लिंच

8

शायद कुछ उदाहरणों से मदद मिलेगी।

यदि आप एक कक्षा का निर्माण कर रहे हैं और आप चाहते हैं कि यह एक शब्दकोश की तरह काम करे, तो आप सभी __ __आवश्यक विभिन्न तरीकों को परिभाषित कर सकते हैं । लेकिन यह थोड़ा सा दर्द है। एक विकल्प के रूप में, आप बस कुछ को परिभाषित कर सकते हैं, और इनहेरिट (किसी अन्य विरासत के अलावा) से UserDict.DictMixin( collections.DictMixinpy3k में स्थानांतरित) कर सकते हैं। यह बाकी सभी शब्दकोश एपीआई को स्वचालित रूप से परिभाषित करने का प्रभाव होगा।

एक दूसरा उदाहरण: जीयूआई टूलकिट wxPython आपको कई स्तंभों के साथ सूची नियंत्रण बनाने की अनुमति देता है (जैसे, कहते हैं, विंडोज एक्सप्लोरर में फ़ाइल डिस्प्ले)। डिफ़ॉल्ट रूप से, ये सूचियाँ काफी बुनियादी हैं। आप अतिरिक्त कार्यक्षमता जोड़ सकते हैं, जैसे कि किसी विशेष स्तंभ द्वारा सूची को सॉर्ट करने की क्षमता, स्तंभ शीर्षलेख पर क्लिक करके, लिस्टक्रैट से विरासत में मिला कर और उपयुक्त मिश्रणों को जोड़कर।


8

यह एक पायथन उदाहरण नहीं है , लेकिन डी प्रोग्रामिंग भाषा में इस शब्द mixinका उपयोग उसी तरह से उपयोग किए गए निर्माण को संदर्भित करने के लिए किया जाता है; एक वर्ग के लिए सामान का ढेर जोड़ना।

डी में (जिस तरह से एमआई नहीं करता है) यह एक टेम्पलेट सम्मिलित करके किया जाता है (लगता है कि वाक्यात्मक रूप से जागरूक और सुरक्षित मैक्रोज़ और आप करीब होंगे) एक दायरे में। यह एक वर्ग, संरचना, फ़ंक्शन, मॉड्यूल या जो भी घोषणाओं की किसी भी संख्या तक विस्तार करने के लिए कोड की एक पंक्ति की अनुमति देता है।


2
मिक्सिन एक सामान्य शब्द है, जिसका उपयोग डी, रूबी, आदि में किया जाता है। विकिपीडिया के अनुसार, वे पुराने स्कूल लिस्प सिस्टम में उत्पन्न हुए थे, और पहली बार 1983 में प्रलेखित किए गए थे: en.wikipedia.org/wiki/…
ली बी

7

ओपी ने उल्लेख किया कि उसने C ++ में मिक्सिन के बारे में कभी नहीं सुना, शायद ऐसा इसलिए है क्योंकि उन्हें C ++ में क्यूरिकली रिकरिंग टेम्प्लेट पैटर्न (CRTP) कहा जाता है। इसके अलावा, @Ciro Santilli ने उल्लेख किया कि मिक्स C ++ में सार बेस क्लास के माध्यम से लागू किया गया है। जबकि एब्सट्रैक्ट बेस क्लास का उपयोग मिक्सिन को लागू करने के लिए किया जा सकता है, यह एक ओवरकिल है क्योंकि रन-टाइम पर वर्चुअल फ़ंक्शन की कार्यक्षमता को रन-टाइम पर वर्चुअल टेबल लुकअप के ओवरहेड के बिना संकलित समय का उपयोग करके प्राप्त किया जा सकता है।

यहाँ CRTP पैटर्न का विस्तार से वर्णन किया गया है

मैंने @Ciro Santilli के जवाब में अजगर उदाहरण को C ++ में नीचे दिए गए टेम्प्लेट क्लास का उपयोग करके परिवर्तित किया है:

    #include <iostream>
    #include <assert.h>

    template <class T>
    class ComparableMixin {
    public:
        bool operator !=(ComparableMixin &other) {
            return ~(*static_cast<T*>(this) == static_cast<T&>(other));
        }
        bool operator <(ComparableMixin &other) {
            return ((*(this) != other) && (*static_cast<T*>(this) <= static_cast<T&>(other)));
        }
        bool operator >(ComparableMixin &other) {
            return ~(*static_cast<T*>(this) <= static_cast<T&>(other));
        }
        bool operator >=(ComparableMixin &other) {
            return ((*static_cast<T*>(this) == static_cast<T&>(other)) || (*(this) > other));
        }
        protected:
            ComparableMixin() {}
    };

    class Integer: public ComparableMixin<Integer> {
    public:
     Integer(int i) {
         this->i = i;
     }
     int i;
     bool operator <=(Integer &other) {
         return (this->i <= other.i);
     }
     bool operator ==(Integer &other) {
         return (this->i == other.i);
     }
    };

int main() {

    Integer i(0) ;
    Integer j(1) ;
    //ComparableMixin<Integer> c; // this will cause compilation error because constructor is protected.
    assert (i < j );
    assert (i != j);
    assert (j >  i);
    assert (j >= i);

    return 0;
}

संपादित करें: तुलनात्मकमिक्सिन में संरक्षित कंस्ट्रक्टर को जोड़ा गया ताकि यह केवल विरासत में मिले और तात्कालिक न हो। यह देखने के लिए कि कंस्ट्रक्टेबलमिक्सिन का कोई ऑब्जेक्ट कैसे बनाया जाता है, यह देखने के लिए कि संरक्षित कंस्ट्रक्टर त्रुटि संकलन का कारण कैसे बनेगा।


मिक्स और CRTP C ++ में समान रूप से नहीं हैं।
आश्र्वासुन

6

शायद माणिक से एक उदाहरण मदद कर सकता है:

आप मिक्सिन को शामिल कर सकते हैं Comparableऔर एक फ़ंक्शन को परिभाषित कर सकते हैं, मिक्सिन "<=>(other)"उन सभी कार्यों को प्रदान करता है:

<(other)
>(other)
==(other)
<=(other)
>=(other)
between?(other)

यह <=>(other)सही परिणाम को वापस लाने और देने के द्वारा करता है ।

"instance <=> other"रिटर्न 0 अगर दोनों ऑब्जेक्ट बराबर हैं, तो 0 से कम है अगर instanceबड़ा है otherऔर 0 से अधिक है तो otherबड़ा है।


यहाँ पायथन के लिए एक समान मिश्रण प्रदान करने वाली पोस्ट है। हालांकि यह सुझाव __lt__आधार के रूप में परिभाषित हो रहा है __cmp__, लेकिन बाद का उपयोग करने के लिए हतोत्साहित और हतोत्साहित किया जाता है। मेरे लिए यह काफी जटिल डेकोरेटर्स ( फंक्शंस के हिस्से ) के बजाय उस मिक्सिन का उपयोग करना आसान लगता है - हालांकि यह एक अधिक गतिशील रूप से प्रतिक्रिया करने में सक्षम हो सकता है जिस पर तुलना प्रदान की जाती है ...
टोबीस किंजलर

6

मिक्सिन एक वर्ग में कार्यक्षमता जोड़ने का एक तरीका देता है, अर्थात आप वांछित वर्ग के अंदर मॉड्यूल को शामिल करके मॉड्यूल में परिभाषित तरीकों के साथ बातचीत कर सकते हैं। हालांकि माणिक एकाधिक वंशानुक्रम का समर्थन नहीं करता है लेकिन इसे प्राप्त करने के विकल्प के रूप में मिक्सिन प्रदान करता है।

यहाँ एक उदाहरण है जो बताता है कि मिक्सिन का उपयोग करके कितने उत्तराधिकार प्राप्त किए जाते हैं।

module A    # you create a module
    def a1  # lets have a method 'a1' in it
    end
    def a2  # Another method 'a2'
    end
end

module B    # let's say we have another module
    def b1  # A method 'b1'
    end
    def b2  #another method b2
    end
end

class Sample    # we create a class 'Sample'
    include A   # including module 'A' in the class 'Sample' (mixin)
    include B   # including module B as well

    def S1      #class 'Sample' contains a method 's1'
    end
end

samp = Sample.new    # creating an instance object 'samp'

# we can access methods from module A and B in our class(power of mixin)

samp.a1     # accessing method 'a1' from module A
samp.a2     # accessing method 'a2' from module A
samp.b1     # accessing method 'b1' from module B
samp.b2     # accessing method 'a2' from module B
samp.s1     # accessing method 's1' inside the class Sample

4
सामान्य रूप से इस और कई वंशानुक्रम के बीच अंतर क्या है?
सिरो सेंटिल्ली 冠状 病毒 iro i 法轮功

अंतर यह है कि आप मॉड्यूल से उदाहरण बनाने में सक्षम नहीं हैं, लेकिन अगर सामान्य वर्गों और मॉड्यूल के बीच कोई अंतर नहीं है, तो मिश्रण स्पष्ट चीज नहीं है और यह समझना कठिन है कि सामान्य वर्ग कहां है और एक मिश्रण कहां है
ka8725

तो रूबी मिक्सिन्स में सिर्फ वे वर्ग होते हैं जिन्हें तात्कालिक नहीं किया जा सकता है लेकिन उनका उपयोग कई उत्तराधिकार के लिए किया जाना चाहिए?
त्रिशूल

6

मैंने सिर्फ अजगर मिल्टरों के लिए यूनिट परीक्षण को लागू करने के लिए एक अजगर मिश्रण का उपयोग किया। आम तौर पर, एक एमटीए के लिए एक मिलर बातचीत करता है, जिससे यूनिट परीक्षण मुश्किल हो जाता है। टेस्ट मिक्सिन उन तरीकों को ओवरराइड करता है जो एमटीए से बात करते हैं, और इसके बजाय परीक्षण मामलों द्वारा संचालित एक नकली वातावरण बनाते हैं।

तो, आप एक अनफ़िल्टर्ड माइलेज एप्लिकेशन लेते हैं, जैसे कि spfmilter और मिक्सिन टेस्टबेस, जैसे:

class TestMilter(TestBase,spfmilter.spfMilter):
  def __init__(self):
    TestBase.__init__(self)
    spfmilter.config = spfmilter.Config()
    spfmilter.config.access_file = 'test/access.db'
    spfmilter.spfMilter.__init__(self)

फिर, परीक्षण आवेदन के लिए परीक्षण मामलों में TestMilter का उपयोग करें:

def testPass(self):
  milter = TestMilter()
  rc = milter.connect('mail.example.com',ip='192.0.2.1')
  self.assertEqual(rc,Milter.CONTINUE)
  rc = milter.feedMsg('test1',sender='good@example.com')
  self.assertEqual(rc,Milter.CONTINUE)
  milter.close()

http://pymilter.cvs.sourceforge.net/viewvc/pymilter/pymilter/Milter/test.py?revision=1.6&view=markup


4

मुझे लगता है कि पिछली प्रतिक्रियाएं बहुत अच्छी तरह से परिभाषित हैं कि मिक्सआईन्स क्या हैं। हालांकि, के लिए उन्हें बेहतर समझते हैं, यह उपयोगी तुलना करने के लिए हो सकता है mixins साथ सार वर्गों और इंटरफेस कोड / कार्यान्वयन के नजरिए से:

1. सार वर्ग

  • कक्षा जिसमें एक या एक से अधिक सार विधियाँ होनी चाहिए

  • सार कक्षा कर सकते हैं राज्य (उदाहरण के चर) और गैर-सार पद्धतियां हैं

2. इंटरफ़ेस

  • इंटरफ़ेस में केवल सार विधियाँ हैं (कोई गैर-सार विधियाँ और कोई आंतरिक स्थिति नहीं)

3. मिक्सआईन्स

  • MixIns (जैसे इंटरफेस) में आंतरिक स्थिति (उदाहरण के चर) नहीं होते हैं
  • मिक्सआईन्स में एक या अधिक गैर-अमूर्त विधियां होती हैं (वे इंटरफेस के विपरीत गैर-अमूर्त विधियां शामिल कर सकते हैं)

उदाहरण के लिए पायथन में ये सिर्फ कन्वेंशन हैं, क्योंकि उपरोक्त सभी को परिभाषित किया गया है class। हालांकि, दोनों की आम सुविधा सार कक्षाएं, इंटरफेस और mixins है कि वे है नहीं करना चाहिए अपने दम पर मौजूद हैं, यानी instantiated नहीं किया जाना चाहिए।


3

मैंने पढ़ा कि आपके पास एसी # बैकग्राउंड है। तो एक अच्छा प्रारंभिक बिंदु .NET के लिए एक मिश्रण कार्यान्वयन हो सकता है।

आप कोडप्लेक्स प्रोजेक्ट को देखना चाहेंगे http://remix.codeplex.com/ ।

अवलोकन प्राप्त करने के लिए lang.net सिम्पोजियम लिंक देखें। अभी भी कोडप्लेक्स पेज पर प्रलेखन पर आना बाकी है।

स्टेफन का संबंध है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.