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


101

मेरे पास एक ऐसा वर्ग है जिसमें केवल फ़ील्ड और कोई विधियाँ नहीं हैं, जैसे:

class Request(object):

    def __init__(self, environ):
        self.environ = environ
        self.request_method = environ.get('REQUEST_METHOD', None)
        self.url_scheme = environ.get('wsgi.url_scheme', None)
        self.request_uri = wsgiref.util.request_uri(environ)
        self.path = environ.get('PATH_INFO', None)
        # ...

इसे आसानी से एक डिक्टेट में अनुवाद किया जा सकता था। भविष्य के अतिरिक्त के लिए वर्ग अधिक लचीला है और इसके साथ तेज हो सकता है __slots__। तो क्या इसके बजाय एक हुकुम का उपयोग करने का कोई लाभ होगा? क्या एक तानाशाह किसी वर्ग से तेज होगा? और स्लॉट के साथ एक वर्ग की तुलना में तेजी से?


2
मैं हमेशा डेटा रखने के लिए शब्दकोशों का उपयोग करता हूं, और यह मेरे लिए उपयोग के मामले जैसा दिखता है। कुछ मामलों में एक वर्ग प्राप्त dictकरने से समझ में आता है, करने के लिए। साफ लाभ: जब आप डिबग करते हैं, तो बस कहते हैं print(request)और आप आसानी से सभी राज्य की जानकारी देखेंगे। अधिक शास्त्रीय दृष्टिकोण के साथ आपको अपने कस्टम __str__तरीकों को लिखना होगा , जो बेकार हो जाता है यदि आपको इसे हर समय करना है।
प्रवाह करें

वे विनिमेय स्टैकओवरफ़्लो
विजय

यदि कक्षा कुल मिलाकर समझ में आती है और दूसरों के लिए स्पष्ट है, तो क्यों नहीं इसके अलावा, यदि आप उदाहरण के लिए सामान्य इंटरफेस के साथ कई वर्गों को परिभाषित करते हैं, तो क्यों नहीं? लेकिन पायथन C ++ जैसी शक्तिशाली वस्तु उन्मुख अवधारणाओं का समर्थन नहीं करता है।
MasterControlProgram

3
@ राल क्या पायथन अजगर का समर्थन नहीं करता है?
qwr

जवाबों:


32

आप इसे शब्दकोश क्यों बनायेंगे? फायदा क्या है? यदि आप बाद में कुछ कोड जोड़ना चाहते हैं तो क्या होता है? आपका __init__कोड कहां जाएगा ?

कक्षाएं संबंधित डेटा (और आमतौर पर कोड) को बंडल करने के लिए होती हैं।

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

इसे एक क्लास रखें।


मैं एक तरह की फैक्ट्री विधि बनाऊंगा जो क्लास की __init__पद्धति के बजाय एक तानाशाही पैदा करेगा । लेकिन आप सही हैं: मैं उन चीजों को अलग करूंगा जो एक साथ हैं।
बहरीन

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

4
यह उन्मुख प्रोग्रामिंग है और किसी कारण से कक्षा उन्मुख नहीं है: हम वस्तुओं से निपटते हैं। एक वस्तु 2 (3) गुणों द्वारा विशेषता है: 1. राज्य (सदस्य) 2. व्यवहार (तरीके) और 3. उदाहरण कई शब्दों में वर्णित किया जा सकता है। इसलिए कक्षाएं राज्य और व्यवहार को एक साथ बांधने के लिए हैं।
फ्रेंडजिस

14
मैंने इसे नीचे चिह्नित किया है क्योंकि आपको हमेशा जहां संभव हो, सरल डेटा संरचना के लिए डिफ़ॉल्ट होना चाहिए। इस मामले में, एक शब्दार्थक उद्देश्य के लिए पर्याप्त है। सवाल where would your __init__ code go?का विषय है। यह एक कम अनुभवी डेवलपर को राजी कर सकता है कि केवल वर्गों का उपयोग किया जाए क्योंकि एक init पद्धति का उपयोग एक शब्दकोश में नहीं किया गया है। बेतुका।
लॉयड मूर

1
@ राल्फ ए क्लास फू केवल एक प्रकार है, जैसे इंट और स्ट्रिंग। क्या आप एक पूर्णांक प्रकार या पूर्णांक प्रकार के चर foo में मूल्य संग्रहीत करते हैं? सूक्ष्म, लेकिन महत्वपूर्ण अर्थ अंतर। C जैसी भाषाओं में यह अंतर अकादमिक हलकों के बाहर बहुत प्रासंगिक नहीं है। यद्यपि अधिकांश OO भाषाओं में वर्ग चर समर्थन होता है, जो वर्ग और वस्तु / उदाहरण के बीच अंतर को प्रासंगिक बनाता है - क्या आप कक्षा में डेटा (सभी उदाहरणों में साझा) या किसी विशिष्ट ऑब्जेक्ट में संग्रहीत करते हैं?
काटो

