2012-03-09 15 views
29

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

+0

आप एक आधार वर्ग में कुछ मुख्य कार्यक्षमता रख सकते हैं? –

+5

वाक्यांश "बड़ी कक्षा" और "ऑब्जेक्ट उन्मुख डिजाइन परिप्रेक्ष्य से एकल वर्ग" एक साथ बहुत अच्छी तरह से नहीं जाते हैं। –

+0

@ निकलास, इस बात पर सहमत हुए कि वे आम तौर पर कभी-कभी नहीं करते हैं। मेरी अधिकांश कक्षाएं बहुत छोटी हैं। –

उत्तर

33

यदि आपकी समस्या वास्तव में एक संपादक में एक बड़ी कक्षा के साथ काम कर रही है, तो पहला समाधान जो मैं वास्तव में देखता हूं वह समस्या को तोड़ने का एक बेहतर तरीका है। दूसरा समाधान एक बेहतर संपादक होगा, अधिमानतः एक कोड फोल्डिंग के साथ।

उस ने कहा, आप कई फाइलों में कक्षा को तोड़ने के कुछ तरीके हैं। पाइथन आपको __init__.py डालकर मॉड्यूल के रूप में फ़ोल्डर का उपयोग करने देता है, जो तब अन्य फ़ाइलों से चीजें आयात कर सकता है। हम प्रत्येक समाधान में इस क्षमता का उपयोग करेंगे। पहले कहें, bigclass नामक एक फ़ोल्डर बनाएं।

  1. फ़ोल्डर में विभिन्न .py फ़ाइलों है कि अंततः अपने वर्ग शामिल होंगे डाल दिया। प्रत्येक में अंतिम कक्षा, कक्षाओं के लिए कार्य और चर परिभाषाएं होनी चाहिए। __init__.py में एक ही फ़ोल्डर में सभी को एक साथ जोड़ने के लिए निम्नलिखित लिखें।

    class Bigclass(object): 
    
        from classdef1 import foo, bar, baz, quux 
        from classdef2 import thing1, thing2 
        from classdef3 import magic, moremagic 
        # unfortunately, "from classdefn import *" is an error or warning 
    
        num = 42 # add more members here if you like 
    

    यह लाभ यह है कि आप एक ही वर्ग object से ली हुई है, जो आपके विरासत रेखांकन में अच्छा लगेगा के साथ खत्म हो गया है।

  2. आप अपनी कक्षा के विभिन्न हिस्सों को गठबंधन करने के लिए एकाधिक विरासत का उपयोग कर सकते हैं। अपने व्यक्तिगत मॉड्यूल में आप कक्षा के कुछ हिस्सों के साथ Bigclass के लिए कक्षा परिभाषा लिखेंगे। फिर अपने __init__.py लिखने में:

    import classdef1, classdef2, classdef3 
    
    class Bigclass(classdef1.Bigclass, classdef2.Bigclass, classdef3.Bigclass): 
        num = 42 # add more members if desired 
    
  3. एकाधिक वंशानुक्रम एक मुद्दा बन जाता है, तो आप कर सकते हैं उपयोग एकल विरासत: सिर्फ श्रृंखला फैशन में एक दूसरे से प्रत्येक वर्ग इनहेरिट की है। मान लीजिए कि आप एक से अधिक कक्षा में कुछ भी परिभाषित नहीं करते हैं, आदेश कोई फर्क नहीं पड़ता।

    import classdef1 
    class Bigclass(classdef1.Bigclass): 
        # more member defs here 
    

    classdef3classdef2 से Bigclass आयात और इसे करने के लिए जोड़ना होगा, और इतने पर: उदाहरण के लिए, classdef2.py जैसा होगा। आपका __init__.py अभी पिछले एक आयात होगा:

    from classdef42 import Bigclass 
    

मैं आम तौर पर पसंद करते हैं # 1, क्योंकि यह क्या सदस्यों को आप से जो फ़ाइलें लेकिन इन समाधानों में से किसी भी आप के लिए काम कर सकता था आयात कर रहे हैं के बारे में अधिक स्पष्ट है।

