मुख्य () छोटा क्यों होना चाहिए?


87

मैं 9 से अधिक वर्षों से प्रोग्रामिंग कर रहा हूं, और मेरे पहले प्रोग्रामिंग शिक्षक की सलाह के अनुसार, मैं हमेशा अपने main()कार्य को बहुत छोटा रखता हूं ।

पहले तो मुझे अंदाजा नहीं था कि क्यों। मैं सिर्फ समझ के बिना, अपने प्रोफेसरों की खुशी के लिए बहुत कुछ किया।

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

कुछ हफ़्ते पहले तेजी से, मैं पायथन के सूइस कोड को देख रहा था, और मुझे यह पता चला main():

/* Minimal main program -- everything is loaded from the library */

...

int
main(int argc, char **argv)
{
    ...
    return Py_Main(argc, argv);
}

याय अजगर। लघु main()समारोह == अच्छा कोड।

प्रोग्रामिंग शिक्षक सही थे।

गहराई से देखना चाहते हैं, मैंने Py_Main पर एक नज़र डाली। इसकी संपूर्णता में, इसे निम्नानुसार परिभाषित किया गया है:

/* Main program */

int
Py_Main(int argc, char **argv)
{
    int c;
    int sts;
    char *command = NULL;
    char *filename = NULL;
    char *module = NULL;
    FILE *fp = stdin;
    char *p;
    int unbuffered = 0;
    int skipfirstline = 0;
    int stdin_is_interactive = 0;
    int help = 0;
    int version = 0;
    int saw_unbuffered_flag = 0;
    PyCompilerFlags cf;

    cf.cf_flags = 0;

    orig_argc = argc;           /* For Py_GetArgcArgv() */
    orig_argv = argv;

#ifdef RISCOS
    Py_RISCOSWimpFlag = 0;
#endif

    PySys_ResetWarnOptions();

    while ((c = _PyOS_GetOpt(argc, argv, PROGRAM_OPTS)) != EOF) {
        if (c == 'c') {
            /* -c is the last option; following arguments
               that look like options are left for the
               command to interpret. */
            command = (char *)malloc(strlen(_PyOS_optarg) + 2);
            if (command == NULL)
                Py_FatalError(
                   "not enough memory to copy -c argument");
            strcpy(command, _PyOS_optarg);
            strcat(command, "\n");
            break;
        }

        if (c == 'm') {
            /* -m is the last option; following arguments
               that look like options are left for the
               module to interpret. */
            module = (char *)malloc(strlen(_PyOS_optarg) + 2);
            if (module == NULL)
                Py_FatalError(
                   "not enough memory to copy -m argument");
            strcpy(module, _PyOS_optarg);
            break;
        }

        switch (c) {
        case 'b':
            Py_BytesWarningFlag++;
            break;

        case 'd':
            Py_DebugFlag++;
            break;

        case '3':
            Py_Py3kWarningFlag++;
            if (!Py_DivisionWarningFlag)
                Py_DivisionWarningFlag = 1;
            break;

        case 'Q':
            if (strcmp(_PyOS_optarg, "old") == 0) {
                Py_DivisionWarningFlag = 0;
                break;
            }
            if (strcmp(_PyOS_optarg, "warn") == 0) {
                Py_DivisionWarningFlag = 1;
                break;
            }
            if (strcmp(_PyOS_optarg, "warnall") == 0) {
                Py_DivisionWarningFlag = 2;
                break;
            }
            if (strcmp(_PyOS_optarg, "new") == 0) {
                /* This only affects __main__ */
                cf.cf_flags |= CO_FUTURE_DIVISION;
                /* And this tells the eval loop to treat
                   BINARY_DIVIDE as BINARY_TRUE_DIVIDE */
                _Py_QnewFlag = 1;
                break;
            }
            fprintf(stderr,
                "-Q option should be `-Qold', "
                "`-Qwarn', `-Qwarnall', or `-Qnew' only\n");
            return usage(2, argv[0]);
            /* NOTREACHED */

        case 'i':
            Py_InspectFlag++;
            Py_InteractiveFlag++;
            break;

        /* case 'J': reserved for Jython */

        case 'O':
            Py_OptimizeFlag++;
            break;

        case 'B':
            Py_DontWriteBytecodeFlag++;
            break;

        case 's':
            Py_NoUserSiteDirectory++;
            break;

        case 'S':
            Py_NoSiteFlag++;
            break;

        case 'E':
            Py_IgnoreEnvironmentFlag++;
            break;

        case 't':
            Py_TabcheckFlag++;
            break;

        case 'u':
            unbuffered++;
            saw_unbuffered_flag = 1;
            break;

        case 'v':
            Py_VerboseFlag++;
            break;

#ifdef RISCOS
        case 'w':
            Py_RISCOSWimpFlag = 1;
            break;
#endif

        case 'x':
            skipfirstline = 1;
            break;

        /* case 'X': reserved for implementation-specific arguments */

        case 'U':
            Py_UnicodeFlag++;
            break;
        case 'h':
        case '?':
            help++;
            break;
        case 'V':
            version++;
            break;

        case 'W':
            PySys_AddWarnOption(_PyOS_optarg);
            break;

        /* This space reserved for other options */

        default:
            return usage(2, argv[0]);
            /*NOTREACHED*/

        }
    }

    if (help)
        return usage(0, argv[0]);

    if (version) {
        fprintf(stderr, "Python %s\n", PY_VERSION);
        return 0;
    }

    if (Py_Py3kWarningFlag && !Py_TabcheckFlag)
        /* -3 implies -t (but not -tt) */
        Py_TabcheckFlag = 1;

    if (!Py_InspectFlag &&
        (p = Py_GETENV("PYTHONINSPECT")) && *p != '\0')
        Py_InspectFlag = 1;
    if (!saw_unbuffered_flag &&
        (p = Py_GETENV("PYTHONUNBUFFERED")) && *p != '\0')
        unbuffered = 1;

    if (!Py_NoUserSiteDirectory &&
        (p = Py_GETENV("PYTHONNOUSERSITE")) && *p != '\0')
        Py_NoUserSiteDirectory = 1;

    if ((p = Py_GETENV("PYTHONWARNINGS")) && *p != '\0') {
        char *buf, *warning;

        buf = (char *)malloc(strlen(p) + 1);
        if (buf == NULL)
            Py_FatalError(
               "not enough memory to copy PYTHONWARNINGS");
        strcpy(buf, p);
        for (warning = strtok(buf, ",");
             warning != NULL;
             warning = strtok(NULL, ","))
            PySys_AddWarnOption(warning);
        free(buf);
    }

    if (command == NULL && module == NULL && _PyOS_optind < argc &&
        strcmp(argv[_PyOS_optind], "-") != 0)
    {
#ifdef __VMS
        filename = decc$translate_vms(argv[_PyOS_optind]);
        if (filename == (char *)0 || filename == (char *)-1)
            filename = argv[_PyOS_optind];

#else
        filename = argv[_PyOS_optind];
#endif
    }

    stdin_is_interactive = Py_FdIsInteractive(stdin, (char *)0);

    if (unbuffered) {
#if defined(MS_WINDOWS) || defined(__CYGWIN__)
        _setmode(fileno(stdin), O_BINARY);
        _setmode(fileno(stdout), O_BINARY);
#endif
#ifdef HAVE_SETVBUF
        setvbuf(stdin,  (char *)NULL, _IONBF, BUFSIZ);
        setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
        setvbuf(stderr, (char *)NULL, _IONBF, BUFSIZ);
#else /* !HAVE_SETVBUF */
        setbuf(stdin,  (char *)NULL);
        setbuf(stdout, (char *)NULL);
        setbuf(stderr, (char *)NULL);
#endif /* !HAVE_SETVBUF */
    }
    else if (Py_InteractiveFlag) {
#ifdef MS_WINDOWS
        /* Doesn't have to have line-buffered -- use unbuffered */
        /* Any set[v]buf(stdin, ...) screws up Tkinter :-( */
        setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
#else /* !MS_WINDOWS */
#ifdef HAVE_SETVBUF
        setvbuf(stdin,  (char *)NULL, _IOLBF, BUFSIZ);
        setvbuf(stdout, (char *)NULL, _IOLBF, BUFSIZ);
#endif /* HAVE_SETVBUF */
#endif /* !MS_WINDOWS */
        /* Leave stderr alone - it should be unbuffered anyway. */
    }
#ifdef __VMS
    else {
        setvbuf (stdout, (char *)NULL, _IOLBF, BUFSIZ);
    }
#endif /* __VMS */

#ifdef __APPLE__
    /* On MacOS X, when the Python interpreter is embedded in an
       application bundle, it gets executed by a bootstrapping script
       that does os.execve() with an argv[0] that's different from the
       actual Python executable. This is needed to keep the Finder happy,
       or rather, to work around Apple's overly strict requirements of
       the process name. However, we still need a usable sys.executable,
       so the actual executable path is passed in an environment variable.
       See Lib/plat-mac/bundlebuiler.py for details about the bootstrap
       script. */
    if ((p = Py_GETENV("PYTHONEXECUTABLE")) && *p != '\0')
        Py_SetProgramName(p);
    else
        Py_SetProgramName(argv[0]);
#else
    Py_SetProgramName(argv[0]);
#endif
    Py_Initialize();

    if (Py_VerboseFlag ||
        (command == NULL && filename == NULL && module == NULL && stdin_is_interactive)) {
        fprintf(stderr, "Python %s on %s\n",
            Py_GetVersion(), Py_GetPlatform());
        if (!Py_NoSiteFlag)
            fprintf(stderr, "%s\n", COPYRIGHT);
    }

    if (command != NULL) {
        /* Backup _PyOS_optind and force sys.argv[0] = '-c' */
        _PyOS_optind--;
        argv[_PyOS_optind] = "-c";
    }

    if (module != NULL) {
        /* Backup _PyOS_optind and force sys.argv[0] = '-c'
           so that PySys_SetArgv correctly sets sys.path[0] to ''
           rather than looking for a file called "-m". See
           tracker issue #8202 for details. */
        _PyOS_optind--;
        argv[_PyOS_optind] = "-c";
    }

    PySys_SetArgv(argc-_PyOS_optind, argv+_PyOS_optind);

    if ((Py_InspectFlag || (command == NULL && filename == NULL && module == NULL)) &&
        isatty(fileno(stdin))) {
        PyObject *v;
        v = PyImport_ImportModule("readline");
        if (v == NULL)
            PyErr_Clear();
        else
            Py_DECREF(v);
    }

    if (command) {
        sts = PyRun_SimpleStringFlags(command, &cf) != 0;
        free(command);
    } else if (module) {
        sts = RunModule(module, 1);
        free(module);
    }
    else {

        if (filename == NULL && stdin_is_interactive) {
            Py_InspectFlag = 0; /* do exit on SystemExit */
            RunStartupFile(&cf);
        }
        /* XXX */

        sts = -1;               /* keep track of whether we've already run __main__ */

        if (filename != NULL) {
            sts = RunMainFromImporter(filename);
        }

        if (sts==-1 && filename!=NULL) {
            if ((fp = fopen(filename, "r")) == NULL) {
                fprintf(stderr, "%s: can't open file '%s': [Errno %d] %s\n",
                    argv[0], filename, errno, strerror(errno));

                return 2;
            }
            else if (skipfirstline) {
                int ch;
                /* Push back first newline so line numbers
                   remain the same */
                while ((ch = getc(fp)) != EOF) {
                    if (ch == '\n') {
                        (void)ungetc(ch, fp);
                        break;
                    }
                }
            }
            {
                /* XXX: does this work on Win/Win64? (see posix_fstat) */
                struct stat sb;
                if (fstat(fileno(fp), &sb) == 0 &&
                    S_ISDIR(sb.st_mode)) {
                    fprintf(stderr, "%s: '%s' is a directory, cannot continue\n", argv[0], filename);
                    fclose(fp);
                    return 1;
                }
            }
        }

        if (sts==-1) {
            /* call pending calls like signal handlers (SIGINT) */
            if (Py_MakePendingCalls() == -1) {
                PyErr_Print();
                sts = 1;
            } else {
                sts = PyRun_AnyFileExFlags(
                    fp,
                    filename == NULL ? "<stdin>" : filename,
                    filename != NULL, &cf) != 0;
            }
        }

    }

    /* Check this environment variable at the end, to give programs the
     * opportunity to set it from Python.
     */
    if (!Py_InspectFlag &&
        (p = Py_GETENV("PYTHONINSPECT")) && *p != '\0')
    {
        Py_InspectFlag = 1;
    }

    if (Py_InspectFlag && stdin_is_interactive &&
        (filename != NULL || command != NULL || module != NULL)) {
        Py_InspectFlag = 0;
        /* XXX */
        sts = PyRun_AnyFileFlags(stdin, "<stdin>", &cf) != 0;
    }

    Py_Finalize();
#ifdef RISCOS
    if (Py_RISCOSWimpFlag)
        fprintf(stderr, "\x0cq\x0c"); /* make frontend quit */
#endif

#ifdef __INSURE__
    /* Insure++ is a memory analysis tool that aids in discovering
     * memory leaks and other memory problems.  On Python exit, the
     * interned string dictionary is flagged as being in use at exit
     * (which it is).  Under normal circumstances, this is fine because
     * the memory will be automatically reclaimed by the system.  Under
     * memory debugging, it's a huge source of useless noise, so we
     * trade off slower shutdown for less distraction in the memory
     * reports.  -baw
     */
    _Py_ReleaseInternedStrings();
#endif /* __INSURE__ */

    return sts;
}

