python बेस क्लास को व्युत्पन्न वर्ग पायथन(या कक्षाओं को विस्तारित करने का अधिक पायथनिक तरीका)




inheritance derived-class (5)

यदि आप केवल व्यवहार जोड़ रहे हैं, और अतिरिक्त आवृत्ति मानों के आधार पर नहीं, तो आप ऑब्जेक्ट के __class__ को असाइन कर सकते हैं:

from math import pi

class Circle(object):
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return pi * self.radius**2

class CirclePlus(Circle):
    def diameter(self):
        return self.radius*2

    def circumference(self):
        return self.radius*2*pi

c = Circle(10)
print c.radius
print c.area()
print repr(c)

c.__class__ = CirclePlus
print c.diameter()
print c.circumference()
print repr(c)

प्रिंटों:

10
314.159265359
<__main__.Circle object at 0x00A0E270>
20
62.8318530718
<__main__.CirclePlus object at 0x00A0E270>

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

मुझे नेटवर्कक्स पायथन पैकेज का विस्तार करने और मेरी विशेष आवश्यकता के लिए Graph क्लास में कुछ विधियां जोड़ने की आवश्यकता है

जिस तरह से मैंने ऐसा करने के बारे में सोचा था, वह एक नई कक्षा को NewGraph कहता है, और आवश्यक विधियों को जोड़ रहा है।

हालांकि नेटवर्कक्स में कई अन्य फ़ंक्शन हैं जो Graph ऑब्जेक्ट्स बनाते हैं और लौटाते हैं (उदाहरण के लिए एक यादृच्छिक ग्राफ उत्पन्न करें)। अब मुझे इन Graph ऑब्जेक्ट्स को NewGraph ऑब्जेक्ट्स में NewGraph है ताकि मैं अपने नए तरीकों का उपयोग कर NewGraph

ऐसा करने का सबसे अच्छा तरीका क्या है? या क्या मुझे समस्या को पूरी तरह से अलग तरीके से निपटाना चाहिए?


आप Graph ऑब्जेक्ट से व्युत्पन्न एक नया NewGraph बना सकते हैं और __init__ फ़ंक्शन में अपनी खुद की गुणों को परिभाषित करने से पहले, पहले पंक्ति के रूप में self.__dict__.update(vars(incoming_graph)) हैं। इस तरह आप मूल रूप से Graph से व्युत्पन्न Graph से सभी गुणों की प्रतिलिपि बनाते हैं, लेकिन आपके विशेष सॉस के साथ।

class NewGraph(Graph):
  def __init__(self, incoming_graph):
    self.__dict__.update(vars(incoming_graph))

    # rest of my __init__ code, including properties and such

उपयोग:

graph = function_that_returns_graph()
new_graph = NewGraph(graph)
cool_result = function_that_takes_new_graph(new_graph)

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

import networkx as nx

class NewGraph(nx.Graph):
    def __getattribute__(self, attr):
        "This is just to show off, not needed"
        print "getattribute %s" % (attr,)
        return nx.Graph.__getattribute__(self, attr)

    def __setattr__(self, attr, value):
        "More showing off."
        print "    setattr %s = %r" % (attr, value)
        return nx.Graph.__setattr__(self, attr, value)

    def plot(self):
        "A convenience method"
        import matplotlib.pyplot as plt
        nx.draw(self)
        plt.show()

अभी तक यह सामान्य सबक्लासिंग की तरह है। अब हमें इस networkx को networkx मॉड्यूल में हुक करने की आवश्यकता है ताकि networkx सभी nx.Graph परिणामस्वरूप NewGraph ऑब्जेक्ट में परिणाम हो। यहां सामान्य रूप से ऐसा होता है जब आप nx.Graph ऑब्जेक्ट को nx.Graph() साथ तत्काल करते हैं

1. nx.Graph.__new__(nx.Graph) is called
2. If the returned object is a subclass of nx.Graph, 
   __init__ is called on the object
