Main () neden kısa olmalıdır?


87

9 yılı aşkın bir süredir programlama yapıyorum ve ilk programlama öğretmenimin tavsiyesine göre, main()fonksiyonumu her zaman çok kısa tutuyorum.

İlk başta nedenini bilmiyordum. Ben sadece profesörlerimin zevkine, anlamadan itaat ettim.

Tecrübe kazandıktan sonra, kodumu doğru tasarladıysam, kısa bir main()fonksiyona sahip olmanın sadece sortof olduğunu gördüm . Modüler kod yazımı ve tek sorumluluk ilkesini izleyerek kodumun "demet" olarak tasarlanmasına izin verildi main()ve programın çalışmasını sağlamak için bir katalizörden başka bir şey olmadı.

Birkaç hafta önce hızlı bir şekilde ileriye doğru, Python'un kullanım koduna bakıyordum ve main()işlevi buldum :

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

...

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

Yay pitonu. Kısa main()işlev == İyi kod.

Programlama öğretmenleri haklıydı.

Daha derinlere bakmak istiyorum, Py_Main'e bir göz attım. Bütününde şöyle tanımlanır:

/* 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;
}

Yüce Tanrı ... ... Titanik'i batırmaya yetecek kadar büyük.

Python "Programlama 101'e Giriş" hilesini yaptı ve tüm main()kodlarını "ana" ile benzer bir şey olarak adlandırılan farklı bir işleve taşıdı .

İşte benim sorum: Bu kod çok mu yazıldı, yoksa kısa bir ana işlevi olması için başka sebepler var mı?

Şu anda olduğu gibi, bunu yapmakla sadece kodu Py_Main()geri taşımak arasında kesinlikle bir fark görmüyorum main(). Bunu düşünmekte yanlış mıyım?


4
codereviews.stackexchange.com için daha iyi olmaz mıydı ?
foobar

38
@Luzhin, hayır. Kimseden Python'un kaynak kodunu incelemesini istemiyorum. Bu programlama sorusudur.
riwalk,

3
TBH, kodun yarısı seçenek işlemesi ve programınız birçok seçeneği desteklediğinde ve özel bir işlemci yazdığınızda, yaptığınız şey budur ...
Nim

7
@ Star No, Programcılar. En iyi uygulamalar, kodlama stilleri vb. İçin de geçerlidir. Aslında, siteyi bunun için ziyaret ediyorum.
Mateen Ulhaq

4
@Nim, bunu ne yaptığını anlıyorum ama olarak yazmak için hiçbir neden yoktur options = ParseOptionFlags(argc,argv)nerede optionsbir olduğunu structdeğişkenleri içeren Py_BytesWarningFlag, Py_DebugFlagvb ...
riwalk

Yanıtlar:


137

mainBir kütüphaneden dışa aktaramazsınız , ancak dışa aktarabilirsiniz Py_Mainve daha sonra bu kütüphaneyi kullanan herkes aynı programda farklı argümanlarla Python'u birçok kez "arayabilir". Bu noktada, pythonkütüphane işlevi için bir sarıcıdan biraz daha fazlası olan kütüphanenin bir başka tüketicisi haline gelir; Py_Maintıpkı herkes gibi çağırıyor .


1
Güzel bir cevap var.
riwalk,

26
Sanırım içe aktaramayacağınızı söylemek daha doğru olabilir , @Shoosh. C ++ standardı onu kendi kodunuzdan çağırmayı yasaklar. Ayrıca, bağlantısı uygulama tarafından tanımlanmıştır. Ayrıca, genellikle bir kütüphanenin yapmasını istemediğiniz mainaramalardan etkili bir şekilde geri dönme exit.
Rob Kennedy,

3
@Coder, bakınız C ++ 03 §3.6.1 / 5: "Bir return ifadesi main, ana fonksiyondan ayrılma ... ve exitargüman olarak dönüş değeri ile çağrılma etkisine sahiptir ." Ayrıca, “statik depolama süresine sahip nesnelerin imha edildiğini” ve “tüm açık C akışlarının… temizlendiğini” açıklayan §18.3 / 8'e bakınız exit. C99 benzer bir dile sahip.
Rob Kennedy,

1
@Coder, exityaprakların mainönemi olup olmadığını Davranışlarını tartışmıyoruz exit. Davranışlarını tartışıyoruz main. Ve davranışı main içerir davranışını exitolabilir ne olursa olsun,. Budur istenmeyen ithalat ve aramaya kılan main(böyle bir şey yaptığını olası veya izin verilen hatta ise).
Rob Kennedy,

3
@Coder, geri dönme derleyicinizi mainçağırmanın etkisine exitsahip değilse, derleyiciniz standarda uymaz. Standart böyle bir davranış dikte İşte için mainorada olduğunu kanıtlar olduğunu bu konuda özel bir şey. Özel olan şey main, ondan geri dönmenin çağrı etkisine sahip olmasıdır exit. (Bu nasıl derleyici yazarlara kalmış? Derleyici, statik nesneleri yok eden, atexityordamları çağıran , dosyaları temizleyen ve programı sonlandıran işlev epilogunda basitçe kod ekleyebilir , bu da yine bir kütüphanede istediğiniz bir şey değildir .)
Rob Kennedy

42

Ondan değil mainkaçınmalısınız sürece çok olmamalıdır herhangi Çok uzun olacak işlevi. mainsadece özel bir fonksiyon örneğidir. Daha uzun fonksiyonlar grok yapmak çok zorlaşır, sürdürebilirliği azaltır ve genellikle çalışması daha zordur. İşlevleri (ve main) kısaltarak, genellikle kodunuzun kalitesini iyileştirirsiniz.

Örneğinizde, kodun dışına çıkarılmasının hiçbir faydası yoktur main.


9
Altın kelime "yeniden" olabilir. Uzun bir süre mainçok tekrar kullanılamaz.
S.Lott

1
@ S - Bu bir altın kelime. Başka bir OMG !!! DEHB SADECE BAŞLADI !!!! veya meslekten olmayan terimlerle: okunabilirlik.
Edward Strange

3
main () ayrıca diğer fonksiyonların sahip olmadığı bazı kısıtlamalara da sahiptir.
Martin York,

1
Ayrıca main () 'in gerçek anlamı yoktur. Kodunuz, başka bir programcı için bir anlam ifade etmelidir. Argümanları ayrıştırmak için main'i kullanırım ve hepsi bu kadar - hatta birkaç satırdan fazlaysa bunu bile devrederim.
Bill K,

@Bill K: Sadece (argümanları ayrıştırmak için argümanları kullanmak) main () kullanmak (ve programın geri kalanını başlatmak) aynı zamanda tek sorumluluk ilkesine de uyar.
Giorgio

28

Kısaltmanın bir nedeni main(), birim testidir. main()birim test edilemeyen bir fonksiyondur, bu nedenle davranışın büyük bölümünü birim test edilebilecek başka bir sınıfa çıkarmak mantıklıdır. Bu söylediklerinle devam ediyor

Modüler kod yazımı ve tek sorumluluk ilkesinin izlenmesi, kodumun "demet" olarak tasarlanmasına izin verdi ve main (), programın çalışmasını sağlamak için bir katalizörden başka bir şey değildi.

Not: Fikri buradan aldım .


Başka bir tane daha iyi. Bu yönü hiç düşünmedim.
riwalk,

16

Nadiren mainuzun olması iyi bir fikirdir ; gibi herhangi uzun olursa fonksiyonu (veya yöntemle) muhtemelen üstlenmeden için fırsatlar kaçırıyoruz.

Yukarıda bahsettiğiniz özel durumda main, kısa, çünkü tüm bu karmaşıklık hesaba katılmıştır Py_Main; Kodunuzun bir python kabuğu gibi davranmasını istiyorsanız, bu kodu sadece çok fazla uğraşmadan kullanabilirsiniz. (Böyle bir faktöre sahip olmalı çünkü mainbir kütüphaneye yerleştirirseniz iyi çalışmaz ; eğer yaparsanız garip şeyler olur.)

EDIT:
Açıklığa kavuşturmak mainiçin statik bir kütüphanede olamaz çünkü kendisine açık bir bağlantısı yoktur ve bu nedenle doğru şekilde bağlanmayacaktır (bir nesne dosyasında, sadece korkunç olan bir nesneyle birlikte konumlandırmadığınız sürece) !) Paylaşılan kütüphanelere genellikle benzer olduğu düşünülür (yine, karışıklığı önlemek için), birçok platformda ek bir faktör, paylaşılan bir kütüphanenin önyükleme bölümü olmayan ( mainyalnızca en son ve en görünür kısım olan) önyükleme bölümü olmayan bir çalıştırılabilir olmasıdır. ).


1
Kısacası, mainbir kütüphaneye koyma . Ya işe yaramaz ya da sizi çok şaşırtır. Ama bir işleve neredeyse tüm çalışmalarını devrederek olan bir lib, sık sık mantıklı.
Donal Fellows,

6

Ana, herhangi bir fonksiyonun kısa olması gerektiği için aynı şekilde kısa olmalıdır. İnsan beyni, büyük miktarda bölümlenmemiş veriyi bir kerede bellekte tutmakta zorlanıyor. Mantıklı parçalara ayırın, böylece diğer geliştiricilerin (hem de kendinizin de!) Hazmetmesi ve akla gelmesi kolaydır.

Ve evet, örneğinizin bakımı tek başına bırakması korkunç ve okunması zor.


Evet, her zaman kodun kendisinin çok kötü olduğundan şüphelendim (soru kodun değil, kodun yerleştirilmesiyle ilgiliydi). Korkarım ki Python vizyonum sonuçta doğası gereği zarar görmüş ...
riwalk

1
@stargazer: Kodun berbat olduğunu bilmiyorum, sadece insan tüketimi için iyi organize edilmemiş. Bu, orada iyi çalışan ve harika bir performans sergileyen bir sürü "çirkin" kod olduğunu söyledi. Kod güzelliği her şey değildir, ancak mümkün olan en temiz kodu yazmak için her zaman elimizden gelenin en iyisini yapmalıyız.
Ed S.

meh. Bana göre onlar bir ve aynı. Temiz kod daha kararlı olma eğilimindedir.
riwalk

Kod korkunç değil, temelde anahtar durumları ve çoklu platformların kullanımı var. Tam olarak ne korkunç buluyorsun?
Francesco

@Francesco: Üzgünüz, "Korkunç" bir bakım ve okunabilirlik bakış açısından, işlevsel değil.
Ed S.

1

Bazı insanlar başka hiçbir şey yapmayan 50+ işlevden hoşlanır, ancak başka bir işleve bir çağrı gönderir. Ana program mantığını yapan normal ana fonksiyonu tercih ederim. Elbette iyi yapılandırılmış.

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

Bunların hiçbirini bir ambalajın içine sarmamın nedenini anlamıyorum.

Bu tamamen kişisel bir lezzet.


1
Çünkü bu belge kod. Hemen hemen hiç yorum yazmanıza gerek kalmadan kodunuzu bu şekilde yazabilirsiniz. Ve kodu değiştirdiğinizde, belgeler otomatik olarak değişir :-).
Oliver Weiler,

1

TÜM fonksiyonlarınızı kısa tutmak için en iyisidir, sadece ana değil. Ancak "kısa" özneldir, programınızın boyutuna ve kullandığınız dile bağlıdır.


0

mainKodlama standartları dışında, herhangi bir uzunlukta olma zorunluluğu yoktur . maindiğerleri gibi bir fonksiyondur ve karmaşıklığı 10'un altında olmalıdır (veya kodlama standartlarınız ne olursa olsun). İşte bu, her şey oldukça tartışmalı.

Düzenle

mainkısa olmamalı Ya da uzun. Tasarımınıza göre gerçekleştirmesi gereken işlevselliği içermeli ve kodlama standartlarına uymalıdır.

Sorunuzdaki özel koda gelince - evet, çirkin.

İkinci sorunuza gelince - evet, yanılıyorsunuz . Tüm bu kodu tekrar ana haline getirmek Py_Main, dışarıdan bağlayarak modüler bir kütüphane olarak kullanmanıza izin vermez .

Şimdi temiz miyim?


Bunun olup olmadığını sormadım olabilir uzun. Neden uzun olmasın diye sordum .
riwalk,

“10'un altındaki karmaşıklık”? Bunun için bir ölçü birimi var mı?
Donal Fellows,

@ Stargazer712 İşlev uzunluğu genellikle kodlama standartları tarafından da düzenlenir. Bu bir okunabilirlik meselesidir (ve karmaşıklık, genellikle uzun fonksiyonlar dallıdır, böylece karmaşıklık 20'nin üzerindedir) ve dediğim gibi - mainbu konuda başka herhangi bir fonksiyondan farklı değildir.
littleadv

@ Donal - evet, bağlantıya tıklayın.
littleadv

Bu tomurcuktan oy kullanmam gerekecek. Sorunun amacını tamamen kaçırıyorsunuz.
riwalk,

0

İşte yeni bir pragmatik bir neden de kısa ana tutmandır GCC 4.6.1 Changelog :

Bölüm desteği olan çoğu hedefte, yalnızca başlangıçta kullanılan işlevler (statik yapıcılar ve ana ), yalnızca çıkışta kullanılan işlevler ve soğuk algılandığı işlevler ayrı metin segmenti alt bölümlerine yerleştirilir . Bu, -freorder-function özelliğini genişletir ve aynı anahtar tarafından kontrol edilir. Amaç, büyük C ++ programlarının başlangıç ​​zamanını iyileştirmektir.

Vurgulama benim tarafımdan eklendi.


0

Bir yazılımın biraz iyi olduğundan, o yazılımın arkasındaki tüm kodların iyi olduğunu varsaymayın. İyi yazılım ve iyi kod aynı değildir ve iyi yazılımın iyi kodla desteklendiği yerlerde bile, büyük bir projede standartların kaydığı yerler olması kaçınılmazdır.

Kısa bir mainişleve sahip olmak iyi bir uygulamadır , fakat bu genel kuralın kısa bir işleve sahip olmasının daha iyi olacağı konusunda gerçekten özel bir durumdur. Kısa fonksiyonların anlaşılması ve hata ayıklaması daha kolaydır ve aynı zamanda programları daha anlamlı hale getiren 'tek amaçlı' tasarıma yapışmakta daha iyidir. mainbelki de, kurallara sadık kalmak için daha önemli bir yer, çünkü programı anlamak isteyen herhangi mainbiri, kod tabanının daha karanlık köşeleri daha az ziyaret edilebildiği zaman anlamak zorundadır .

Ancak, Python kod temeli Py_Mainbu kuralı oynamak için kodu zorlamaz, ancak mainbir kütüphaneden dışa aktaramazsınız ya da işlev olarak adlandırmazsınız.


-1

Yukarıda birkaç teknik cevap var, bunu bir kenara bırakalım.

Bir ana kısa olmalı çünkü bir önyükleme olmalı. Temel, işi yapan az sayıda nesneyi örneklemelidir. Her yerde olduğu gibi, bu nesneler iyi tasarlanmış, uyumlu, gevşek bir şekilde bağlı, kapsüllenmiş, ...

Tek satırlık bir ana şebekeye başka bir canavar yöntemi çağırmak için teknik nedenler olsa da, prensipte haklısınız. Yazılım mühendisliği açısından bakıldığında hiçbir şey kazanılmamıştır. Seçim, bir canavar yöntemi olarak adlandırılan bir satır ana ile bir canavar yöntemi olarak adlandırılan şey arasındaysa, ikincisi kesirli olarak daha az kötüdür.


"C ++ kodunun nesneleri ve yalnızca nesneleri kullanması gerektiğini" varsayıyorsunuz. Bu doğru değil, C ++ bir çok paradigma dilidir ve her şeyi diğer diller gibi OO kalıbına zorlamaz.
Ben Voigt
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.