मॉड्यूल नाम के रूप में फ़ोल्डर नाम का उपयोग कर इन परिदृश्यों आप इसे आयात कर सकते हैं में से किसी में वर्ग का उपयोग करने के लिए,: from bigclass import Bigclass

+0

+1: मेरे उत्तर के समान ही उतना ही अधिक सुरुचिपूर्ण। – obmarg

+1

+1 मुझे आपके विकल्पों में से पहला सबसे अच्छा अब तक उल्लिखित किसी भी तरह का सबसे अच्छा पसंद है। – wberry

+0

इस उत्तर को समाधान के रूप में चिह्नित करना क्योंकि अन्य उत्तरों सुझाव देते हैं कि * आमतौर पर * एक बड़ी कक्षा वास्तव में एक वर्ग नहीं होनी चाहिए। लेकिन मैं यह मानता हूं कि वे मौलिक रूप से होते हैं और यह उत्तर स्थिति से निपटने के लिए कुछ व्यावहारिक तरीकों की पेशकश करता है। –

2

मैं इसे इस्तेमाल नहीं किया है, लेकिन this package called partial दावों आंशिक वर्गों के लिए समर्थन जोड़ने के लिए।

ऐसा लगता है जैसे कुछ अन्य तरीके आप स्वयं इस रूप में अच्छी तरह लागू कर सकता है।

आप के अलग अलग हिस्सों को लागू कर सकता है अलग फ़ाइलों में मिश्रित के रूप में कक्षा, फिर उन्हें कहीं भी आयात करें और उन्हें उपclass।

परिवर्तन मूल रूप से, आप किसी केंद्रीय फ़ाइल में कहीं भी अपनी कक्षा के प्रत्येक तरीके को कार्यान्वित कर सकते हैं और उन्हें ऑब्जेक्ट आयात करने के लिए उन्हें कक्षा में विशेषताओं के रूप में असाइन कर सकते हैं। इसलिए जैसा:

a.py:

def AFunc(self, something): 
    # Do something 
    pass 

b.py:

def BFunc(self, something): 
    # Do something else 
    pass 

c.py:

import a, b 

class C: 
    AFunc = a.AFunc 
    BFunc = b.BFunc 

तुम भी अब तक इस स्वचालित करने के लिए के रूप में जा सकते हैं यदि आप वास्तव में चाहते थे तो प्रक्रिया - मॉड्यूल a और b द्वारा प्रदान किए गए सभी कार्यों के माध्यम से लूप करें और फिर जोड़ें C पर विशेषताओं के रूप में एम। हालांकि यह कुल ओवरकिल हो सकता है।

इसके बारे में जाने के लिए अन्य (संभवतः बेहतर) तरीके हो सकते हैं, लेकिन वे 2 हैं जो दिमाग में चले गए हैं।

7

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

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

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

+0

+1: आईएमएचओ, यह बहुत समझदार सलाह है। –

+0

मैं मानता हूं कि आम तौर पर एक बड़ी कक्षा से पता चलता है कि इसे एक से अधिक ज़िम्मेदारी मिली है और नहीं चाहिए।हालांकि, वे होते हैं (यहां तक ​​कि सर्वोत्तम प्रथाओं का पालन भी)। –

+0

वास्तव में वे करते हैं। मैंने हाल ही में तर्कसंगत अंकगणितीय के लिए लिखा है कि 362 लाइनें हैं, जिनमें लंबे डॉकस्ट्रिंग शामिल हैं, सभी खाली लाइनें छीन ली गई हैं। हालांकि मेरे पास '_' से शुरू होने वाले नामों के साथ कुछ '@ staticmethod' है, जो मेरी अपनी सलाह से शायद कार्यों के रूप में बाहर ले जाया जाना चाहिए। इससे लंबाई लगभग आधा हो जाएगी। – wberry

-1