अच्छा भगवान सर्वशक्तिमान ... यह टाइटैनिक को डूबाने के लिए काफी बड़ा है।

ऐसा लगता है मानो पायथन ने "इन्ट्रो टू प्रोग्रामिंग 101" ट्रिक को अंजाम दिया और बस main()एक अलग फ़ंक्शन के सभी कोड को स्थानांतरित कर दिया, इसे "मुख्य" के समान कुछ कहा जाता है।

यहाँ मेरा प्रश्न है: क्या यह कोड बहुत लिखा गया है, या इसके कुछ अन्य कारण भी हैं जिनका मुख्य कार्य छोटा है?

जैसा कि यह अभी खड़ा है, मुझे ऐसा करने और बस कोड को Py_Main()वापस में ले जाने के बीच कोई अंतर नहीं दिखता है main()। क्या मैं यह सोचने में गलत हूँ?


4
यह बेहतर नहीं होगा codereviews.stackexchange.com के लिए ?
फोबार

38
@ लुज़िन, नहीं। मैं किसी को भी पायथन के स्रोत कोड की समीक्षा करने के लिए नहीं कह रहा हूं। यह प्रोग्रामिंग प्रश्न है।
रिवल

3
टीबीएच, आधा कोड विकल्प प्रसंस्करण है, और कभी भी आपका कार्यक्रम बहुत सारे विकल्पों का समर्थन करता है, और आप एक कस्टम प्रोसेसर लिखते हैं, यह वही है जो आप कर रहे हैं ...
निम

