क्या पायथन में किसी भी वर्ग में उदाहरण चर को घोषित करना एक अच्छा अभ्यास है?


68

निम्नलिखित वर्ग पर विचार करें:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

मेरे सहकर्मी इसे इस तरह परिभाषित करते हैं:

class Person:
    name = None
    age = None

    def __init__(self, name, age):
        self.name = name
        self.age = age

इसका मुख्य कारण यह है कि उनकी पसंद का संपादक स्वतः पूर्णता के गुणों को दर्शाता है।

व्यक्तिगत रूप से, मैं बाद वाले को नापसंद करता हूं, क्योंकि इसका कोई मतलब नहीं है कि एक वर्ग के पास उन गुणों को निर्धारित किया गया है None

कौन सा बेहतर अभ्यास होगा और किन कारणों से?


62
अपने IDE को कभी भी न बताएं कि आप क्या कोड लिखते हैं?
मार्टिज़न पीटर्स

14
वैसे: एक उचित अजगर आईडीई (जैसे PyCharm) __init__का उपयोग करके, पहले से ही विशेषताओं को सेट करना स्वत: पूर्णता आदि प्रदान करता है। इसके अलावा, Noneआईडीई को विशेषता के लिए बेहतर प्रकार का अनुमान लगाने से रोकता है, इसलिए इसके बजाय एक संवेदी डिफ़ॉल्ट का उपयोग करना बेहतर है (जब मुमकिन)।
बकुरीउ

यदि यह सिर्फ ऑटोकंप्लीमेंट के लिए है तो आप टाइप हिंटिंग का उपयोग कर सकते हैं, और अतिरिक्त डोकस्ट्रिंग्स एक प्लस भी होगा।
10

3
"कभी भी अपने आईडीई को यह निर्धारित न करने दें कि आप किस कोड को लिखते हैं" एक बहस का मुद्दा है। पाइथन 3.6 के रूप में इन-लाइन एनोटेशन और एक typingमॉड्यूल है, जो आपको आईडीई और लिंटर को संकेत प्रदान करने की अनुमति देता है, अगर उस तरह की चीज आपके फैंस को गुदगुदी करती है ...
cz

1
कक्षा स्तर पर इन असाइनमेंट का बाकी कोड पर कोई प्रभाव नहीं पड़ता है। उन पर कोई असर नहीं हुआ self। भले ही वे सौंपे गए हों self.nameया self.ageनहीं , __init__उदाहरण के लिए self, वे केवल कक्षा में दिखाई देते हैं Person
जोलवी २

जवाबों:


70

मैं बाद के बुरे व्यवहार को "यह वह नहीं करता है जो आप सोचते हैं कि यह करता है" नियम है।

आपके सहकर्मी की स्थिति को फिर से लिखा जा सकता है: "मैं क्लास-स्टैटिक क्वासी-ग्लोबल वैरिएबल का एक समूह बनाने जा रहा हूं जो कभी एक्सेस नहीं किया जाता है, लेकिन जो विभिन्न क्लास के नेमस्पेस टेबल ( __dict__) में जगह लेते हैं , बस अपनी आईडीई बनाने के लिए कुछ कुछ।"


4
कुछ हद तक डॉकस्ट्रिंग्स की तरह ;-) बेशक, पायथन के पास उन लोगों के लिए स्ट्रिप करने का एक आसान तरीका है -OO, जिनके लिए इसकी ज़रूरत है।
स्टीव जेसप

15
लिया गया स्थान अब तक का सबसे कम महत्वपूर्ण कारण है जिससे यह सम्मेलन बदबू मार रहा है। यह एक दर्जन बाइट्स प्रति नाम (प्रति प्रक्रिया) है। मुझे ऐसा लग रहा है कि मेरा समय बर्बाद हो रहा है, बस आपके उत्तर का हिस्सा इसे पढ़ रहा है, यही कारण है कि यह अंतरिक्ष लागत को महत्वहीन करता है।

8
@delnan मैं एंट्रीज़ के मेमोरी साइज़ के बारे में व्यर्थ है, मैं अधिक विचारशील / मानसिक स्थान पर विचार कर रहा था, आत्मनिरीक्षण डिबगिंग बना रहा था और ऐसे में अधिक पढ़ने और छांटने की आवश्यकता होती है, मुझे लगता है। मैं ~ एलएल
स्टारविवर

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

2
यदि आप 8 बाइट्स के बारे में चिंतित थे तो आप पायथन का उपयोग नहीं करेंगे।
cz

26

