पायथन में कक्षा चर बनाम उदाहरण चर


120

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

कक्षा चर:

class MyController(Controller):

  path = "something/"
  children = [AController, BController]

  def action(self, request):
    pass

आवृत्ति के चर:

class MyController(Controller):

  def __init__(self):
    self.path = "something/"
    self.children = [AController, BController]

  def action(self, request):
    pass

4
इस प्रश्न को पढ़ने और उत्तर देखने के बाद, मेरा पहला प्रश्न था, "तो मैं कक्षा चर का उपयोग कैसे करूं?" - क्योंकि इस बिंदु तक मैं केवल उदाहरण चर का उपयोग किया है। मेरे स्वयं के प्रश्न के उत्तर में, आप इसे कक्षा के नाम के माध्यम से करते हैं, हालांकि तकनीकी रूप से आप इसे एक उदाहरण के माध्यम से भी कर सकते हैं। यहाँ एक ही प्रश्न के साथ किसी और के लिए पढ़ने के लिए एक लिंक है: stackoverflow.com/a/3434596/4561887
गेब्रियल स्टेपल्स

जवाबों:


158

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


7
बोर्ग पैटर्न के बारे में कभी नहीं सुना? केवल एक ही उदाहरण होना पहली जगह में होने का गलत तरीका था।
डेविन जीनपीयरे

434
@ डिविज़न, हाँ, मैंने बोर्ग पैटर्न के बारे में सुना है, क्योंकि मैं वह हूँ जिसने इसे पेश किया था (2001 में, cfr code.activestate.com/recipes/… ;-)। लेकिन कुछ भी गलत नहीं है, साधारण मामलों में, बिना किसी प्रवर्तन के बस एक ही उदाहरण के साथ।
एलेक्स मार्टेली

2
@ user1767754, उन्हें अपने आप से बनाना आसान है python -mtimeit- लेकिन सिर्फ इतना python3.4 में किया है। मैं ध्यान दें कि एक intवर्ग चर का उपयोग वास्तव में लगभग 5 से 11 नैनोसेकंड है जो मेरे पुराने वर्कस्टेशन पर उसी तरह से अधिक है, जो सुनिश्चित नहीं है - कोडपाथ ऐसा बनाता है।
एलेक्स मार्टेली

45

आगे माइक और एलेक्स की सलाह की गूंज और मेरा अपना रंग जोड़ने ...

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

एलेक्स ने अपने उत्तर में उल्लेख किया कि एक कम स्तर की खोज के कारण पहुंच (थोड़ी सी) तेज होगी ... मुझे उन लोगों के लिए और स्पष्ट करना चाहिए जो इस बारे में नहीं जानते हैं कि यह अभी तक कैसे काम करता है। यह परिवर्तनशील पहुंच के समान है - जिसकी खोज क्रम है:

  1. स्थानीय लोगों
  2. nonlocals
  3. वैश्विक
  4. बनाया-इन

विशेषता पहुंच के लिए, आदेश है:

  1. उदाहरण
  2. कक्षा
  3. MRO द्वारा निर्धारित आधार कक्षाएं (विधि संकल्प आदेश)

दोनों तकनीक "अंदर-बाहर" तरीके से काम करती हैं, जिसका अर्थ है कि सबसे स्थानीय वस्तुओं को पहले चेक किया जाता है, फिर बाहरी परतों को उत्तराधिकार में जांचा जाता है।

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

हालाँकि, यदि आप वर्ग विशेषताओं पर जोर देते हैं, तो आपको उस अतिरिक्त खोज की आवश्यकता है। या , आपका अन्य विकल्प ऑब्जेक्ट को उदाहरण के बजाय वर्ग के माध्यम से संदर्भित करना है, जैसे, के MyController.pathबजाय self.path। यह एक प्रत्यक्ष लुकअप है जो आस्थगित लुकअप के आसपास मिलेगा, लेकिन जैसा कि नीचे उल्लेख किया गया है, यह एक वैश्विक वैरिएबल है, इसलिए आप उस बिट को खो देते हैं जो आपने सोचा था कि आप सहेजने जा रहे थे (जब तक कि आप [ग्लोबल] वर्ग के नाम का स्थानीय संदर्भ न बनाएं। )।

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