7
@Star No, Programmers.SE भी सर्वोत्तम प्रथाओं, कोडिंग शैलियों आदि के लिए है। वास्तव में, यही वह है जिसके लिए मैं साइट पर जाता हूं।
मतीन उल्हाक

4
@Nim, मैं समझता हूँ कि यह क्या कर रहा है, लेकिन वहाँ के रूप में यह लिखने के लिए नहीं कोई कारण नहीं है options = ParseOptionFlags(argc,argv)जहां optionsएक है structकि चर होते हैं Py_BytesWarningFlag, Py_DebugFlag, आदि ...
riwalk

जवाबों:


137

आप mainकिसी लायब्रेरी से निर्यात नहीं कर सकते हैं , लेकिन आप निर्यात कर सकते हैं Py_Main, और फिर उस लाइब्रेरी का उपयोग करने वाला कोई भी एक ही प्रोग्राम में विभिन्न तर्कों के साथ कई बार अजगर को "कॉल" कर सकता है। उस बिंदु पर, pythonलाइब्रेरी का सिर्फ एक और उपभोक्ता बन जाता है, लाइब्रेरी फ़ंक्शन के लिए एक रैपर से थोड़ा अधिक; यह Py_Mainहर किसी की तरह कहता है।


1
एक अच्छा जवाब है।
रिवल