1. अपने कोड को समझने में आसान बनाएं

कोड लिखित की तुलना में अधिक बार पढ़ा जाता है। अपने कोड मेंटेनर के काम को आसान बनायें (यह अगले साल खुद भी हो सकता है)।

मैं किसी भी कठिन नियमों के बारे में नहीं जानता, लेकिन मैं भविष्य के किसी भी उदाहरण को स्पष्ट रूप से स्पष्ट घोषित करना पसंद करता हूं । ए के साथ क्रैश करना AttributeErrorकाफी बुरा है। स्पष्ट रूप से नहीं देख रहा है एक उदाहरण विशेषता का जीवनचक्र बदतर है। संभावित कॉल सीक्वेंस को पुनर्स्थापित करने के लिए आवश्यक मानसिक जिम्नास्टिक की मात्रा जिसे विशेषता को सौंपा जा रहा है, आसानी से गैर-तुच्छ हो सकता है, जिससे त्रुटि हो सकती है।

इसलिए मैं आमतौर पर न केवल कंस्ट्रक्टर में सबकुछ परिभाषित करता हूं, बल्कि उत्परिवर्तनीय विशेषताओं की संख्या को न्यूनतम रखने का भी प्रयास करता हूं।

2. वर्ग-स्तरीय और उदाहरण-स्तर के सदस्यों को न मिलाएं

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

क्लास-स्तरीय डेटा सदस्य स्थिरांक के रूप में सबसे अधिक उपयोगी हैं:

class Missile(object):
  MAX_SPEED = 100  # all missiles accelerate up to this speed
  ACCELERATION = 5  # rate of acceleration per game frame

  def move(self):
    self.speed += self.ACCELERATION
    if self.speed > self.MAX_SPEED:
      self.speed = self.MAX_SPEED
    # ...

2
हाँ, लेकिन वर्ग-स्तरीय और उदाहरण-स्तर के सदस्यों को मिलाना बहुत अधिक है जो डीफ़ करता है। यह ऐसे कार्यों का निर्माण करता है जिन्हें हम वस्तुओं की विशेषता मानते हैं, लेकिन वास्तव में वर्ग के सदस्य हैं। यही बात संपत्ति और उसके ilk के लिए भी जाती है। यह भ्रम देना कि काम वस्तुओं से संबंधित है जब यह वास्तव में वर्ग द्वारा मध्यस्थता है नट न जाने का एक समय सम्मानित तरीका है। यह सब इतना बुरा कैसे हो सकता है, अगर यह खुद पायथन के लिए ठीक है।
जॉन जे ओबेरमार्क

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

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

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

आनंद! मिसाइलों! वैसे भी, मुझे पूरा यकीन है कि क्लास लेवल वर्जन बनाना और उन्हें मिक्स करना ठीक है ... जब तक क्लास लेवल में डिफॉल्ट होते हैं, आदि
Erik Aronesty

18

व्यक्तिगत रूप से मैं सदस्यों को __ init __ () विधि में परिभाषित करता हूं। मैंने उन्हें कक्षा के भाग में परिभाषित करने के बारे में कभी नहीं सोचा था। लेकिन मैं हमेशा क्या करता हूं: मैं __ init__ मेथड में सभी सदस्यों को इनविट करता हूं, यहां तक ​​कि जिन्हें __ init__ मेथड की जरूरत नहीं है।

उदाहरण:

class Person:
    def __init__(self, name, age):
        self._name = name
        self._age = age
        self._selected = None

   def setSelected(self, value):
        self._selected = value

मुझे लगता है कि सभी सदस्यों को एक जगह परिभाषित करना महत्वपूर्ण है। यह कोड को अधिक पठनीय बनाता है। चाहे वह __ init __ () के बाहर हो या बाहर, वह महत्वपूर्ण नहीं है। लेकिन एक टीम के लिए कमोबेश एक ही कोडिंग शैली के लिए प्रतिबद्ध होना महत्वपूर्ण है।

ओह, और आप नोटिस कर सकते हैं कि मैं कभी भी सदस्य चर में उपसर्ग "_" जोड़ता हूं।


13
आपको कंस्ट्रक्टर में सभी मान सेट करने चाहिए। यदि मूल्य वर्ग में ही सेट किया गया था, तो इसे उदाहरणों के बीच साझा किया जाएगा, जो कि किसी के लिए भी ठीक है, लेकिन अधिकांश मूल्यों के लिए नहीं। तो इसके बारे में कुछ भी मत बदलो। ;)
रेमको हस्ज़िंग