44

जब तक आपको किसी वर्ग के अतिरिक्त तंत्र की आवश्यकता न हो तब शब्दकोश का उपयोग करें। आप namedtupleहाइब्रिड दृष्टिकोण के लिए भी उपयोग कर सकते हैं :

>>> from collections import namedtuple
>>> request = namedtuple("Request", "environ request_method url_scheme")
>>> request
<class '__main__.Request'>
>>> request.environ = "foo"
>>> request.environ
'foo'

यहां प्रदर्शन का अंतर कम से कम होगा, हालांकि मुझे आश्चर्य होगा कि अगर शब्दकोश तेज नहीं था।


15
"यहां प्रदर्शन का अंतर न्यूनतम होगा , हालांकि मुझे आश्चर्य होगा कि अगर शब्दकोश काफी तेज नहीं था ।" यह गणना नहीं करता है। :)
मपीदी

1
@mipadi: यह सच है। अब नियत: p
कैट्रील

तानाशाह नेमटुपल की तुलना में 1.5 गुना तेज और बिना स्लॉट्स के एक वर्ग के मुकाबले दोगुना तेज है। इस उत्तर पर मेरी पोस्ट देखें।
एलेक्सपिनहो98

@ alexpinho98: मैंने उस 'पोस्ट' को खोजने की बहुत कोशिश की, जिसका आप जिक्र कर रहे हैं, लेकिन मैं इसे नहीं पा सकता! क्या आप URL प्रदान कर सकते हैं धन्यवाद!
डैन ओब्लिंगर

@DanOblinger मैं मान रहा हूँ कि वह नीचे अपने जवाब का मतलब है।
एडम लुईस

37

अजगर में एक वर्ग है एक dict नीचे। आपको क्लास के व्यवहार के साथ कुछ ओवरहेड मिलता है, लेकिन आप इसे बिना प्रोफाइलर के नोटिस नहीं कर पाएंगे। इस मामले में, मेरा मानना ​​है कि आप वर्ग से लाभान्वित होंगे क्योंकि:

  • आपके सभी तर्क एक ही फ़ंक्शन में रहते हैं
  • अद्यतन करना आसान है और रुक जाता है
  • यदि आप बाद में कुछ भी बदलते हैं, तो आप इंटरफ़ेस को आसानी से रख सकते हैं

आपके सभी तर्क एक समारोह में नहीं रहते हैं। एक वर्ग साझा राज्य का एक टपल है और आमतौर पर एक या एक से अधिक तरीके। यदि आप एक वर्ग बदलते हैं, तो आपको इंटरफ़ेस के बारे में कोई गारंटी नहीं दी जाती है।
लॉयड मूर

25

मुझे लगता है कि हर एक का उपयोग मेरे लिए उस पर प्राप्त करने के लिए बहुत व्यक्तिपरक है, इसलिए मैं सिर्फ संख्याओं पर टिकूंगा।

मैंने उस समय की तुलना की, जिसमें एक परिवर्तन करने के लिए समय लगता है, और एक परिवर्तनशील, एक new_style वर्ग और स्लॉट्स के साथ एक new_style वर्ग।

यहां वह कोड है जिसका मैं इसे परीक्षण करता था (यह थोड़ा गड़बड़ है लेकिन यह काम करता है।)

import timeit

class Foo(object):

    def __init__(self):

        self.foo1 = 'test'
        self.foo2 = 'test'
        self.foo3 = 'test'

def create_dict():

    foo_dict = {}
    foo_dict['foo1'] = 'test'
    foo_dict['foo2'] = 'test'
    foo_dict['foo3'] = 'test'

    return foo_dict

class Bar(object):
    __slots__ = ['foo1', 'foo2', 'foo3']

    def __init__(self):

        self.foo1 = 'test'
        self.foo2 = 'test'
        self.foo3 = 'test'

tmit = timeit.timeit

print 'Creating...\n'
print 'Dict: ' + str(tmit('create_dict()', 'from __main__ import create_dict'))
print 'Class: ' + str(tmit('Foo()', 'from __main__ import Foo'))
print 'Class with slots: ' + str(tmit('Bar()', 'from __main__ import Bar'))

print '\nChanging a variable...\n'