26
मुझे लगता है कि यह कहना अधिक सटीक हो सकता है कि आप इसे आयात नहीं कर सकते , @ घोष। C ++ मानक इसे अपने स्वयं के कोड से कॉल करने से मना करता है। इसके अलावा, इसका लिंकेज कार्यान्वयन-परिभाषित है। इसके अलावा, mainप्रभावी रूप से कॉल से लौटते हुए exit, जिसे आप आमतौर पर लाइब्रेरी नहीं करना चाहते हैं।
रोब कैनेडी

3
@ कोडर, C ++ 03 §3.6.1 / 5 देखें: "एक रिटर्न स्टेटमेंट में mainमुख्य फ़ंक्शन को छोड़ने का प्रभाव है ... और exitतर्क के रूप में रिटर्न वैल्यू के साथ कॉल करना।" जब आप कॉल करते हैं तो objects18.3 / 8 भी देखें, जो बताता है कि "स्थिर भंडारण अवधि वाली वस्तुएं नष्ट हो जाती हैं" और "सभी खुली सी धाराएँ ... बह जाती हैं" exit। C99 में समान भाषा है।
रोब कैनेडी

1
@ कोडर, चाहे exitपत्ते mainअप्रासंगिक हों। हम के व्यवहार पर चर्चा नहीं कर रहे हैं exit। हम के व्यवहार पर चर्चा कर रहे हैं main। और जो कुछ भी हो सकता है, का व्यवहार main शामिलexit है। यही कारण है कि यह आयात और कॉल करने के लिए अवांछनीय बनाता है main(यदि ऐसा करना संभव भी है या अनुमत है)।
रोब कैनेडी