@wescpy, लेकिन MyController, वैश्विक में देखा तो कुल लागत की तुलना में अधिक है self.pathजहां pathएक उदाहरण चर रहा है (के बाद से selfहै स्थानीय विधि == सुपर फास्ट देखने के लिए)।
एलेक्स मार्टेली

आह, सच। अच्छी पकड़। मुझे लगता है कि स्थानीय संदर्भ बनाने के लिए एकमात्र समाधान है ... इस बिंदु पर, यह वास्तव में इसके लायक नहीं है।
वेस्कैपी 27'10

24

जब संदेह में, आप शायद एक उदाहरण विशेषता चाहते हैं।

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


1
कक्षा चर एक प्रकार का केवल पढ़ने योग्य स्थिरांक हैं। यदि पायथन मुझे स्थिरांक परिभाषित करता है, तो मैंने इसे स्थिरांक के रूप में लिखा होगा।
बहमन

1
@ डायमॉन, मुझे अपने कॉन्स्टेंट्स को पूरी तरह से एक क्लास परिभाषा के बाहर रखने और सभी कैप में नाम रखने की संभावना है। उन्हें कक्षा के अंदर रखना भी ठीक है। उन्हें उदाहरण बनाने से कुछ भी नुकसान नहीं होगा, लेकिन थोड़ा अजीब हो सकता है। मुझे नहीं लगता कि यह एक ऐसा मुद्दा है जहां समुदाय बहुत अधिक विकल्पों में से एक के पीछे हो जाता है।
माइक ग्राहम

@ माइकइग्राहम एफडब्ल्यूआईडब्ल्यू, गूगल का पायथन स्टाइल गाइड वर्ग चर के पक्ष में वैश्विक चर से बचने का सुझाव देता है। हालांकि इसके कुछ अपवाद भी हैं।
डेनिस

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

4

पायथन में वर्ग चर तक पहुँचने के प्रदर्शन पर एक ही सवाल - यहाँ कोड @ एडवर्ड लपर से अनुकूलित है

लोकल वेरिएबल्स एक्सेस करने के लिए सबसे तेज़ हैं, बहुत अधिक मॉड्यूल वेरिएबल्स के साथ बंधे हैं, इसके बाद क्लास वेरिएबल्स, उसके बाद इंस्टेंस वेरिएबल्स।

4 स्कोप हैं जिनसे आप चर तक पहुँच सकते हैं:

  1. इंस्टेंस वेरिएबल्स (self.varname)
  2. वर्ग चर (Classname.varname)
  3. मॉड्यूल चर (VARNAME)
  4. स्थानीय चर (varname)

कसौटी:

import timeit

setup='''
XGLOBAL= 5
class A:
    xclass = 5
    def __init__(self):
        self.xinstance = 5
    def f1(self):
        xlocal = 5
        x = self.xinstance
    def f2(self):
        xlocal = 5
        x = A.xclass
    def f3(self):
        xlocal = 5
        x = XGLOBAL
    def f4(self):
        xlocal = 5
        x = xlocal
a = A()
'''
print('access via instance variable: %.3f' % timeit.timeit('a.f1()', setup=setup, number=300000000) )
print('access via class variable: %.3f' % timeit.timeit('a.f2()', setup=setup, number=300000000) )
print('access via module variable: %.3f' % timeit.timeit('a.f3()', setup=setup, number=300000000) )
print('access via local variable: %.3f' % timeit.timeit('a.f4()', setup=setup, number=300000000) )

परिणाम:

access via instance variable: 93.456
access via class variable: 82.169
access via module variable: 72.634
access via local variable: 72.199
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.