print 'Dict: ' + str((tmit('create_dict()[\'foo3\'] = "Changed"', 'from __main__ import create_dict') - tmit('create_dict()', 'from __main__ import create_dict')))
print 'Class: ' + str((tmit('Foo().foo3 = "Changed"', 'from __main__ import Foo') - tmit('Foo()', 'from __main__ import Foo')))
print 'Class with slots: ' + str((tmit('Bar().foo3 = "Changed"', 'from __main__ import Bar') - tmit('Bar()', 'from __main__ import Bar')))

और यहाँ उत्पादन है ...

बनाना...

Dict: 0.817466186345
Class: 1.60829183597
Class_with_slots: 1.28776730003

परिवर्तनशील ...

Dict: 0.0735140918748
Class: 0.111714198313
Class_with_slots: 0.10618612142

इसलिए, यदि आप केवल चर संग्रहित कर रहे हैं, तो आपको गति की आवश्यकता होती है, और इसके लिए आपको कई गणनाएँ करने की आवश्यकता नहीं होगी, मैं एक तानाशाह का उपयोग करने की सलाह देता हूं (आप हमेशा एक फ़ंक्शन बना सकते हैं जो एक विधि की तरह दिखता है)। लेकिन, अगर आपको वास्तव में कक्षाओं की आवश्यकता है, तो याद रखें - हमेशा __ स्लॉट का उपयोग करें __

ध्यान दें:

मैंने 'क्लास' का परीक्षण new_style और old_style दोनों वर्गों के साथ किया। यह पता चला है कि Old_style कक्षाएं बनाने के लिए तेज़ हैं, लेकिन संशोधित करने के लिए धीमी (बहुत अधिक लेकिन महत्वपूर्ण नहीं हैं यदि आप एक तंग लूप में बहुत सारी कक्षाएं बना रहे हैं (टिप: आप इसे गलत कर रहे हैं)।

चरों के बनाने और बदलने का समय भी आपके कंप्यूटर पर हो सकता है क्योंकि मेरा पुराना और धीमा है। सुनिश्चित करें कि आप 'वास्तविक' परिणाम देखने के लिए इसे स्वयं परखें।

संपादित करें:

मैंने बाद में नामित नाम का परीक्षण किया: मैं इसे संशोधित नहीं कर सकता लेकिन 10000 नमूने (या ऐसा कुछ) बनाने में 1.4 सेकंड का समय लगा, इसलिए शब्दकोश वास्तव में सबसे तेज़ है।

यदि मैं चाबियाँ और मूल्यों को शामिल करने के लिए तानाशाही फ़ंक्शन को बदल देता हूं और जब मैं इसे बनाता हूं, तो यह वेरिएबल युक्त वेरिएबल के बजाय वापस लौटा देता है। यह 0.8 सेकंड के बजाय मुझे 0.65 देता है

class Foo(dict):
    pass

बनाना स्लॉट्स वाली एक क्लास की तरह है और वेरिएबल को बदलना सबसे धीमा (0.17 सेकंड) है, इसलिए इन क्लास का इस्तेमाल न करें । एक तानाशाही (गति) के लिए या ऑब्जेक्ट से व्युत्पन्न वर्ग के लिए जाएं ('सिंटैक्स कैंडी')


मैं एक उपवर्ग के लिए संख्याओं को देखना चाहता हूं dict(बिना किसी ओवरराइड विधियों के, मुझे लगता है?)। क्या यह उसी तरह का प्रदर्शन करता है जैसे कि एक नई शैली का वर्ग जो खरोंच से लिखा गया था?
बेंजामिन हॉजसन

12

मैं @adw से सहमत हूं। मैं कभी भी एक शब्दकोश के साथ एक "वस्तु" (एक ओ ओ अर्थ में) का प्रतिनिधित्व नहीं करूंगा। शब्दकोश सकल नाम / मूल्य जोड़े। कक्षाएं वस्तुओं का प्रतिनिधित्व करती हैं। मैंने कोड देखा है जहां वस्तुओं को शब्दकोशों के साथ दर्शाया गया है और यह स्पष्ट नहीं है कि चीज़ का वास्तविक आकार क्या है। क्या होता है जब कुछ नाम / मान नहीं होते हैं? क्या ग्राहक को कुछ भी डालने से रोकता है या बाहर कुछ भी प्राप्त करने की कोशिश कर रहा है। चीज़ के आकार को हमेशा स्पष्ट रूप से परिभाषित किया जाना चाहिए।

पायथन का उपयोग करते समय अनुशासन के साथ निर्माण करना महत्वपूर्ण है क्योंकि भाषा लेखक को पैर में उसे / खुद को गोली मारने के कई तरीके देती है।


9
SO पर उत्तरों को वोटों द्वारा क्रमबद्ध किया जाता है, और एक ही वोट गणना के साथ उत्तर बेतरतीब ढंग से दिए जाते हैं। तो कृपया स्पष्ट करें कि आप "अंतिम पोस्टर" से किसका मतलब है।
माइक डिमोन

4
और आप कैसे जानते हैं कि ऐसी कोई चीज़ जिसमें केवल फ़ील्ड्स हैं और कोई कार्यक्षमता नहीं है, एक OO अर्थ में "ऑब्जेक्ट" है?
मुहम्मद अल्करौरी

1
मेरा लिटमस टेस्ट "इस डेटा की संरचना तय है?"। यदि हाँ, तो एक वस्तु का उपयोग करें, अन्यथा एक तानाशाही। इससे प्रस्थान केवल भ्रम पैदा करने वाला है।
weberc2

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

5

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

इसलिए, कक्षा के साथ रहें।


2
मैं पूरी तरह से असहमत हूँ। चीजों को शब्दकोशों के उपयोग को सीमित करने का कोई कारण नहीं है। वे मानचित्रण बनाए रखने के लिए हैं।
कैट्रील

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

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

4

यदि आप जो हासिल करना चाहते हैं वह सब सिंटेक्स कैंडी की तरह obj.bla = 5है obj['bla'] = 5, खासकर यदि आपको यह दोहराना है कि बहुत कुछ, आप शायद कुछ सादे कंटेनर वर्ग का उपयोग करना चाहते हैं जैसे कि मार्टिनेस सुझाव। फिर भी, वहाँ कोड काफी फूला हुआ और अनावश्यक रूप से धीमा है। आप इसे इस तरह सरल रख सकते हैं:

class AttrDict(dict):
    """ Syntax candy """
    __getattr__ = dict.__getitem__
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

स्मृति उपयोग के namedtupleसाथ s या कक्षा में स्विच करने का एक और कारण __slots__हो सकता है। डायट को सूची प्रकारों की तुलना में बहुत अधिक मेमोरी की आवश्यकता होती है, इसलिए यह सोचने का बिंदु हो सकता है।

वैसे भी, आपके विशिष्ट मामले में, आपके वर्तमान कार्यान्वयन से दूर जाने के लिए कोई प्रेरणा प्रतीत नहीं होती है। आप इनमें से लाखों वस्तुओं को बनाए रखने के लिए प्रतीत नहीं होते हैं, इसलिए किसी भी सूची-व्युत्पन्न प्रकार की आवश्यकता नहीं है। और यह वास्तव में कुछ कार्यात्मक तर्क से युक्त है __init__, इसलिए आपको भी नहीं मिलना चाहिए AttrDict


types.SimpleNamespace(पायथन 3.3 के बाद से उपलब्ध) कस्टम AttrDict का एक विकल्प है।
क्रिस्टियन सियुपिटु

4

यह संभव है कि आपका केक हो और इसे खाएं। दूसरे शब्दों में आप कुछ ऐसा बना सकते हैं जो एक वर्ग और शब्दकोश उदाहरण दोनों की कार्यक्षमता प्रदान करता है। ActiveState का Dɪᴄᴛɪᴏɴᴀʀʏ ᴡɪᴛʜ Active-sᴀᴄᴄᴇ .ss देखें नुस्खा देखें और करने के तरीकों पर टिप्पणी करें।

यदि आप उपवर्ग के बजाय एक नियमित कक्षा का उपयोग करने का निर्णय लेते हैं, तो मैंने पाया है कि Tɪᴍᴘʟᴇ sʙᴜᴛ ʙᴜᴛ ʜᴀɴᴅʏ "ᴀ a a a ᴛᴜғғ sᴛᴜғғ" recipess नुस्खा (एलेक्स मार्टेली द्वारा) बहुत ही लचीला और उपयोगी है। ऐसा लगता है कि आप कर रहे हैं (यानी जानकारी के सापेक्ष सरल एग्रीगेटर बनाएं)। चूंकि यह एक वर्ग है आप आसानी से तरीकों को जोड़कर इसकी कार्यक्षमता को और बढ़ा सकते हैं।

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

अपडेट करें

मॉड्यूल पायथन 3.3 में एक वर्ग object(जिसका कोई नहीं है __dict__) का नाम SimpleNamespace(जिसमें एक है) को जोड़ा गया था types, और अभी तक कोई अन्य विकल्प नहीं है।


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