3
@ कोडर, यदि आपके कंपाइलर पर mainकॉलिंग का प्रभाव नहीं पड़ता है exit, तो आपका कंपाइलर मानक का पालन नहीं करता है। मानक इस तरह के व्यवहार तय है कि के लिए mainसाबित होता है कि वहाँ है कुछ इसके बारे में विशेष। खास बात यह mainहै कि इससे लौटने पर कॉलिंग का असर पड़ता है exit। ( यह कैसे होता है कि यह कंपाइलर लेखकों पर निर्भर करता है। कंपाइलर केवल फ़ंक्शन एपिलॉग में कोड सम्मिलित कर सकता है जो स्थिर ऑब्जेक्ट्स, कॉल atexitरूटीन, फ़्लश फ़ाइलों को नष्ट कर देता है , और प्रोग्राम को समाप्त कर देता है - जो, फिर से, कुछ ऐसा नहीं है जिसे आप लाइब्रेरी में चाहते हैं ।)
रोब कैनेडी

42

ऐसा नहीं है कि mainआपको इतना लंबा नहीं होना चाहिए क्योंकि आपको किसी भी फ़ंक्शन को बहुत लंबा होने से बचना चाहिए । mainफ़ंक्शन का एक विशेष मामला है। लंबे समय तक कार्य करने के लिए बहुत मुश्किल है, स्थिरता में कमी, और आम तौर पर साथ काम करने के लिए कठिन हैं। फ़ंक्शंस (और main) को छोटा रखकर आप आमतौर पर अपने कोड की गुणवत्ता में सुधार करते हैं।

आपके उदाहरण में कोड को बाहर ले जाने में कोई लाभ नहीं है main


9
सुनहरा शब्द "पुन: उपयोग" हो सकता है। एक लंबा mainपुन: प्रयोज्य नहीं है।
S.Lott