3. The object is returned as the instance

हम nx.Graph.__new__ को प्रतिस्थापित करेंगे और इसे इसके बजाय NewGraph वापस कर NewGraph । इसमें, हम __new__ की __new__ विधि की बजाय object की __new__ विधि को NewGraph , क्योंकि उत्तरार्द्ध उस विधि को कॉल करने का एक और तरीका है जिसे हम बदल रहे हैं, और इसलिए परिणामस्वरूप अंतहीन रिकर्सन होगा।

def __new__(cls):
    if cls == nx.Graph:
        return object.__new__(NewGraph)
    return object.__new__(cls)

# We substitute the __new__ method of the nx.Graph class
# with our own.     
nx.Graph.__new__ = staticmethod(__new__)

# Test if it works
graph = nx.generators.random_graphs.fast_gnp_random_graph(7, 0.6)
graph.plot()

ज्यादातर मामलों में आपको यह जानने की ज़रूरत है, लेकिन एक गोचा है। __new__ विधि का हमारा ओवरराइडिंग केवल nx.Graph प्रभावित करता है, न कि इसके उप-वर्ग। उदाहरण के लिए, यदि आप nx.gn_graph कॉल nx.gn_graph , जो nx.gn_graph का उदाहरण देता है, तो इसमें हमारे किसी भी फैंसी एक्सटेंशन नहीं होंगे। आपको nx.Graph प्रत्येक उप-वर्ग को उप-वर्ग करने की nx.Graph जिसे आप साथ काम करना चाहते हैं और अपनी आवश्यक विधियों और विशेषताओं को जोड़ना चाहते हैं। mix-ins का उपयोग करके DRY सिद्धांत का पालन करते समय लगातार उप-वर्गों का विस्तार करना आसान हो सकता है।

यद्यपि यह उदाहरण काफी सरल प्रतीत हो सकता है, मॉड्यूल में हुक करने की यह विधि सामान्य रूप से सामान्यीकृत करना मुश्किल है जो फसल उगाने वाली सभी छोटी समस्याओं को शामिल करती है। मेरा मानना ​​है कि इसे हाथ में समस्या के अनुरूप बनाना आसान है। उदाहरण के लिए, यदि आप जिस श्रेणी में हुकिंग कर रहे हैं, वह अपनी कस्टम __new__ विधि को परिभाषित करता है, तो आपको इसे बदलने से पहले इसे स्टोर करना होगा, और object.__new__ बजाय इस विधि को कॉल करना होगा object.__new__


क्या आपने लोगों ने [पायथन] कास्ट क्लास क्लास को व्युत्पन्न कक्षा में करने की कोशिश की है

मैंने इसका परीक्षण किया है, और ऐसा लगता है कि यह काम करता है। साथ ही मुझे लगता है कि यह विधि नीचे से बेहतर है क्योंकि नीचे से व्युत्पन्न फ़ंक्शन के इनिट फ़ंक्शन निष्पादित नहीं करता है।

c.__class__ = CirclePlus

यदि कोई फ़ंक्शन ग्राफ़ ऑब्जेक्ट्स बना रहा है, तो आप उन्हें न्यूग्राफ ऑब्जेक्ट्स में नहीं बदल सकते हैं।

ग्राफ़ होने के बजाए न्यूग्राफ के पास ग्राफ का एक और विकल्प है। आप ग्राफ ऑब्जेक्ट्स को ग्राफ़ ऑब्जेक्ट में प्रतिनिधि करते हैं, और आप किसी भी ग्राफ ऑब्जेक्ट को एक नए न्यूग्राफ ऑब्जेक्ट में लपेट सकते हैं:

class NewGraph:
    def __init__(self, graph):
        self.graph = graph

    def some_graph_method(self, *args, **kwargs):
        return self.graph.some_graph_method(*args, **kwargs)
    #.. do this for the other Graph methods you need

    def my_newgraph_method(self):
        ....




base-class