सबसे पहले मैं यह कहना चाहता हूं कि यह जटिल है कि यह संभवतः क्लास में अपना स्थान ढूंढने के लिए एक अच्छा विचार नहीं है - टिप्पणियां जोड़ने, अनुभागों को हाइलाइट करना सबसे अच्छा होगा।

  1. कई फ़ाइलों में वर्ग लिखें उन्हें पाठ के रूप में पढ़ा तो, उन्हें और exec जिसके परिणामस्वरूप स्ट्रिंग श्रेणीबद्ध: हालांकि, मैं दो तरीकों से ऐसा कर सकता है देखते हैं।

  2. प्रत्येक फ़ाइल में एक अलग वर्ग बनाएं, फिर उन्हें सभी को मास्टर श्रेणी में मिश्रित के रूप में प्राप्त करें। हालांकि, अगर आप पहले से ही किसी अन्य वर्ग को उप-वर्गीकृत कर रहे हैं तो इससे एमआरओ समस्याएं हो सकती हैं। आप अपने मास्टर क्लास के लिए मेटाक्लास बनाकर इसे प्राप्त कर सकते हैं जो मैन्युअल रूप से एमआरओ को हल करता है, लेकिन यह गन्दा हो सकता है।

सबसे आसान विकल्प पहला विकल्प होगा।

+3

'exec' से सावधान रहें। आपको नेमस्पेस की आपूर्ति करनी होगी कि कोड को "इन" निष्पादित करना चाहिए। सुरक्षा जोखिम, आदि – wberry

+0

+1 अच्छी टिप्पणी। – aquavitae

5

मैं पहले कुछ इसी तरह के साथ चारों ओर toyed है। मेरा उपयोगकेस एक अमूर्त वाक्यविन्यास पेड़ में नोड्स का एक वर्ग पदानुक्रम था, और फिर मैं सभी उदा। prettyprinting फ़ंक्शंस एक अलग prettyprint.py फ़ाइल में है लेकिन अभी भी उन्हें कक्षाओं में विधियों के रूप में है।

एक चीज जिसकी मैंने कोशिश की थी वह एक सजावट का उपयोग करना था जो सजाए गए कार्य को निर्दिष्ट कक्षा पर एक विशेषता के रूप में रखता था। मेरे मामले में इसका मतलब यह होगा कि prettyprint.py अलग @inclass(...)

इस के साथ एक समस्या यह है कि एक यकीन है कि उप फ़ाइलें हमेशा आयात किए जाते हैं बनाना चाहिए है के साथ सजाया def prettyprint(self) सभी के बहुत सारे शामिल है, और है कि वे मुख्य वर्ग पर निर्भर करते हैं, जो एक परिपत्र निर्भरता के लिए बनाता है, जो गन्दा हो सकता है।

def inclass(kls): 
    """ 
    Decorator that adds the decorated function 
    as a method in specified class 
    """ 
    def _(func): 
     setattr(kls,func.__name__, func) 
     return func 
    return _ 

## exampe usage 
class C: 
    def __init__(self, d): 
     self.d = d 

# this would be in a separate file. 
@inclass(C) 
def meth(self, a): 
    """Some method""" 
    print "attribute: %s - argument: %s" % (self.d, a) 

i = C(10) 
print i.meth.__doc__ 
i.meth(20) 
+0

वाह, विधियों के लिए एक भेजने के लिए! – wberry

0

सबसे पहले, मुझे नहीं लगता कि कक्षा को कई फाइलों में विभाजित करने से कोई संपादन आसान हो जाता है। एक सभ्य आईडीई किसी भी विधि को आसानी से ढूंढने में सक्षम होना चाहिए चाहे एक फ़ाइल या एकाधिक में; यदि आप एक सभ्य आईडीई का उपयोग नहीं कर रहे हैं, तो क्लास को विभाजित करने का अर्थ है कि रखरखावकर्ता को अनुमान लगाया जाना चाहिए कि कौन सी फ़ाइल दी गई विधि है, जो आसान के बजाय कठिन लगती है।

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

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

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

3

तुम इतनी तरह सज्जाकार के साथ ऐसा कर सकते हैं:

class Car(object): 

    def start(self): 
    print 'Car has started' 


def extends(klass): 
    def decorator(func): 
     setattr(klass, func.__name__, func) 
     return func 
    return decorator 

#this can go in a different module/file 
@extends(Car) 
def do_start(self): 
    self.start() 


#so can this 
car = Car() 
car.do_start() 

#=> Car has started 
संबंधित मुद्दे