1
@ एस - यह एक सुनहरा शब्द है। एक और OMG है !!! एडीएचडी बस में रखा गया !!!! या आम शब्दों में: सुगमता।
एडवर्ड स्ट्रेंज

3
मुख्य () में कुछ प्रतिबंध भी हैं जो अन्य कार्यों में नहीं हैं।
मार्टिन यॉर्क

1
इसके अलावा मुख्य () का कोई वास्तविक अर्थ नहीं है। आपके कोड को किसी अन्य प्रोग्रामर के लिए कुछ मतलब होना चाहिए। मैं तर्कों को पार्स करने के लिए मुख्य का उपयोग करता हूं और यही है - और मैं यह भी बताता हूं कि अगर यह कुछ लाइनों से अधिक है।
बिल के

@ बिल के: अच्छा बिंदु, मुख्य () का उपयोग केवल तर्कों (और कार्यक्रम के बाकी को शुरू करने) के लिए भी एकल-जिम्मेदारी सिद्धांत के अनुरूप है।
जियोर्जियो

28

main()शॉर्ट बनाने का एक कारण इकाई परीक्षण भी शामिल है। main()एक ऐसा फ़ंक्शन है जिसे यूनिट परीक्षण नहीं किया जा सकता है, इसलिए यह व्यवहार के बहुमत को किसी अन्य वर्ग में निकालने के लिए समझ में आता है जिसे यूनिट परीक्षण किया जा सकता है। आपने जो कहा, यह साथ जाता है

मॉड्यूलर कोड लिखना और एकल जिम्मेदारी सिद्धांत का पालन करने से मेरे कोड को "बंच" में डिज़ाइन किया जा सकता है, और मुख्य () प्रोग्राम को चलाने के लिए उत्प्रेरक से अधिक कुछ भी नहीं है।

नोट: मुझे यहाँ से आइडिया मिला ।


एक और अच्छा। उस बारे में सोचा ही नहीं।
रिवल

16

mainलंबे समय के लिए यह एक अच्छा विचार है ; किसी भी फ़ंक्शन (या विधि) के साथ के रूप में अगर यह लंबा है तो आप शायद रिफैक्टरिंग के लिए अवसरों को याद कर रहे हैं।

आपके द्वारा ऊपर उल्लेखित विशिष्ट मामले में, mainकम है क्योंकि उस सभी जटिलता को बाहर फैक्टर किया गया है Py_Main; यदि आप चाहते हैं कि आपका कोड अजगर के गोले की तरह व्यवहार करे, तो आप बस उस कोड का उपयोग कर सकते हैं, जिसके आसपास बहुत कुछ नहीं है। (यह इस तरह फैक्टर किया जाना चाहिए क्योंकि अगर आप mainलाइब्रेरी में रखते हैं तो यह अच्छी तरह से काम नहीं करता है ; यदि आप करते हैं तो अजीब चीजें होती हैं।)

संपादित करें:
स्पष्ट करने के लिए, mainएक स्थिर पुस्तकालय में नहीं हो सकता क्योंकि इसका कोई स्पष्ट लिंक नहीं है और इसलिए इसे सही तरीके से लिंक नहीं किया जाएगा (जब तक कि आप इसे किसी ऑब्जेक्ट फ़ाइल में कॉलोकेट नहीं करते हैं, जिसे संदर्भित किया जाता है, जो सिर्फ भयानक है !) साझा पुस्तकालयों को आमतौर पर समान (फिर से, भ्रम को रोकने के लिए) के रूप में माना जाता है, हालांकि बहुत सारे प्लेटफार्मों पर एक अतिरिक्त कारक यह है कि एक साझा पुस्तकालय केवल बूटस्ट्रैप अनुभाग के बिना एक निष्पादन योग्य है (जिनमें mainसे अंतिम और सबसे अधिक दृश्य भाग है )।


1
संक्षेप में, mainएक पुस्तकालय में मत डालो । यह या तो काम नहीं करेगा या यह आपको बहुत भ्रमित करेगा। लेकिन एक समारोह है कि करने के लिए लगभग सभी अपने काम सौंपने का है एक lib में, कि अक्सर समझदार है।
डोनाल्ड फेलो

