Python Type Checker Համեմատություն՝ դատարկ կոնտեյների եզրակացություն
Մեկնաբանություններ
Mewayz Team
Editorial Team
Ինչու՞ են դատարկ բեռնարկղերը կոտրում Python տեսակի ստուգիչները — և ինչ կարող եք անել դրա մասին
Python-ի աստիճանական մուտքագրման համակարգը զգալիորեն հասունացել է այն բանից հետո, երբ 2015 թվականին PEP 484-ը ներկայացրեց տիպային ակնարկներ: Այսօր միլիոնավոր ծրագրավորողներ հիմնվում են ստատիկ տիպի շաշկի վրա՝ սխալները հայտնաբերելու համար, նախքան դրանք արտադրություն կհասնեն: Բայց կա տիպային համակարգի մի նուրբ, հիասթափեցնող անկյուն, որը դեռևս շրջում է նույնիսկ փորձառու ինժեներներին. ի՞նչ տեսակ ունի դատարկ բեռնարկղը: Երբ գրում եք x = [] առանց անոտացիայի, ձեր տիպի ստուգիչը պետք է կռահի, իսկ տարբեր շաշկիներ՝ այլ կերպ: Այս տարբերությունը իրական խնդիրներ է ստեղծում կոդերի մեծ բազաներ պահպանող թիմերի համար, որտեղ տիպային ստուգիչները փոխելը կամ համակցելը կարող է հարյուրավոր անսպասելի սխալներ հայտնաբերել մեկ գիշերվա ընթացքում:
Այս հոդվածը մանրամասնում է, թե ինչպես են չորս հիմնական Python տիպի ստուգիչները՝ mypy, pyright, pytype և pyre, մշակում են դատարկ բեռնարկղերի եզրակացությունը, ինչու են նրանք համաձայն չեն, և ինչ գործնական ռազմավարություններ կարող եք ընդունել տիպի անվտանգ Python գրելու համար՝ անկախ ձեր գործիքակազմի ընտրությունից:
Հիմնական խնդիրը. դատարկ բեռնարկղերը ի սկզբանե երկիմաստ են
Դիտարկենք Python-ի այս անմեղ տողը. արդյունքներ = []: Արդյո՞ք արդյունքները ցուցակ[int] է: ցուցակ[str]? ցուցակ[dict[str, Ցանկացած]]: Առանց լրացուցիչ ենթատեքստի, իրականում հնարավոր չէ իմանալ: Python-ի գործարկման ժամանակին չի հետաքրքրում. ցուցակներն իրենց բնույթով տարասեռ են, բայց ստատիկ տիպի ստուգիչները պետք է կոնկրետ տիպ նշանակեն յուրաքանչյուր փոփոխականին՝ իրենց աշխատանքը կատարելու համար: Սա հիմնարար լարվածություն է ստեղծում Python-ի դինամիկ ճկունության և այն երաշխիքների միջև, որոնք փորձում է ապահովել ստատիկ վերլուծությունը:
Խնդիրը միանում է բառարաններին և բազմություններին: Դատարկ {}-ն իրականում վերլուծվում է որպես դիկտ, այլ ոչ թե կոմպլեկտ, որը տիպի մակարդակի երկիմաստության վրա ավելացնում է շարահյուսական երկիմաստություն: Իսկ ներկառուցված բեռնարկղերը — մտածեք defaultdict(list) կամ results = {k: [] համար k-ի համար ստեղներով — եզրակացության շարժիչները մղեք իրենց սահմաններին: Յուրաքանչյուր տեսակի ստուգիչ մշակել է իր էվրիստիկա, և տարբերություններն ավելի նշանակալի են, քան ծրագրավորողներից շատերն են պատկերացնում:
Արտադրական համակարգերում, որոնք մշակում են իրական ծանրաբեռնվածությունը, լինի դա CRM-ը, որը մշակում է հաճախորդների գրառումները, հաշիվ-ապրանքագրերի մոդուլը, որը ստեղծում է գծի տարրեր, կամ վերլուծական խողովակաշարի ագրեգացման չափանիշները, դատարկ բեռնարկղերը մշտապես հայտնվում են որպես սկզբնավորման օրինաչափություններ: Դրանց տեսակները սխալ ստանալը պարզապես չի առաջացնում ցողունային նախազգուշացումներ. այն կարող է քողարկել իրական սխալները, որոնք անցնում են գործարկման ժամանակ:
Mypy. Հետաձգված եզրակացություն անուղղակի ցանկացածով
Mypy-ը՝ Python տիպի ամենահին և լայնորեն ընդունված ստուգիչը, համեմատաբար մեղմ մոտեցում է ցուցաբերում դատարկ բեռնարկղերի նկատմամբ: Երբ գործառույթի շրջանակում հանդիպում է x = [], այն փորձում է հետաձգել տեսակի որոշումը և հետևել տարրի տեսակը հետագա օգտագործումից: Եթե գրեք x = [] որին հաջորդում է x.append(42), mypy-ը կհանգեցնի list[int]: Այս «միանալու» ռազմավարությունը զարմանալիորեն լավ է աշխատում պարզ դեպքերի համար, երբ բեռնարկղը բնակեցված է նույն շրջանակում:
Սակայն mypy-ի վարքագիծը կտրուկ փոխվում է՝ կախված համատեքստից և խստության կարգավորումներից: Մոդուլի շրջանակում (վերին մակարդակի կոդ) կամ երբ բեռնարկղը փոխանցվում է մեկ այլ գործառույթի՝ նախքան լրացվելը, mypy-ը հաճախ վերադառնում է ցուցակ[Ցանկացած]: -- խիստ դրոշի տակ սա սխալ է առաջացնում, բայց լռելյայն ռեժիմում այն լուռ անցնում է: Սա նշանակում է, որ mypy-ն առանց խիստ ռեժիմի գործարկող թիմերը կարող են կուտակել անուղղակիորեն մուտքագրված կոնտեյներներ, որոնք գործում են որպես տիպի համակարգից փախուստի ելուստ՝ խախտելով դրա նպատակը:
Հատկապես նուրբ վարքագիծ. 0.990-ից առաջ mypy տարբերակները երբեմն ենթադրում են ցուցակ[Անհայտ] ներքին, այնուհետև ընդլայնվում են ցանկում[Ցանկացած] հանձնարարությամբ: 0.990-ից հետո եզրակացությունը խստացվեց, բայց փոփոխությունը կոտրեց իրական աշխարհի կոդերի զարմանալի թվով հիմքեր, որոնք հիմնվում էին թույլատրելի վարքագծի վրա՝ առանց գիտակցելու դա: Սա կրկնվող թեմա է. դատարկ կոնտեյների եզրակացության փոփոխությունները տիպի ստուգիչի ամենախանգարող թարմացումներից են, քանի որ օրինաչափությունները շատ տարածված են:
Pyright. Խիստ եզրակացություն և «Անհայտ» տեսակ
Pyright-ը, որը մշակվել է Microsoft-ի կողմից և հզորացնելով Pylance-ը VS Code-ում, ունի հիմնովին այլ փիլիսոփայական դիրքորոշում: Փոխանակ լուռ վերադառնալու Ցանկացած-ին, pyright-ը տարբերակում է Անհայտ (տեսակ, որը դեռ որոշված չէ) և Ցանկացած (տեսակի ստուգումից բացահայտ հրաժարում): Երբ դուք գրում եք x = [] հեղինակային իրավունքի խիստ ռեժիմով, այն ենթադրում է ցուցակ[Անհայտ] և հայտնում ախտորոշման մասին՝ ստիպելով ձեզ անոտացիա տրամադրել:
Pyright-ը նաև ավելի ագրեսիվ է տրամադրված սահմանափակման հարցում: Եթե գրեք՝
- x = [] որին հաջորդում է x.append("hello") — pyright-ը ենթադրում է ցուցակ[str]
- x = [] որին հաջորդում է x.append(1), ապա x.append("hello") — pyright-ը ենթադրում է ցուցակ[int | փող]
- x = [] ուղղակիորեն փոխանցվել է ֆունկցիային, որն ակնկալում է ցուցակ[int] — pyright-ը ենթադրում է ցուցակ[int] զանգի կայքի համատեքստից
- x = [] վերադարձվել է ֆունկցիայից առանց վերադարձի տեսակի ծանոթագրության. pyright-ը հաղորդում է սխալ, այլ ոչ թե գուշակություն
Այս երկկողմանի եզրակացությունը (օգտագործելով ինչպես հետագա օգտագործումը, այնպես էլ զանգերի կայքերից սպասվող տեսակները) pyright-ը զգալիորեն ավելի ճշգրիտ է դարձնում, քան mypy-ը դատարկ բեռնարկղերի համար: Փոխզիջումը շատախոսություն է. pyright-ի խիստ ռեժիմը նշում է մոտավորապես 30-40% ավելի շատ խնդիրներ տիպիկ աննոտագրված կոդերի բազայի վրա՝ համեմատած mypy-ի խիստ ռեժիմի հետ, համաձայն մի քանի բաց կոդով միգրացիայի զեկույցների վերլուծության: Բարդ հետին համակարգեր կառուցող թիմերի համար, օրինակ՝ պլատֆորմ, որը կառավարում է 207 փոխկապակցված մոդուլներ, որոնք ներառում են CRM, աշխատավարձ և վերլուծություն, pyright-ի խստությունը գրավում է ինտերֆեյսի նուրբ անհամապատասխանությունները, որոնք թույլ չեն տալիս մեղմ եզրակացությունը:
Pytype և Pyre. The Less Travel Roads
Google-ի pytype-ը թերևս ամենապրագմատիկ մոտեցումն է ընդունում: Անոտացիաներ պահանջելու կամ Ցանկացած-ին վերադառնալու փոխարեն pytype-ն օգտագործում է ամբողջ ծրագրի վերլուծությունը՝ հետևելու, թե ինչպես է բեռնարկղը օգտագործվում ֆունկցիաների սահմաններից դուրս: Եթե մի ֆունկցիայի մեջ ստեղծեք դատարկ ցուցակ և փոխանցեք այն մեկ այլին, որը կցում է ամբողջ թվեր, pytype-ը հաճախ կարող է եզրակացնել list[int] առանց որևէ անոտացիայի: Այս խաչաձև ֆունկցիոնալ եզրակացությունը հաշվողականորեն թանկ է. pytype-ը զգալիորեն ավելի դանդաղ է, քան mypy-ը կամ pyright-ը խոշոր կոդերի բազաներում, բայց այն ավելի քիչ կեղծ դրական արդյունքներ է տալիս աննոտացված կոդի վրա:
Pytype-ը նաև ներկայացնում է «մասնակի տեսակների» հայեցակարգը դատարկ բեռնարկղերի համար: Թարմ ստեղծված []-ը ստանում է մասնակի տիպ, որն աստիճանաբար զտվում է, քանի որ ստուգիչն ավելի շատ օգտագործման է հանդիպում: Սա կոնցեպտուալ առումով էլեգանտ է, բայց կարող է առաջացնել շփոթեցնող սխալի հաղորդագրություններ, երբ մասնակի տեսակը չի կարող լիովին լուծվել, օրինակ, երբ դատարկ բեռնարկղը հոսում է մի քանի գործառույթների միջով՝ առանց երբևէ լրացվելու:
💡 DID YOU KNOW?
Mewayz replaces 8+ business tools in one platform
CRM · Invoicing · HR · Projects · Booking · eCommerce · POS · Analytics. Free forever plan available.
Start Free →Մետայի pyre-ը, միևնույն ժամանակ, ավելի մոտ է mypy-ի վարքագծին, բայց ավելի խիստ կանխադրվածներով: Pyre-ը x = []-ին վերաբերվում է որպես ցուցակ[անհայտ] և պահանջում է ծանոթագրություն շատ համատեքստում: Այն որտեղ pyre-ը տարբերվում է դատարկ բառարան բառացիների մշակման մեջ է, որն օգտագործվում է որպես կվարգ, որը տարածված օրինակ է վեբ շրջանակներում: Pyre-ն ունի հատուկ դեպքերի տրամաբանություն՝ հիմնաբառերի արգումենտների համատեքստից բառարանի տեսակները եզրակացնելու համար՝ նվազեցնելով անոտացիոն բեռը շրջանակային կոդերի մեծ բազաներում: Հաշվի առնելով, որ ժամանակակից վեբ հավելվածների մեծամասնությունը ներառում է բառարանի ապափաթեթավորման մեծ օգտագործում՝ կազմաձևման և հարցումների մշակման համար, այս պրագմատիզմը շահաբաժիններ է տալիս:
Ազդեցությունը իրական աշխարհի վրա. երբ եզրակացության տարաձայնությունները խայթում են
Տիպի ստուգիչների միջև եղած տարբերությունները կարող են ակադեմիկ թվալ, քանի դեռ դրանք չեն նկատվել արտադրության կոդերի բազայում: Դիտարկենք բիզնես հավելվածների ընդհանուր օրինաչափությունը. տվյալների կառուցվածքի սկզբնավորում, որը պայմանականորեն համալրվում է:
Ամենավտանգավոր դատարկ բեռնարկղերը այն տեսակների շաշկի դրոշակները չեն, դրանք նրանք են, որոնք անձայն անցնում են ենթադրյալ Ցանկացած տիպի հետ, ինչը թույլ է տալիս անհամատեղելի տվյալներ կուտակել առանց նախազգուշացման, մինչև գործարկման ժամանակ խափանվի ներքևի հոսքի ֆունկցիան TypeError, որը գրեթե անհնար է հետագծել իր սկզբնաղբյուրը:
Կոնկրետ օրինակ․ ֆինտեխ նորաստեղծ ընկերության թիմը հայտնել է, որ ծախսել է երեք օր՝ վրիպազերծելով արտադրության խնդիրը որտեղ դատարկ ցուցակը, որը սկզբնավորվել է վճարումների մշակման ֆունկցիայի մեջ, ենթադրվում է որպես ցանկ[Ցանկացած] mypy-ի կողմից: Ցանկը պետք է պարունակեր տասնորդական օբյեկտներ արժույթի գումարների համար, սակայն կոդի ուղին դրա փոխարեն ավելացնում էր լողացող արժեքներ: Mypy-ի մեղմ եզրակացությունը լուռ թույլ տվեց: The bug only surfaced when rounding errors in float arithmetic caused a $0.01 discrepancy on a batch of 12,000 invoices. Եթե նրանք օգտագործեին pyright խիստ ռեժիմում, կամ պարզապես նշեին դատարկ ցուցակը որպես ցուցակ[Տասնորդական], սխալը կհայտնաբերվեր մշակման ժամանակ:
Mewayz-ում, որտեղ պլատֆորմը մշակում է հաշիվ-ապրանքագրերը, աշխատավարձի հաշվարկները և ֆինանսական վերլուծությունները 138,000+ օգտատերերի հաշիվներում, այս տեսակի անվտանգության բացը տեսական չէ, դա տարբերությունն է ճիշտ աշխատավարձի հաշվարկների և ծախսատար վերահաշվարկների միջև: Կոնտեյների սկզբնավորման շուրջ մուտքագրման խիստ կարգապահությունն այն «ձանձրալի» ինժեներական պրակտիկաներից մեկն է, որը կանխում է արտադրության հետաքրքիր միջադեպերը:
Լավագույն պրակտիկա պաշտպանական բեռնարկղերի սկզբնավորման համար
Անկախ նրանից, թե որ տեսակի ստուգիչն է օգտագործում ձեր թիմը, կան կոնկրետ ռազմավարություններ դատարկ բեռնարկղերի երկիմաստությունն ամբողջությամբ վերացնելու համար: Նպատակն է երբեք չհիմնվել դատարկ բեռնարկղերի համար եզրակացությունների վրա. տիպը պարզ դարձրեք, որպեսզի ձեր կոդը շարժական լինի բոլոր ստուգիչներով և անձեռնմխելի լինի եզրակացությունների վարքագծի փոփոխություններից տարբերակների միջև:
- Միշտ նշեք դատարկ բեռնարկղի փոփոխականները: Գրեք արդյունքները՝ list[int] = [] results = [] փոխարեն: Փոքր խոսակցությունների արժեքը աննշան է՝ համեմատած խնայված վրիպազերծման ժամանակի հետ: This single practice eliminates roughly 80% of empty container inference issues.
- Օգտագործեք գործարանային գործառույթները բարդ կոնտեյներների համար: cache = {}-ի փոխարեն գրեք գործառույթ, ինչպիսին է def make_cache() -> dict[str, list[UserRecord]]. վերադարձ {}: The return type annotation makes the intended type unambiguous and self-documenting.
- Նախընտրեք տպագրված կոնստրուկտորները, քան բառացիները ոչ տրիվիալ տիպերի համար: Գրեք տարրեր՝ set[int] = set(), այլ ոչ թե հիմնվելով բազմությունների ըմբռնման եզրակացության վրա: կանխադրված և Հաշվիչ-ի համար միշտ տրամադրեք տիպի պարամետրը՝ հաշվում է՝ Counter[str] = Counter():
- Կարգավորեք ձեր տեսակի ստուգիչի խիստ ռեժիմը նոր կոդի համար: Ինչպես mypy-ը, այնպես էլ pyright-ը աջակցում են յուրաքանչյուր ֆայլի կամ գրացուցակի կազմաձևմանը: Enable strict checking on new modules while gradually migrating legacy code. This prevents the accumulation of new implicitly-typed containers.
- Ավելացրե՛ք տիպի ստուգիչ համեմատություն ձեր CI խողովակաշարին: Ձեր կոդի բազայի վրա և՛ mypy, և՛ pyright գործարկումը շուտ է հայտնաբերում եզրակացությունների տարբերությունը: Եթե օրինաչափությունն անցնում է մեկ ստուգիչ, բայց ձախողում է մյուսը, դա ազդանշան է, որ տեսակը բավականաչափ հստակ չէ:
Մեծ պատկերը. Տիպի ստուգումը որպես թիմային պրակտիկա
Դատարկ բեռնարկղերի եզրակացությունը, ի վերջո, Python-ի տիպային համակարգում ավելի մեծ մարտահրավերի միկրոկոսմ է՝ հարմարավետության և անվտանգության միջև լարվածություն: Python-ի «մենք բոլորս համաձայնում ենք մեծահասակների» փիլիսոփայությունը հիանալի է աշխատում նախատիպերի և սցենարների համար, սակայն հազարավոր օգտատերերի սպասարկող արտադրական համակարգերն ավելի ուժեղ երաշխիքների կարիք ունեն: Այն փաստը, որ չորս հիմնական տիպի ստուգիչները համաձայն չեն նույնքան հիմնական բանի շուրջ, ինչպիսին է [] տեսակը, ընդգծում է, որ Python մուտքագրման էկոհամակարգը դեռ հասունանում է:
Բարդ պլատֆորմներ կառուցող ինժեներական թիմերի համար, անկախ նրանից՝ դուք կառավարում եք մի քանի միկրոծառայություններ, թե ինտեգրված համակարգ հարյուրավոր փոխկապակցված մոդուլներով, ինչպիսին Mewayz-ի բիզնես OS-ն է, գործնական խորհուրդը պարզ է. դատարկ բեռնարկղերի համար մի հիմնվեք եզրակացությունների վրա, ընտրեք տիպի ստուգիչ և խստորեն կազմաձևեք այն, և այդ անոտացիաները վերաբերվեք որպես փաստաթղթավորման: []-ի փոխարեն ցուցակ[Invoice] գրելու ծախսած հինգ րոպեները կխնայեն ձեզ ժամեր վրիպազերծման ժամանակ, երբ ձեր կոդի բազան մասշտաբավորվի:
Քանի որ PEP 696-ը (կանխադրված տիպի պարամետրեր) և PEP 695-ը (տիպի պարամետրի շարահյուսություն) շարունակում են տեղակայվել Python-ի ավելի նոր տարբերակներում, բացահայտ մուտքագրման էրգոնոմիկան կշարունակի բարելավվել: «Ծանոթագրված» և «առանց ծանոթագրված» Python-ի միջև բացը կնվազի: Բայց մինչ այդ, բացահայտ բեռնարկղերի տեսակները մնում են Python-ի մշակողների գործիքակազմի ամենաբարձր ROI-ի պրակտիկաներից մեկը. փոքր կարգապահություն, որը վճարում է համակցված տոկոս յուրաքանչյուր մոդուլի, յուրաքանչյուր սպրինտի և արտադրության յուրաքանչյուր տեղակայման համար:
Կառուցեք ձեր բիզնեսի OS այսօր
Ֆրիլանսերներից մինչև գործակալություններ, Mewayz-ը 207 ինտեգրված մոդուլներով ապահովում է 138000+ բիզնես: Սկսեք անվճար, նորացրեք, երբ աճեք:
Անվճար ստեղծելWe use cookies to improve your experience and analyze site traffic. Cookie Policy