4
मापदंडों के लिए डिफ़ॉल्ट मान, और मनमाने ढंग से स्थितीय और खोजशब्द तर्क लेने की क्षमता इसे बहुत कम दर्दनाक बनाती है, जिसकी अपेक्षा की जाती है। (और यह वास्तव में निर्माण को अन्य तरीकों या यहां तक ​​कि अकेले खड़े कार्यों को सौंपने के लिए संभव है, इसलिए यदि आपको वास्तव में कई प्रेषण की आवश्यकता है तो आप भी ऐसा कर सकते हैं)।
शॉन विएरा

6
@ बेनेडिक्ट पायथन का कोई एक्सेस कंट्रोल नहीं है। अग्रणी अंडरस्कोर कार्यान्वयन विवरण के लिए स्वीकृत सम्मेलन है। पीईपी 8 देखें ।
डोभाल

3
@ डोवाल गुण नामों के साथ उपसर्ग करने के लिए एक असाधारण अच्छा कारण है _: यह इंगित करने के लिए कि यह निजी है! (इस धागे में इतने सारे लोग भ्रमित क्यों हैं या अन्य भाषाओं के साथ आधे भ्रमित भ्रमित अजगर?)

1
आह, तो आप उन गुणों-या-फ़ंक्शंस-फॉर-ऑल-एक्सक्लूसिव-इंटरैक्शन लोगों में से एक हैं ... गलतफहमी के लिए क्षमा करें। वह शैली मुझे हमेशा अत्यधिक लगती है, लेकिन इसमें निम्नलिखित है।
जॉन जे ओबेरमार्क

11

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

विचार करें:

>>> class WithNone:
...   x = None
...   y = None
...   def __init__(self, x, y):
...     self.x = x
...     self.y = y
... 
>>> class InitOnly:
...   def __init__(self, x, y):
...     self.x = x
...     self.y = y
... 
>>> wn = WithNone(1,2)
>>> wn.x
1
>>> WithNone.x #Note that it returns none, no error
>>> io = InitOnly(1,2)
>>> InitOnly.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: class InitOnly has no attribute 'x'

मुझे उस 'त्रुटि के कारण' को कॉल करने के लिए मुश्किल होगा। यह अस्पष्ट है कि आप यहां 'x' का अनुरोध करने से क्या मतलब है, लेकिन आप बहुत अच्छी तरह से सबसे प्रारंभिक प्रारंभिक मूल्य चाहते हैं।
जॉन जे ओबेरमार्क

मुझे विस्तार से बताना चाहिए था कि अगर गलत तरीके से इस्तेमाल किया जाता है तो यह एक त्रुटि का कारण बन सकता है।
डेनिथ

उच्च जोखिम अभी भी एक वस्तु के लिए प्रारंभिक है। कोई भी वास्तव में बहुत सुरक्षित नहीं है। एकमात्र त्रुटि यह पैदा करने वाली है कि वास्तव में लंगड़ा-दिमाग अपवादों को निगलने के लिए है।
जॉन जे ओबेरमार्क

1
त्रुटियों के कारण असफल होना एक समस्या है यदि त्रुटियों ने अधिक गंभीर मुद्दों को रोका होगा।
एलिक एरोनेस्टी

0

मैं "थोड़ा सा डोकस्ट्रिंग्स, फिर" के साथ जाऊंगा और इस हानिरहित घोषित करूंगा, जब तक यह हमेशा होता हैNone , या अन्य मूल्यों की एक संकीर्ण श्रेणी, सभी अपरिवर्तनीय।

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

यह दस्तावेज करता है कि अपेक्षित नाम क्या हैं, इसलिए अगर मैं किसी के साथ कोड जोड़ देता हूं और हममें से किसी का 'यूजरनेम' है और दूसरा user_name है, तो मनुष्यों का एक संकेत है कि हमारे पास तरीके हैं और समान चर का उपयोग नहीं कर रहे हैं।

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

स्पष्ट रूप से BIG समस्या यह है कि यह लोगों को अन्य मूल्यों के साथ आरंभ करने के लिए प्रेरित करता है None, जो खराब हो सकते हैं:

class X:
    v = {}
x = X()
x.v[1] = 2

एक वैश्विक निशान छोड़ता है और x के लिए एक उदाहरण नहीं बनाता है।

लेकिन इस प्रथा की तुलना में अजगर के रूप में एक विचित्रता अधिक है, और हमें इसके बारे में पहले ही अवगत होना चाहिए।

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