6

मुख्य एक ही कारण के लिए छोटा होना चाहिए कि कोई भी कार्य छोटा होना चाहिए। मानव मस्तिष्क में एक समय में स्मृति में बड़ी मात्रा में बिना डेटा के डेटा रखने का कठिन समय होता है। इसे तार्किक क्रम में तोड़ें ताकि अन्य डेवलपर्स (साथ ही साथ!) को पचाने और इसके बारे में तर्क करने में आसानी हो।

और हां, आपका उदाहरण भयानक है और पढ़ने में कठिन है, अकेले बनाए रखें।


हां, मुझे हमेशा यह संदेह था कि कोड स्वयं भयानक था (हालांकि प्रश्न कोड के स्थान से जुड़ा था, स्वयं कोड नहीं)। मुझे डर है कि पायथन की मेरी दृष्टि एक परिणाम के रूप में स्वाभाविक रूप से क्षतिग्रस्त हो गई है ...
रिवालक

1
@stargazer: मुझे नहीं पता कि कोड स्वयं भयानक है, बस यह मानव उपभोग के लिए अच्छी तरह से व्यवस्थित नहीं है। उस ने कहा, वहाँ "बदसूरत" कोड बहुत है जो अच्छा काम करता है और शानदार प्रदर्शन करता है। कोड सौंदर्य सब कुछ नहीं है, हालांकि हमें हमेशा सबसे अच्छे कोड को लिखने की पूरी कोशिश करनी चाहिए।
एड एस।

हुंह। मेरे लिए, वे एक हैं और एक ही हैं। स्वच्छ कोड अधिक स्थिर हो जाता है।
रिवल

कोड भयानक नहीं है, मुख्य रूप से स्विच मामलों और कई प्लेटफार्मों की हैंडलिंग हैं। क्या वास्तव में आप भयानक पाते हैं?
फ्रांसेस्को

@Francesco: क्षमा करें, "रखरखाव" और पठनीयता के दृष्टिकोण से, "कार्यात्मक" नहीं।
एड एस।

1

कुछ लोग 50+ फ़ंक्शन का आनंद लेते हैं जो कुछ और नहीं करते हैं, लेकिन किसी अन्य फ़ंक्शन पर कॉल लपेटते हैं। मैं बल्कि सामान्य मुख्य कार्य को प्राथमिकता दूंगा जो मुख्य कार्यक्रम तर्क देता है। अच्छी तरह से संरचित।

int main()
{
CheckInstanceCountAndRegister();
InitGlobals();
ProcessCmdParams();
DoInitialization();
ProgramMainLoopOrSomething();
DeInit();
ClearGlobals();
UnregisterInstance();
return 0; //ToMainCRTStartup which cleans heap, etc.
}

मुझे कोई कारण नहीं दिख रहा है कि मुझे रैपर के अंदर कुछ भी लपेटना चाहिए।

यह विशुद्ध रूप से एक व्यक्तिगत स्वाद है।


1
क्योंकि यह एक कोड का दस्तावेज है। आप (लगभग) कभी भी टिप्पणी लिखने की आवश्यकता के बिना इस तरह से कोड लिख सकते हैं। और जब आप कोड बदलते हैं, तो प्रलेखन स्वचालित रूप से बदल जाता है :-)।
ओलिवर वीलर

1

अपने सभी कार्यों को छोटा रखने के लिए इसका सबसे अच्छा अभ्यास, न केवल मुख्य। हालाँकि "संक्षिप्त" व्यक्तिपरक है, यह आपके कार्यक्रम के आकार और उस भाषा पर निर्भर करता है जिसका आप उपयोग कर रहे हैं।


0

mainकोडिंग मानकों के अलावा किसी भी लम्बाई के लिए कोई आवश्यकता नहीं है । mainकिसी भी अन्य के रूप में एक समारोह है, और जैसे कि यह जटिलता 10 से नीचे होनी चाहिए (या जो भी आपके कोडिंग मानक कहते हैं)। यह बात, कुछ और नहीं बल्कि तर्क है।

