मुझे पायथन में कक्षाओं का उपयोग कब करना चाहिए?


177

मैं लगभग दो साल से अजगर में प्रोग्रामिंग कर रहा हूं; ज्यादातर डेटा सामान (पांडा, एमपीएल, सुपी), लेकिन स्वचालन स्क्रिप्ट और छोटे वेब ऐप भी। मैं एक बेहतर प्रोग्रामर बनने की कोशिश कर रहा हूं और अपने अजगर के ज्ञान को बढ़ाता हूं और एक चीज जो मुझे परेशान करती है वह यह है कि मैंने कभी भी क्लास का इस्तेमाल नहीं किया है (छोटे वेब ऐप्स के लिए रैंडम फ्लास्क कोड कॉपी करने के बाहर)। मैं आम तौर पर समझता हूं कि वे क्या हैं, लेकिन मैं अपने सिर को चारों ओर लपेटने के लिए प्रतीत नहीं हो सकता है कि मुझे एक साधारण समारोह में उनकी आवश्यकता क्यों होगी।

अपने प्रश्न में विशिष्टता जोड़ने के लिए: मैं कई स्वचालित डेटा स्रोतों (जिसमें मोंगो, एसक्यूएल, पोस्टग्रेज, एपिस) से डेटा खींचने वाली स्वचालित रिपोर्टें लिखता हूं, बहुत अधिक या थोड़ा डाटा मूंगिंग और फॉर्मेट करना, डेटा को सीएसवी / एक्सेल में लिखना। / html, इसे ईमेल में भेजें। स्क्रिप्ट ~ 250 लाइनों से ~ 600 लाइनों तक होती है। क्या मेरे पास ऐसा करने के लिए कक्षाओं का उपयोग करने का कोई कारण होगा और क्यों?


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

जवाबों:


133

कक्षाएं ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग के स्तंभ हैं । OOP कोड संगठन, पुन: प्रयोज्यता और इनकैप्सुलेशन के साथ अत्यधिक चिंतित है।

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

हालाँकि, OOP का उपयोग करने के कई कारण हैं।

कुछ कारणों से:

  • संगठन: OOP कोड में डेटा और प्रक्रिया दोनों का वर्णन और परिभाषित करने के अच्छी तरह से ज्ञात और मानक तरीकों को परिभाषित करता है। डेटा और प्रक्रिया दोनों को परिभाषा के विभिन्न स्तरों (विभिन्न वर्गों में) में संग्रहीत किया जा सकता है, और इन परिभाषाओं के बारे में बात करने के मानक तरीके हैं। यही है, यदि आप एक मानक तरीके से OOP का उपयोग करते हैं, तो यह आपके बाद के स्वयं और दूसरों को आपके कोड को समझने, संपादित करने और उपयोग करने में मदद करेगा। इसके अलावा, एक जटिल, मनमाने ढंग से डेटा स्टोरेज मैकेनिज्म (डिकट्स या लिस्ट या डाइक या सेट के डाइक की लिस्ट या जो भी हो) का उपयोग करने के बजाय, आप डेटा संरचनाओं के टुकड़ों का नाम दे सकते हैं और आसानी से उनका उल्लेख कर सकते हैं।

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

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

  • इनहेरिटेंस : इनहेरिटेंस आपको डेटा और प्रक्रिया को एक स्थान पर (एक वर्ग में) परिभाषित करने की अनुमति देता है, और फिर बाद में उस कार्यक्षमता को ओवरराइड या विस्तारित करता है। उदाहरण के लिए, पायथन में, मैं अक्सर लोगों dictको अतिरिक्त कार्यक्षमता जोड़ने के लिए कक्षा के उप- वर्ग बनाने के लिए देखता हूं । एक सामान्य परिवर्तन उस विधि को ओवरराइड कर रहा है जो एक अपवाद को फेंक देता है जब एक कुंजी को एक शब्दकोश से अनुरोध किया जाता है जो एक अज्ञात कुंजी के आधार पर डिफ़ॉल्ट मान देने के लिए मौजूद नहीं है। यह आपको अपने स्वयं के कोड को अभी या बाद में विस्तारित करने की अनुमति देता है, दूसरों को आपके कोड का विस्तार करने की अनुमति देता है, और आपको अन्य लोगों के कोड का विस्तार करने की अनुमति देता है।

  • पुन: प्रयोज्य: इन सभी कारणों और दूसरों के लिए कोड की अधिक पुन: प्रयोज्य की अनुमति है। ऑब्जेक्ट ओरिएंटेड कोड आपको एक बार ठोस (परीक्षण) कोड लिखने की अनुमति देता है, और फिर से अधिक से अधिक पुन: उपयोग करता है। यदि आपको अपने विशिष्ट उपयोग के मामले के लिए कुछ ट्वीस्ट करने की आवश्यकता है, तो आप एक मौजूदा वर्ग से वारिस कर सकते हैं और मौजूदा व्यवहार को ओवरराइट कर सकते हैं। यदि आपको कुछ बदलने की आवश्यकता है, तो आप मौजूदा सार्वजनिक विधि हस्ताक्षर को बनाए रखते हुए इसे बदल सकते हैं, और कोई भी समझदार (उम्मीद) नहीं है।

