पायथन "ईश्वर वर्ग" को कैसे प्रतिशोधित करें?


10

मुसीबत

मैं एक पायथन प्रोजेक्ट पर काम कर रहा हूं जिसका मुख्य वर्ग थोड़ा " गॉड ऑब्जेक्ट " है। वहाँ रहे हैं तो friggin 'कई गुण और तरीकों!

मैं क्लास को रिफ्लेक्टर करना चाहता हूं।

अब तक…

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

मूल रूप से, वर्ग में विशेषताओं की एक लंबी सूची है - लेकिन मैं स्पष्ट रूप से उन्हें देख सकता हूं और सोच सकता हूं, "ये 5 विशेषताएँ संबंधित हैं ... ये 8 भी संबंधित हैं ... और फिर बाकी हैं।"

getattr

मैं मूल रूप से संबंधित विशेषताओं को एक तानाशाह की तरह सहायक श्रेणी में समूहित करना चाहता था। मुझे लगता है __getattr__कि यह नौकरी के लिए आदर्श होगा। इसलिए मैंने विशेषताओं को एक अलग वर्ग में स्थानांतरित कर दिया, और, निश्चित रूप से पर्याप्त, __getattr__अपने जादू को पूरी तरह से काम किया ...

सबसे पहले

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

@संपत्ति

मैंने तब @propertyडेकोरेटर के बारे में पढ़ा । लेकिन फिर मैंने यह भी पढ़ा कि यह उन उपवर्गों के लिए समस्याएँ पैदा करता है जो तब करना चाहते हैं self.x = blahजब xमूल वर्ग की संपत्ति होती है।

चाहा हे

  • सभी क्लाइंट कोड का उपयोग करना जारी रखें self.whatever, भले ही माता-पिता की whateverसंपत्ति "भौतिक रूप से" कक्षा (या उदाहरण) में न हो।
  • समूह से संबंधित विशेषताओं को तानाशाह की तरह कंटेनरों में।
  • मुख्य कक्षा में कोड की चरम नीचता को कम करें।

उदाहरण के लिए, मैं इसे बदलना नहीं चाहता:

larry = 2
curly = 'abcd'
moe   = self.doh()

इस मामले में:

larry = something_else('larry')
curly = something_else('curly')
moe   = yet_another_thing.moe()

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

हालांकि, मैं इस तरह से कुछ के साथ ठीक हो जाएगा:

stooges = Stooges()

और यदि कोई विफलता के लिए खोज करता self.larryहै, तो कुछ जाँच करेगा stoogesऔर देखेगा कि क्या larryहै। (लेकिन यह भी काम करना होगा अगर कोई उपवर्ग larry = 'blah'वर्ग स्तर पर करने की कोशिश करे ।)

सारांश

  • माता-पिता वर्ग में विशेषताओं के संबंधित समूहों को एक एकल विशेषता के साथ बदलना चाहते हैं जो सभी डेटा को कहीं और संग्रहीत करता है
  • मौजूदा क्लाइंट कोड के साथ काम करना चाहते हैं larry = 'blah'जो वर्ग स्तर पर उपयोग करता है (जैसे)
  • उपवर्गों को कुछ भी बदले बिना जानने के लिए इन refactored विशेषताओं को बढ़ाने, ओवरराइड करने और संशोधित करने की अनुमति देना जारी रखना चाहते हैं


क्या यह संभव है? या मैं गलत पेड़ को काट रहा हूं?


6
यदि आप अभी भी इस विशाल ईश्वर जैसे इंटरफ़ेस पर जोर देते हैं, भले ही आप कार्यान्वयन के अलग-अलग हिस्सों पर जोर देते हैं, तो आप आधे लाभ याद कर रहे हैं। आप शॉर्टकट प्रदान कर सकते हैं, लेकिन बस चर को विभिन्न नामस्थानों में डाल सकते हैं और उन पर पूरी तरह से पुनर्निर्देशन आपको बहुत कम देता है, अगर कुछ भी।

1
@ डायलेन: ठीक है, तो आप इसके बजाय क्या सिफारिश करेंगे?
ज़रीन

जवाबों:


9

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

method A():
    self.bla += 1

method B():
    self.bla += 1

do stuff():
    self.bla = 1
    method A()
    method B()
    print self.bla

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

"गॉड ऑब्जेक्ट" स्टार्ट अप में साझा वर्ग की एक नई प्रतिलिपि बनाता है, और प्रत्येक नए उप-वर्ग अपने इनिट विधि के हिस्से के रूप में एक पॉइंटर को स्वीकार करते हैं। उदाहरण के लिए, यहाँ मेलर का एक छीन लिया गया संस्करण है:

#!/usr/bin/env python
# -*- coding: ascii -*-
'''Functions for emailing with dirMon.'''

from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders
import os
import smtplib
import datetime
import logging

class mailer:
    def __init__(self,SERVER="mail.server.com",FROM="support@server.com"):
        self.server = SERVER
        self.send_from = FROM
        self.logger = logging.getLogger('dirMon.mailer')

    def send_mail(self, send_to, subject, text, files=[]):
        assert type(send_to)==list
        assert type(files)==list
        if self.logger.isEnabledFor(logging.DEBUG):
            self.logger.debug(' '.join(("Sending email to:",' '.join(send_to))))
            self.logger.debug(' '.join(("Subject:",subject)))
            self.logger.debug(' '.join(("Text:",text)))
            self.logger.debug(' '.join(("Files:",' '.join(files))))
        msg = MIMEMultipart()
        msg['From'] = self.send_from
        msg['To'] = COMMASPACE.join(send_to)
        msg['Date'] = formatdate(localtime=True)
        msg['Subject'] = subject
        msg.attach( MIMEText(text) )
        for f in files:
            part = MIMEBase('application', "octet-stream")
            part.set_payload( open(f,"rb").read() )
            Encoders.encode_base64(part)
            part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(f))
            msg.attach(part)
        smtp = smtplib.SMTP(self.server)
        mydict = smtp.sendmail(self.send_from, send_to, msg.as_string())
        if self.logger.isEnabledFor(logging.DEBUG):
            self.logger.debug("Email Successfully Sent!")
        smtp.close()
        return mydict

यह एक बार बनाया जाता है और विभिन्न वर्गों के बीच साझा किया जाता है जिन्हें मेलिंग क्षमताओं की आवश्यकता होती है।

तो आपके लिए, larryअपनी ज़रूरत के गुणों और तरीकों के साथ एक वर्ग बनाएं । हर जगह क्लाइंट कहता है larry = blahकि इसे बदलें larryObj.larry = blah। यह वर्तमान इंटरफ़ेस को तोड़ने के बिना उप परियोजनाओं में माइग्रेट करता है।

केवल दूसरी चीज "काम की इकाइयां" की तलाश है। यदि आप "गॉड ऑब्जेक्ट" का हिस्सा बनने जा रहे हैं, तो इसका अपना तरीका है, ऐसा करें । लेकिन, इसके बाहर विधि रखो। यह आपको घटकों के बीच एक इंटरफ़ेस बनाने के लिए मजबूर करता है।

उस आधार को बिछाने से बाकी सब कुछ का पालन करने की अनुमति मिलती है। उदाहरण के लिए, हेल्पर ऑब्जेक्ट का एक टुकड़ा यह दर्शाता है कि यह मेलर के साथ कैसे इंटरफेस करता है:

#!/usr/bin/env python
'''This module holds a class to spawn various subprocesses'''
import logging, os, subprocess, time, dateAdditionLib, datetime, re

class spawner:
    def __init__(self, mailer):
        self.logger = logging.getLogger('dirMon.spawner')
        self.myMailer = mailer

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

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


1
शानदार जवाब, स्पेंसर। धन्यवाद! मेरे कुछ अनुवर्ती प्रश्न हैं जो यहां उपयुक्त होने के लिए प्रकृति में बहुत विशिष्ट हैं। क्या मुझे इन पर चर्चा करने के लिए आपसे निजी तौर पर संपर्क करना चाहिए?
ज़रीन

@Zearin सुनिश्चित करें, मेरी प्रोफ़ाइल में मेरा ईमेल पता है। हालांकि यह एक कंपनी के प्रोजेक्ट के लिए था, और मैं मालिकाना सामान की वजह से आपको रिपॉजिटरी की पूरी कॉपी नहीं दे सकता। पर्याप्त समय को देखते हुए, मैं स्नैपशॉट से पहले / बाद में सफाई कर सकता था, लेकिन मैं अनिश्चित हूं कि इससे आपको कितनी मदद मिलेगी।
स्पेंसर रथबुन

मैं आपकी प्रोफ़ाइल पर कोई ई-मेल पता नहीं देख सकता। जानकारी के सभी प्रकार है, लेकिन संपर्क जानकारी नहीं है। Contact मुझे आपसे कैसे संपर्क करना चाहिए?
ज़रीन

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