संपादित करें

mainकम नहीं होना चाहिए। या लंबा है। इसमें आपके डिज़ाइन के आधार पर कार्यक्षमता की आवश्यकता होती है, और कोडिंग मानकों का पालन करना चाहिए।

आपके प्रश्न में विशिष्ट कोड के रूप में - हाँ, यह बदसूरत है।

आपके दूसरे प्रश्न के रूप में - हां, आप गलत हैं । उस सभी कोड को मुख्य में वापस ले जाने से आप इसे लाइब्रेरी Py_Mainसे बाहर से जोड़कर मॉड्यूल के रूप में उपयोग कर सकते हैं ।

अब मैं स्पष्ट हूँ?


मैंने यह नहीं पूछा कि क्या यह लंबा हो सकता है। मैंने पूछा कि यह लंबा क्यों नहीं होना चाहिए
रिवल

"10 से नीचे की जटिलता"? क्या उसके लिए एक मापक इकाई है?
डोनाल्ड फेलो

@ Stargazer712 फंक्शन की लंबाई आमतौर पर कोडिंग मानकों द्वारा विनियमित होती है। यह पठनीयता का मुद्दा है (और जटिलता, आमतौर पर लंबे कार्यों को शाखाबद्ध किया जाता है ताकि जटिलता 20 से ऊपर हो), और जैसा कि मैंने कहा - mainइस संबंध में किसी भी अन्य फ़ंक्शन से अलग नहीं है।
littleadv

@ डॉनल - हाँ, लिंक पर क्लिक करें।
littleadv

मैं इस एक कली को कम करने जा रहा हूं। आप प्रश्न के इरादे को पूरी तरह से याद कर रहे हैं।
रिवल

0

यहाँ एक नया व्यावहारिक कारण भी जीसीसी 4.6.1 चैंज से मुख्य कमी रखना :

नामित अनुभाग समर्थन के साथ अधिकांश लक्ष्यों पर, केवल स्टार्टअप पर उपयोग किए जाने वाले कार्य (स्थिर निर्माणकर्ता और मुख्य ), केवल बाहर निकलने पर उपयोग किए जाने वाले कार्य और ठंड का पता लगाने वाले कार्यों को अलग-अलग पाठ खंडों में रखा जाता है । यह -freorder-functions सुविधा का विस्तार करता है और उसी स्विच द्वारा नियंत्रित किया जाता है। लक्ष्य बड़े C ++ कार्यक्रमों के स्टार्टअप समय में सुधार करना है।

मेरे द्वारा जोड़ा गया हाइलाइटिंग।


0

यह मत मानिए कि सिर्फ इसलिए कि थोड़ा सा सॉफ्टवेयर अच्छा है, उस सॉफ्टवेयर के पीछे के सभी कोड अच्छे हैं। अच्छा सॉफ्टवेयर और अच्छा कोड एक ही बात नहीं है और यहां तक ​​कि जहां अच्छे सॉफ्टवेयर अच्छे कोड द्वारा समर्थित हैं, यह अपरिहार्य है कि एक बड़ी परियोजना में ऐसी जगहें होंगी जहां मानक फिसल जाते हैं।

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

लेकिन, पायथन कोडबेस Py_Mainइस नियम को चलाने के लिए कोड को बाहर नहीं धकेल रहा है, लेकिन क्योंकि आप mainएक पुस्तकालय से निर्यात नहीं कर सकते हैं और न ही इसे फ़ंक्शन के रूप में कह सकते हैं।


-1

ऊपर कई तकनीकी जवाब हैं, जो इसे एक तरफ छोड़ देते हैं।

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

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


आप मान रहे हैं कि "C ++ कोड को ऑब्जेक्ट और केवल ऑब्जेक्ट का उपयोग करना चाहिए"। यह सच नहीं है, C ++ एक बहुभाषी भाषा है, और कुछ अन्य भाषाओं की तरह OO मोल्ड में सब कुछ मजबूर नहीं करता है।
बेन वोइगट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.