फिर, OOP का उपयोग न करने के कई कारण हैं, और आपको इसकी आवश्यकता नहीं है। लेकिन सौभाग्य से पायथन जैसी भाषा के साथ, आप बस थोड़ा सा या बहुत उपयोग कर सकते हैं, यह आपके ऊपर है।

छात्र उपयोग के मामले का उदाहरण (कोड गुणवत्ता पर कोई गारंटी नहीं, सिर्फ एक उदाहरण):

वस्तु के उन्मुख

class Student(object):
    def __init__(self, name, age, gender, level, grades=None):
        self.name = name
        self.age = age
        self.gender = gender
        self.level = level
        self.grades = grades or {}

    def setGrade(self, course, grade):
        self.grades[course] = grade

    def getGrade(self, course):
        return self.grades[course]

    def getGPA(self):
        return sum(self.grades.values())/len(self.grades)

# Define some students
john = Student("John", 12, "male", 6, {"math":3.3})
jane = Student("Jane", 12, "female", 6, {"math":3.5})

# Now we can get to the grades easily
print(john.getGPA())
print(jane.getGPA())

स्टैंडर्ड डिक्ट

def calculateGPA(gradeDict):
    return sum(gradeDict.values())/len(gradeDict)

students = {}
# We can set the keys to variables so we might minimize typos
name, age, gender, level, grades = "name", "age", "gender", "level", "grades"
john, jane = "john", "jane"
math = "math"
students[john] = {}
students[john][age] = 12
students[john][gender] = "male"
students[john][level] = 6
students[john][grades] = {math:3.3}

students[jane] = {}
students[jane][age] = 12
students[jane][gender] = "female"
students[jane][level] = 6
students[jane][grades] = {math:3.5}

# At this point, we need to remember who the students are and where the grades are stored. Not a huge deal, but avoided by OOP.
print(calculateGPA(students[john][grades]))
print(calculateGPA(students[jane][grades]))

"उपज" के कारण अजगर एन्कैप्सुलेशन अक्सर कक्षाओं के साथ जनरेटर और संदर्भ प्रबंधकों के साथ क्लीनर है।
दिमित्री रुबानोविच

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

5
@ मीटर भी, एनकैप्सुलेशन के एक उदाहरण के रूप में: मान लीजिए कि आज यह कार्यान्वयन ठीक है क्योंकि मुझे केवल एक बार एक टर्म में अपने विश्वविद्यालय में 50,000 छात्रों के लिए जीपीए प्राप्त करने की आवश्यकता है। अब कल हमें एक अनुदान मिलेगा और हर छात्र को हर सेकंड का वर्तमान जीपीए देने की जरूरत है (बेशक, कोई भी इसके लिए नहीं पूछेगा, लेकिन सिर्फ इसे कम्प्यूटेशनल रूप से चुनौतीपूर्ण बनाने के लिए)। हम तब GPA को "याद" कर सकते हैं और केवल तभी गणना कर सकते हैं जब यह बदलता है (उदाहरण के लिए, सेटग्रैड विधि में एक चर सेट करके), अन्य एक कैश्ड संस्करण लौटाते हैं। उपयोगकर्ता अभी भी getGPA () का उपयोग करता है, लेकिन कार्यान्वयन बदल गया है।
डैंटिस्टन

4
@ डेंटिस्टन, इस उदाहरण के संग्रह की जरूरत है। आप एक नया प्रकार छात्र बना सकते हैं = संग्रह.नामलोक ("छात्र", "नाम, आयु, लिंग, स्तर, ग्रेड")। और फिर आप उदाहरण बना सकते हैं जॉन = छात्र ("जॉन", 12, "पुरुष", ग्रेड = {'गणित': 3.5}, स्तर = 6)। ध्यान दें कि आप एक कक्षा बनाने के साथ ही स्थिति और नामित तर्क दोनों का उपयोग करते हैं। यह एक डेटा प्रकार है जो पहले से ही आपके लिए पायथन में लागू है। फिर आप ट्यूल का पहला तत्व प्राप्त करने के लिए john [0] या john.name का उल्लेख कर सकते हैं। आप जॉन के ग्रेड को john.grades.values ​​() के रूप में प्राप्त कर सकते हैं। और यह पहले से ही आपके लिए किया गया है।
दिमित्री रुबनोविच

2
मेरे लिए एनकैप्सुलेशन हमेशा ओओपी का उपयोग करने का एक अच्छा पर्याप्त कारण है। मैं यह देखने के लिए संघर्ष करता हूं कि किसी भी आकार के कोडिंग प्रोजेक्ट के लिए OOP का उपयोग नहीं किया गया है। मुझे लगता है कि मुझे उल्टे सवाल के जवाब की जरूरत है :)
सैन जे।

23

