2013-02-21 45 views
22

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

class Size(object): 
    """ 
    Utility object used to describe the size of a document. 
    """ 

    BYTE = 8 
    KILO = 1024 

    def __init__(self, bits): 
     self._bits = bits 

    @property 
    def bits(self): 
     return float(self._bits) 

    @property 
    def bytes(self): 
     return self.bits/self.BYTE 

    @property 
    def kilobits(self): 
     return self.bits/self.KILO 

    @property 
    def kilobytes(self): 
     return self.bytes/self.KILO 

    @property 
    def megabits(self): 
     return self.kilobits/self.KILO 

    @property 
    def megabytes(self): 
     return self.kilobytes/self.KILO 

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

class Size(object): 
    """ 
    Utility object used to describe the size of a document. 
    """ 

    BYTE = 8 
    KILO = 1024 

    @classmethod 
    def from_bytes(cls, bytes): 
     bits = bytes * cls.BYTE 
     return cls(bits) 

या

def create_instance_from_bytes(bytes): 
    bits = bytes * Size.BYTE 
    return Size(bits) 

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

कोई भी प्रतिक्रिया बहुत सराहना की है।

चीयर्स

+0

मैं एक सिक्का फ्लिप करना चाहता हूं। अधिकांश पायथन पुस्तकालय प्रक्रियात्मक एपीआई पसंद करते हैं, लेकिन ऐसा इसलिए है क्योंकि वे आपके कोडबेस में आंतरिक पुन: प्रयोज्य कोड से अलग तरीके से उपभोग करने के लिए हैं। – millimoose

+4

पीएस, एक चर 'बाइट्स' कॉल न करें; यह एक बिल्टिन प्रकार है (2.6 और बाद में)। – abarnert

+3

और निश्चित रूप से मुझे एहसास हुआ कि मैंने अपने जवाब में एक ही गलती की है: 'आकार (बाइट्स = 20) '। जैसा मैं करता हूं वैसा मत करो, जैसा कि मैंने कहा है। :) – abarnert

उत्तर

22

सबसे पहले, समय आपको लगता है कि आप कुछ इस तरह की जरूरत के अधिकांश, तुम नहीं; यह एक संकेत है कि आप जावा जैसे पायथन का इलाज करने की कोशिश कर रहे हैं, और समाधान वापस कदम उठाना है और पूछना है कि आपको कारखाने की आवश्यकता क्यों है।

अक्सर, सबसे सरल बात यह है कि केवल डिफॉल्ट/वैकल्पिक/कीवर्ड तर्कों के साथ एक कन्स्ट्रक्टर होना है। यहां तक ​​कि जिन मामलों में आप कभी भी जावा में इस तरह से लिख नहीं पाएंगे- यहां तक ​​कि ऐसे मामले जहां अधिभारित कन्स्ट्रक्टर सी ++ या ओबीजेसी में गलत महसूस करेंगे-पाइथन में पूरी तरह से प्राकृतिक दिख सकते हैं। उदाहरण के लिए, size = Size(bytes=20), या size = Size(20, Size.BYTES) उचित दिखते हैं। उस मामले के लिए, Bytes(20) वर्ग जो Size से विरासत में है और बिल्कुल कुछ भी नहीं जोड़ता है लेकिन __init__ ओवरलोड उचित दिखता है। और इन परिभाषित करने के लिए तुच्छ हैं:

def __init__(self, *, bits=None, bytes=None, kilobits=None, kilobytes=None): 

या:

BITS, BYTES, KILOBITS, KILOBYTES = 1, 8, 1024, 8192 # or object(), object(), object(), object() 
def __init__(self, count, unit=Size.BITS): 

लेकिन, कभी कभी आप जरूरत कारखाने कार्यों कर । तो, आप तब क्या करते हैं? खैर, दो प्रकार की चीजें हैं जिन्हें अक्सर "कारखानों" में एक साथ लाया जाता है।

एक @classmethod एक "वैकल्पिक निर्माता" ऐसा करने के लिए, वहाँ सभी stdlib- itertools.chain.from_iterable, datetime.datetime.fromordinal से अधिक उदाहरण हैं मुहावरेदार रास्ता, आदि

एक समारोह एक ऐसा करने के लिए मुहावरेदार तरीका है कि "मुझे नहीं पता देखभाल करें कि वास्तविक वर्ग क्या है "कारखाना। उदाहरण के लिए, अंतर्निहित open फ़ंक्शन देखें। क्या आप जानते हैं कि यह 3.3 में क्या आता है? क्या तुम्हें परवाह है? नहीं। यही कारण है कि यह एक समारोह है, io.TextIOWrapper.open या जो भी हो।

आपका दिया गया उदाहरण पूरी तरह वैध उपयोग केस की तरह लगता है, और "वैकल्पिक कन्स्ट्रक्टर" बिन में स्पष्ट रूप से फिट बैठता है (यदि यह "अतिरिक्त तर्कों के साथ निर्माता" बिन में फिट नहीं होता है)।

+2

जबकि मैं इसके साथ सहमत हूं - यह कहना उचित है कि @classmethod की बजाय एक अन्य डिज़ाइन विकल्प - __init __ (किलोबाइट = 345) 'आदि बनाना है ... –

+0

@ जोनक्लेमेंट्स: अच्छा बिंदु-हालांकि मुझे लगता है कि वास्तव में पहली वाक्य के साथ फिट बैठता है, जो निश्चित रूप से लिखित के रूप में स्पष्ट नहीं है, इसलिए मैं इसे संपादित कर दूंगा। – abarnert

+0

युप - मैं इस उपयोग के मामले के बारे में क्या सोच रहा था: http://dpaste.com/958194/ (सिवाय इसके कि यह एन * बेस * खांसी * होना चाहिए) –