जब भी आपको अपने कार्यों की स्थिति को बनाए रखने की आवश्यकता होती है और यह जनरेटर के साथ पूरा नहीं किया जा सकता है (ऐसे कार्य जो रिटर्न के बजाय उपज देते हैं)। जनरेटर अपना राज्य बनाए रखते हैं।

यदि आप किसी भी मानक को ओवरराइड करना चाहते हैं ऑपरेटर , तो आपको एक वर्ग की आवश्यकता है।

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

यदि आप "पायथोनिक" कोड लिखना चाहते हैं, तो आपको कक्षाओं में संदर्भ प्रबंधकों और जनरेटर को प्राथमिकता देना चाहिए। यह क्लीनर होगा।

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

प्रत्येक नियम के रूप में, इसका एक अपवाद है। यदि आप कार्यक्षमता को जल्दी से एनकोड करना चाहते हैं (यानी, लाइब्रेरी-स्तरीय पुन: प्रयोज्य कोड के बजाय परीक्षण कोड लिखें), तो आप राज्य को एक कक्षा में इनकैप कर सकते हैं। यह सरल होगा और पुन: प्रयोज्य होने की आवश्यकता नहीं होगी।

यदि आपको C ++ स्टाइल डिस्ट्रक्टर (RIIA) की आवश्यकता है, तो आप निश्चित रूप से कक्षाओं का उपयोग नहीं करना चाहते हैं। आप संदर्भ प्रबंधक चाहते हैं।


1
@DmitryRubanovich क्लोजर पायथन में जनरेटर के माध्यम से लागू नहीं किया जाता है।
एली कोरविगो

1
@DmitryRubanovich मैं "बंद को पायथन में जनरेटर के रूप में लागू किया जाता है" का उल्लेख कर रहा था, जो सच नहीं है। क्लोजर कहीं अधिक लचीले होते हैं। जेनरेटर एक Generatorउदाहरण (एक विशेष पुनरावृत्त) वापस करने के लिए बाध्य हैं , जबकि बंद होने पर कोई भी हस्ताक्षर हो सकता है। आप मूल रूप से क्लोजर बनाकर अधिकांश समय कक्षाओं से बच सकते हैं। और क्लोजर केवल "अन्य कार्यों के संदर्भ में परिभाषित कार्य" नहीं हैं।
एली कोरविगो

3
@ एली कोरविगो, वास्तव में, जनरेटर एक महत्वपूर्ण छलांग है। वे एक कतार का एक अमूर्त निर्माण उसी तरह से करते हैं, जिसमें फ़ंक्शन एक स्टैक के सार होते हैं। और अधिकांश डेटा प्रवाह स्टैक / कतार प्राइमिटिव से एक साथ pieced किया जा सकता है।
दिमित्री रूबनोविच

1
@DmitryRubanovich हम यहां सेब और संतरे की बात कर रहे हैं। मैं कह रहा हूँ, कि जनरेटर बहुत ही सीमित मामलों में उपयोगी होते हैं और किसी भी तरह से सामान्य प्रयोजन के लिए उपयोगी कॉलफुल का विकल्प नहीं माना जा सकता। आप मुझे बता रहे हैं, मेरी बातों का खंडन किए बिना वे कितने महान हैं।
एली कोरविगो

1
@ एली कोरविगो, और मैं कह रहा हूं कि कॉलबेल केवल कार्यों के सामान्यीकरण हैं। जो स्वयं स्टैक के प्रसंस्करण पर वाक्यगत चीनी हैं। जबकि जनरेटर कतारों के प्रसंस्करण के लिए सिंटैक्टिक चीनी होते हैं। लेकिन यह सिंटैक्स में यह सुधार है जो अधिक जटिल निर्माणों को आसानी से और अधिक स्पष्ट सिंटैक्स के साथ बनाने की अनुमति देता है। '.next ()' का उपयोग लगभग कभी नहीं किया गया है, btw।
दिमित्री रूबनोविच

11

मुझे लगता है कि आप इसे सही करते हैं। जब आप कुछ व्यावसायिक तर्क या कठिन वास्तविक जीवन की प्रक्रियाओं को कठिन संबंधों के साथ अनुकरण करना चाहते हैं तो कक्षाएं उचित होती हैं। उदाहरण के रूप में:

  • शेयर राज्य के साथ कई कार्य
  • एक ही राज्य चर की एक से अधिक प्रति
  • किसी मौजूदा कार्यक्षमता के व्यवहार का विस्तार करने के लिए

मैं आपको यह क्लासिक वीडियो देखने का सुझाव भी देता हूं


3
जब कॉलबैक फ़ंक्शन को पायथन में एक स्थिर स्थिति की आवश्यकता होती है, तो एक वर्ग का उपयोग करने की कोई आवश्यकता नहीं है। वापसी के बजाय अजगर की उपज का उपयोग करने से एक फ़ंक्शन फिर से प्रवेश करता है।
दिमित्री रूबनोविच

4

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

यदि यह मामला नहीं है, तो कक्षा बनाने की आवश्यकता नहीं है


0

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

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