Кіріспе

ITUniver

1
Кіріспе

Бұл тарауда сіз бірінші Python бағдарламаңызды, hello_world.py іске қосасыз. Алдымен компьютерде Python бағдарламасының соңғы нұсқасы орнатылғанын тексеру керек; олай болмаса, оны орнатасыз. Сондай-ақ Python бағдарламаларымен жұмыс істеу үшін мәтіндік редакторды орнатасыз. Мәтіндік редакторлар Python кодын таниды және сіз жазған кезде бөлімдерді бөлектейді, бұл код құрылымын түсінуді жеңілдетеді.

Бағдарламалау ортасын орнату

Python әр түрлі операциялық жүйелерде аздап ерекшеленеді, сондықтан бірнеше нәрсені есте ұстаған жөн. Келесі бөлімдерде Python жүйеңізде дұрыс орнатылғанына көз жеткіземіз.

Python нұсқалары

Жаңа идеялар мен технологиялар пайда болған сайын әрбір бағдарламалау тілі дамиды және Python әзірлеушілері тілді үнемі жан-жақты және қуатты етіп жасайды. Осы жазу кезінде ең соңғы нұсқасы Python 3.11, бірақ бұл кітаптағы барлық код Python 3.9 немесе одан кейінгі нұсқаларында жұмыс істеуі керек. Бұл бөлімде жүйеде Python орнатылғанын және жаңарақ нұсқасын орнату қажет пе екенін анықтаймыз. Қосымша А (Appendix A алда жазылып, толықтырылады) әрбір негізгі операциялық жүйеде Python бағдарламасының соңғы нұсқасын орнату туралы қосымша мәліметтерді қамтиды. (көп жағдайда оқушыларда Windows ОЖ-сі. Сондықтан бірінші кезекте сол қарастырылады және Windows-та Python-ды орнату аса күрделі емес)

Python кодының үзінділерін іске қосу

Python интерпретаторын (interpreter) терминал терезесінде іске қосуға болады, бұл сізге Python кодының бүкіл бағдарламасын сақтап, іске қосудың қажетінсіз, кішкентай код биттерін сынап көруге мүмкіндік береді.

Осы кітапта сіз келесідей код үзінділерін көресіз:


          >>> print("Hello Python interpreter!")
          Hello Python interpreter!
        

Мына үш бұрышты (>>>) белгішелер промпт, біз оны Python prompt деп атайтын боламыз, бұл сізге терминалды пайдалануыңыз керек дегенді білдіреді. Бірінші қатардағы мәтін - теріп, ENTER пернесін басу арқылы орындау керек код. Бұл кітаптағы мысалдардың көпшілігі терминалдан емес, мәтіндік редактордан іске қосылатын шағын, дербес бағдарламалар болып табылады, өйткені сіз кодтың көп бөлігін мәтіндік редакторда жазасыз. Бірақ кейде негізгі ұғымдар белгілі бір тұжырымдамаларды тиімдірек көрсету үшін Python терминал сеансы арқылы орындалатын үзінділер сериясында көрсетіледі. Кодтар тізімінде үш бұрыштық жақшаны көргенде, сіз терминал сеансының кодын және шығысын қарап жатырсыз. Кітаптың келесі бөлімдерінде жүйеңіздегі интерпретаторда кодтар жазып көреміз.

Сонымен қатар біз бағдарламалауды үйренудің негізгі құралына айналған Hello World! деп аталатын қарапайым бағдарламаны жасау үшін мәтіндік редакторды қолданамыз. Бағдарламалау әлемінде бұрыннан бір дәстүр бар: Hello world! хабарын экранға жаңа тілдегі бірінші бағдарлама ретінде басып шығару сізге сәттілік әкеледі. Мұндай қарапайым бағдарлама өте нақты мақсатқа қызмет етеді. Егер ол жүйеде дұрыс жұмыс істесе, сіз жазған кез-келген Python бағдарламасы да жұмыс істеуі керек.

VS Code мәтін редакторы (VS Code Text Editor)

VS Code - бұл тегін және бастаушыға ыңғайлы қуатты, кәсіби сапалы мәтіндік редактор. VS Code қарапайым да, күрделі де жобалар үшін тамаша, сондықтан Python тілін үйрену кезінде оны пайдалану ыңғайлы болса, үлкенірек және күрделі жобаларға өту кезінде оны пайдалануды жалғастыра аласыз. VS Code-ты барлық заманауи операциялық жүйелерге орнатуға болады және ол Python-ды қоса алғанда, басқа да көптеген бағдарламалау тілдерін қолдайды.

B қосымшасы басқа мәтін өңдегіштері туралы ақпаратты береді. Егер басқа опциялар сізді қызықтырса, осы уақытта қосымшаны қарап шығуды қалауыңыз мүмкін. Бағдарламалауды жылдам бастағыңыз келсе, бастау үшін VS Code пайдалануға болады. Бағдарламашы ретінде біраз тәжірибе жинақтағаннан кейін басқа редакторларды қарастыруға болады. Бұл тарауда мен сізге операциялық жүйеңізге VS Code орнату арқылы көрсетемін.

Python әртүрлі Операциялық жүйелерде

Python - бұл кросс-платформалық бағдарламалау тілі, яғни ол барлық негізгі операциялық жүйелерде жұмыс істейді. Сіз жазған кез-келген Python бағдарламасы Python орнатылған кез-келген заманауи компьютерде жұмыс істеуі керек. Дегенмен, әртүрлі операциялық жүйелерде Python орнату әдістері сәл өзгереді.

Бұл бөлімде жүйеде Python орнату жолын үйренесіз. Алдымен жүйеңізде Python бағдарламасының соңғы нұсқасы орнатылғанын тексеріп, егер ол орнатылмаған болса, оны орнатыңыз. Содан кейін VS Code орнатасыз. Бұл әр операциялық жүйе үшін әр түрлі болатын екі ғана қадам.

Келесі бөлімдерде hello_world.py іске қосып, жұмыс істемейтін кез-келген ақаулықты түзетіңіз. Мен сізге әр операциялық жүйе үшін осы процесті көрсетемін, осылайша сізде сенуге болатын Python бағдарламалау ортасы болады.

Windows жүйесіндегі Python

Windows әдетте Python-мен бірге келмейді, сондықтан оны орнатып, содан кейін VS Code орнату қажет болуы мүмкін.

Python орнату

Біріншіден, жүйеде Python орнатылғанын тексеріңіз. Бастау мәзіріне (Пуск) command енгізу және Command Prompt қолданбасын басу арқылы пәрмен терезесін ашыңыз. Терминал терезесінде python сөзін кіші әріппен енгізіңіз. Жауап ретінде Python шақыруын (>>>) алсаңыз, Python жүйеңізде орнатылған. python танылған пәрмен емес екенін көрсететін қате хабарын көрсеңіз немесе Microsoft дүкені ашылса, Python орнатылмаған. Егер ашылған болса, Microsoft дүкенін жабыңыз; Microsoft нұсқасын пайдаланғаннан гөрі ресми орнатушыны жүктеп алған дұрыс.

Жүйеде Python орнатылмаған болса немесе Python 3.9 нұсқасынан ертерек нұсқаны көрсеңіз, Windows жүйесіне арналған Python орнатушысын жүктеп алуыңыз қажет. https://python.org сайтына өтіп, меңзерді Downloads сілтемесінің үстіне апарыңыз. Python бағдарламасының соңғы нұсқасын жүктеп алу түймешігін көруіңіз керек. Жүйеңізге дұрыс орнатушыны автоматты түрде жүктеп алуды бастау керек түймені басыңыз. Файлды жүктеп алғаннан кейін орнатушыны іске қосыңыз. Жүйені дұрыс конфигурациялауды жеңілдететін PATH жүйесіне Python қосу опциясын таңдағаныңызға көз жеткізіңіз. 1-1-сурет таңдалған осы опцияны көрсетеді.

1-1-сурет: Add Python x.xx to PATH деп белгіленген құсбелгіні таңдағаныңызға көз жеткізіңіз.

Терминал сеансында Python іске қосу

Жаңа пәрмен терезесін ашып, python деп кіші әріппен енгізіңіз. Python шақыруын (>>>) көруіңіз керек, яғни Windows сіз орнатқан Python нұсқасын тапты.


          C:\> python
          Python 3.x.x (main, Jun . . . , 13:29:14) [MSC v.1932 64 bit (AMD64)] on win32
          Type "help", "copyright", "credits" or "license" for more information.
          >>>

Python сеансында келесі жолды енгізіңіз:


        >>> print("Hello Python interpreter!")
        Hello Python interpreter!
        >>>

Сіз Hello Python interpreter! шығысын көруіңіз керек. Python кодының үзіндісін кез-келген уақытта іске қосқыңыз келсе, пәрмен терезесін ашыңыз және Python терминал сеансын бастаңыз. Терминал сеансын жабу үшін CTRL-Z пернелерін басыңыз, содан кейін ENTER пернесін басыңыз немесе exit() пәрменін енгізіңіз.

VS Code орнату

VS Code үшін орнатушыны https://code.visualstudio.com сайтынан жүктеп алуға болады.Windows жүйесіне арналған жүктеп алу түймесін басып, орнатушыны іске қосыңыз. macOS және Linux туралы келесі бөлімдерді өткізіп жіберіп, Hello World бағдарламасын іске қосу" бөліміндегі қадамдарды орындаңыз.

Python әдепкі бойынша macOS-тың соңғы нұсқаларында орнатылмаған, сондықтан әлі орнатпаған болсаңыз, оны орнатуыңыз керек. Бұл бөлімде сіз Python бағдарламасының соңғы нұсқасын орнатасыз, содан кейін VS Code н орнатып, оның дұрыс конфигурацияланғанына көз жеткізесіз.

Python 3 орнатылғанын тексеру

Терминал терезесін ҚолданбаларУтилиталар бөліміне өту арқылы ашыңыз.Терминал. Сондай-ақ, ⌘-бос орын пернесін басып, терминал деп теріп, ENTER пернесін басуға болады. Python бағдарламасының жақында орнатылған нұсқасы бар-жоғын білу үшін python3 енгізіңіз. Сіз пәрмен жолы әзірлеуші құралдарын орнату туралы хабарды көресіз. Бұл құралдарды Python орнатқаннан кейін орнатқан дұрыс, сондықтан бұл хабар пайда болса, қалқымалы терезеден бас тартыңыз.

Егер шығыс Python 3.9 немесе одан кейінгі нұсқасы орнатылғанын көрсетсе, келесі бөлімді өткізіп жіберуге және “Терминалда Python-ды іске қосу бөліміне өтуіңізге болады. Сеанс». Python 3.9 нұсқасынан ертерек кез-келген нұсқаны көрсеңіз, соңғы нұсқаны орнату үшін келесі бөлімдегі нұсқауларды орындаңыз.

MacOS жүйесінде осы кітапта python пәрменін көрген сайын, Python 3-ті пайдаланып жатқаныңызға көз жеткізу үшін оның орнына python3 пәрменін пайдалану керек екенін ескеріңіз. Көптеген macOS жүйелерінде python пәрмені не тек ішкі жүйе құралдарымен пайдаланылуы тиіс Python бағдарламасының ескірген нұсқасын көрсетеді немесе ол ештеңені көрсетпейді және қате туралы хабарды жасайды.

Python бағдарламасының соңғы нұсқасын орнату

Жүйеңізге арналған Python орнатушысын https://python.org сайтынан таба аласыз. Меңзерді Жүктеп алу сілтемесінің үстіне апарыңыз және Python бағдарламасының соңғы нұсқасын жүктеп алу түймешігін көресіз. Жүйеңізге дұрыс орнатушыны автоматты түрде жүктеп алуды бастау керек түймені басыңыз. Файл жүктеп алғаннан кейін орнатушыны іске қосыңыз.

Орнатушы іске қосылғаннан кейін Finder терезесі пайда болуы керек. Install Certificates.command файлын екі рет басыңыз. Бұл файлды іске қосу нақты жобаларға, соның ішінде осы кітаптың екінші жартысындағы жобаларға қажет қосымша кітапханаларды оңай орнатуға мүмкіндік береді.

Терминал сеансында Python іске қосу

Енді жаңа терминал терезесін ашып, python3 теру арқылы Python кодының үзінділерін іске қосып көруге болады:

$ python3
          Python 3.x.x (v3.11.0:eb0004c271, Jun . . . , 10:03:01)
          [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
          Type "help", "copyright", "credits" or "license" for more information.
          >>>

Бұл пәрмен Python терминал сеансын бастайды. Python шақыруын (>>>) көруіңіз керек, бұл macOS жаңа ғана орнатқан Python нұсқасын тапқанын білдіреді.

Терминал сеансына келесі Тіркесті енгізіңіз:

>>> print("Hello Python interpreter!")
        Hello Python interpreter!
        >>>

Сіз ағымдағы терминал терезесінде тікелей басып шығарылатын Hello Python интерпретаторы! хабарын көруіңіз керек. Python аудармашысын CTRL-D пернесін басу немесе exit() пәрменін енгізу арқылы жабуға болады.

VS Code н орнату

VS Code өңдегішін орнату үшін орнатушыны https://code.visualstudio сайтынан жүктеп алу керек. .com. Жүктеп алу түймесін басып, Табу терезесін ашыңыз және Жүктеулер каталогына өтіңіз. Visual Studio Code орнатушысын Қолданбалар каталогына сүйреп апарыңыз, одан кейін оны іске қосу үшін орнатушыны екі рет басыңыз.

Linux жүйесінде Python туралы келесі бөлімді өткізіп жіберіп, Hello World бағдарламасын іске қосу" бөліміндегі қадамдарды орындаңыз. ="xref" itemid="xref_target_page 9">9-бет.

Linux жүйелері бағдарламалауға арналған, сондықтан Python Linux компьютерлерінің көпшілігінде орнатылған. Linux-ті жазатын және оған қызмет көрсететін адамдар сізден белгілі бір уақытта өзіңіздің бағдарламаңызды жасауыңызды күтеді және сізді осылай жасауға шақырады. Осы себепті орнатуға өте аз және бағдарламалауды бастау үшін өзгертуге болатын бірнеше параметрлер ғана бар.

Python нұсқасын тексеру

Жүйеде Терминал қолданбасын іске қосу арқылы терминал терезесін ашыңыз (Ubuntu жүйесінде CTRL-ALT-T пернелерін басуға болады). Python бағдарламасының қай нұсқасы орнатылғанын білу үшін python3 әріпін p әріпімен енгізіңіз. Python орнатылған кезде, бұл пәрмен Python аудармашысын іске қосады. Python нұсқасының қай нұсқасы орнатылғанын көрсететін шығысты көруіңіз керек. Сондай-ақ Python пәрмендерін енгізуді бастауға болатын Python сұрауын (>>>) көруіңіз керек:

$ python3
        Python 3.10.4 (main, Apr  . . . , 09:04:19) [GCC 11.2.0] on linux
        Type "help", "copyright", "credits" or "license" for more information.
        >>>

Бұл шығыс Python 3.10.4 қазіргі уақытта осы компьютерде орнатылған Python бағдарламасының әдепкі нұсқасы екенін көрсетеді. Бұл шығысты көргенде, CTRL-D пернесін басыңыз немесе Python сұрауынан шығып, терминал сұрауына оралу үшін exit() енгізіңіз. Осы кітапта python пәрменін көрген сайын оның орнына python3 енгізіңіз.

Осы кітаптағы кодты іске қосу үшін сізге Python 3.9 немесе одан кейінгі нұсқасы қажет. Жүйеде орнатылған Python нұсқасы Python 3.9 нұсқасынан ертерек болса немесе қазіргі уақытта қол жетімді соңғы нұсқаға жаңартқыңыз келсе, А қосымшасындағынұсқауларды қараңыз. span>.

Терминал сеансында Python іске қосу

Нұсқаңызды тексерген кездегідей терминалды ашып, python3 енгізу арқылы Python кодының үзінділерін іске қосып көруге болады. Мұны қайталаңыз және Python іске қосылғанда, терминал сеансына келесі Тіркесті енгізіңіз:

>>> print("Hello Python interpreter!")
        Hello Python interpreter!
        >>>

Хабар ағымдағы терминал терезесінде тікелей басып шығарылуы керек. Python аудармашысын CTRL-D пернесін басу немесе exit() пәрменін енгізу арқылы жабуға болатынын есте сақтаңыз.

VS Code-н орнату

Ubuntu Linux жүйесінде Ubuntu бағдарламалық орталығынан VS Code-н орнатуға болады. Мәзірдегі Ubuntu бағдарламалық құралы белгішесін басып, vscode іздеңіз. Visual Studio Code (кейде код деп аталады) деп аталатын қолданбаны басып, Орнату түймесін басыңыз. Ол орнатылғаннан кейін жүйеңізден VS Code н іздеп, қолданбаны іске қосыңыз.


Hello World бағдарламасын іске қосу

Python және VS Code-тың соңғы нұсқасы орнатылған болса, сіз мәтіндік редакторда жазылған алғашқы Python бағдарламаңызды іске қосуға дайынсыз. Бірақ мұны жасамас бұрын, VS Code үшін Python кеңейтімін орнату керек (install the Python extension for VS Code).

VS Code үшін Python кеңейтімін орнату

VS Code көптеген әртүрлі бағдарламалау тілдерімен жұмыс істейді; Python бағдарламашысы ретінде оны барынша пайдалану үшін сізге Python кеңейтімін орнату қажет. Бұл кеңейтім Python бағдарламаларын жазу, өңдеу және іске қосу үшін қолдауды қосады.

Python кеңейтімін орнату үшін VS Code қолданбасының төменгі сол жақ бұрышындағы тетікке ұқсайтын Басқару(Manage) белгішесін басыңыз. Пайда болған мәзірде Extenstions (Кеңейтімдер) түймесін басыңыз. Іздеу жолағына python енгізіп, Python кеңейтімін басыңыз. (Егер Python деп аталатын бірнеше кеңейтімді көрсеңіз, Microsoft ұсынған кеңейтімді таңдаңыз.) Орнату түймесін басып, орнатуды аяқтау үшін жүйеге қажет кез-келген қосымша құралдарды орнатыңыз. Python орнату керек деген хабарды көрсеңіз және оны әлдеқашан орындаған болсаңыз, бұл хабарды елемеуіңізге болады.

hello_world.py бағдарламасын іске қосу

Бірінші бағдарламаңызды жазбас бұрын, жобаларыңыз үшін жұмыс үстеліңізде python_work деп аталатын каталогты жасаңыз. Файл және каталог атауларындағы бос орындар үшін кіші әріптерді және астын сызуды қолданған дұрыс, өйткені Python осы атау конвенцияларын пайдаланады. Бұл каталогты жұмыс үстелінен басқа жерде жасауға болады, бірақ python_work каталогын тікелей жұмыс үстелінде сақтасаңыз, кейінгі қадамдарды орындау оңайырақ болады.

VS Code-ты ашыңыз не әлі ашық болса, Get Started қойындысын жабыңыз. FileNew File түймесін басу немесе CTRL-N (macOS жүйесінде ⌘-N) пернелерін басу арқылы жаңа файл жасаңыз. Файлды hello_world.py ретінде python_work каталогында сақтаңыз. .py кеңейтімі VS Code-қа файлыңыздың Python тілінде жазылғанын айтады және бағдарламаны қалай іске қосу және мәтінді пайдалы жолмен бөлектеу керектігін айтады.

hello_world.py

Файлды сақтағаннан кейін редакторға келесі жолды енгізіңіз:


        print("Hello Python world!")

Бағдарламаны іске қосу үшін RunRun Without Debugging опциясын таңдаңыз немесе CTRL-F5 пернелерін басыңыз. VS Code терезесінің төменгі жағында бағдарламаның шығысын көрсететін терминал экраны пайда болуы керек:


        Hello Python world!

Бағдарламаны іске қосу үшін пайдаланылған Python интерпретаторын көрсететін қосымша шығыстарды көресіз. Бағдарламаның нәтижесін ғана көру үшін көрсетілетін ақпаратты жеңілдеткіңіз келсе, B қосымшасын қараңыз. Сондай-ақ, VS Code-ты тиімдірек пайдалану туралы пайдалы ұсыныстарды B қосымшасынан таба аласыз.

Бұл нәтижені көрмесеңіз, бағдарламада бірдеңе дұрыс болмады. Енгізілген Тіркестегі әрбір таңбаны тексеріңіз. Сіз print-ды байқаусызда бас әріппен жаздыңыз ба? Тырнақшалардың немесе жақшалардың біреуін немесе екеуін де ұмыттыңыз ба? Бағдарламалау тілдері өте нақты синтаксисті күтеді және оны бермесеңіз, қателер аласыз. Бағдарламаны іске қоса алмасаңыз, келесі бөлімдегі ұсыныстарды қараңыз.

Егер hello_world.py қолданбасын іске қоса алмасаңыз, мұнда кез-келген бағдарламалау мәселесіне жақсы жалпы шешімдер болып табылатын бірнеше әдістерді қолданып көруге болады:

  • Бағдарламада маңызды қате болған кезде, Python қате туралы есеп болып табылатын кері бақылауды көрсетеді. Python файлды қарап шығып, мәселені анықтауға тырысады. Бақылауды тексеріңіз; ол сізге қандай мәселе бағдарламаның іске қосылуына кедергі келтіретіні туралы түсінік беруі мүмкін.
  • Компьютерден алыстап, қысқа үзіліс жасап, әрекетті қайталаңыз. Синтаксис бағдарламалауда өте маңызды екенін есте сақтаңыз, сондықтан сәйкес келмейтін тырнақшалар немесе сәйкес келмейтін жақшалар сияқты қарапайым нәрсе бағдарламаның дұрыс жұмыс істеуіне кедергі келтіруі мүмкін. Осы тараудың тиісті бөліктерін қайта оқып шығыңыз, кодты қарап шығыңыз және қатені табуға тырысыңыз.
  • Қайтадан бастаңыз. Сізге ешқандай бағдарламалық құралды жоюдың қажеті жоқ болуы мүмкін, бірақ hello_world.py файлыңызды жойып, оны нөлден қайта жасағаныңыз жөн болар.
  • Басқа біреуден осы тараудағы қадамдарды компьютерде немесе басқада орындауын сұраңыз және олардың не істеп жатқанын мұқият бақылаңыз. Басқа біреу ұстай алатын шағын қадамды жіберіп алған болуыңыз мүмкін.
  • Қосымша орнату нұсқауларын А қосымшасынан қараңыз; Қосымшадағы кейбір мәліметтер мәселені шешуге көмектесуі мүмкін.
  • Python тілін білетін адамды тауып, оны орнатуға көмектесуін сұраңыз. Егер айналаңыздан сұрасаңыз, Python тілін пайдаланатын біреуді күтпеген жерден танитыныңызды байқайсыз.
  • Осы тараудағы орнату нұсқаулары сонымен қатар https://ehmatthes.github.io мекенжайындағы осы кітаптың серіктес веб-сайтында қолжетімді. /pcc_3e. Бұл нұсқаулардың онлайн нұсқасы жақсырақ жұмыс істеуі мүмкін, себебі сіз жай ғана кодты қиып, қоюға және қажетті ресурстарға сілтемелерді басуға болады.
  • Желіде көмек сұраңыз. Қосымша С мәселемен бұрыннан жұмыс істеген адамдардан шешім сұрауға болатын форумдар мен тікелей чат сайттары сияқты бірқатар ресурстарды қамтамасыз етеді. сіз қазір қарсы тұрасыз.

Тәжірибелі бағдарламашыларды мазалайды деп ешқашан уайымдамаңыз. Әрбір бағдарламашы бір сәтте тұрып қалды және көптеген бағдарламашылар жүйені дұрыс орнатуға көмектесуге қуанышты. Сіз не істеуге тырысып жатқаныңызды, не істеп көргеніңізді және сіз алған нәтижелерді нақты айта алсаңыз, біреу сізге көмектесе алады. кіріспеде айтылғандай, Python қауымдастығы жаңадан бастаушыларға өте мейірімді және қонақжай.

Python кез-келген заманауи компьютерде жақсы жұмыс істеуі керек. Ерте орнату мәселелері көңіліңізді қалдыруы мүмкін, бірақ оларды шешуге тұрарлық. hello_world.py іске қосылғаннан кейін Python тілін үйренуге болады, сонда сіздің бағдарламалау жұмысыңыз қызықты әрі қанағаттанарлық болады.


Терминалдан Python бағдарламаларын іске қосу

Бағдарламалардың көпшілігін тікелей мәтіндік редакторда іске қосасыз. Дегенмен, кейде оның орнына терминалдан бағдарламаларды іске қосу пайдалы. Мысалы, жазылып қойған, бар бағдарламаны, редакторда ашпай-ақ бірден іске қосқыңыз келуі мүмкін.

Бағдарлама файлы сақталған каталогқа кіру жолын білсеңіз, мұны Python орнатылған кез-келген жүйеде жасауға болады. Мұны істеу үшін жұмыс үстеліңіздегі python_work каталогында hello_world.py файлын сақтағаныңызды тексеріңіз.

Windows жүйесінде

Пәрмен терезесінде файлдық жүйеде шарлау үшін каталогты өзгерту үшін cd терминал пәрменін пайдалануға болады. Каталог үшін dir пәрмені ағымдағы каталогта бар барлық файлдарды көрсетеді.

Жаңа терминал терезесін ашыңыз және hello_world.py іске қосу үшін келесі пәрмендерді енгізіңіз:


        C:\> cd Desktop\python_work
        C:\Desktop\python_work> dir
        hello_world.py
        C:\Desktop\python_work> python hello_world.py
        Hello Python world!

Біріншіден,Жұмыс үстелі каталогындағы python_work каталогына өту үшін cd пәрменін пайдаланыңыз. Одан кейін hello_world.py осы каталогта екеніне көз жеткізу үшін dir пәрменін пайдаланыңыз. Содан кейін файлды python hello_world.py пәрмені арқылы іске қосыңыз.

Бағдарламаларыңыздың көпшілігі тікелей редакторыңыздан жақсы жұмыс істейді. Дегенмен, жұмысыңыз күрделене түскен сайын, кейбір бағдарламаларды терминалдан іске қосқыңыз келеді.

Python бағдарламасын терминал сеансынан іске қосу Linux және macOS жүйелерінде бірдей. Терминал сеансында файлдық жүйеде шарлау үшін каталогты өзгерту үшін cd терминал пәрменін пайдалануға болады. list үшін ls пәрмені ағымдағы каталогта бар барлық жасырын емес файлдарды көрсетеді.

Жаңа терминал терезесін ашыңыз және hello_world.py іске қосу үшін келесі пәрмендерді енгізіңіз:

~$ cd Desktop/python_work/
        ~/Desktop/python_work$ ls
        hello_world.py
        ~/Desktop/python_work$ python3 hello_world.py
        Hello Python world!

Біріншіден, Жұмыс үстелі каталогындағы python_work каталогына өту үшін cd пәрменін пайдаланыңыз. Одан кейін hello_world.py осы каталогта екеніне көз жеткізу үшін ls пәрменін пайдаланыңыз. Содан кейін файлды python3 hello_world.py пәрмені арқылы іске қосыңыз.

Бағдарламаларыңыздың көпшілігі тікелей редакторыңыздан жақсы жұмыс істейді. Бірақ жұмысыңыз күрделене түскен сайын, кейбір бағдарламаларды терминалдан іске қосқыңыз келеді.


Қорытынды

Бұл тарауда сіз жалпы Python туралы аздап білдіңіз және Python әлі жоқ болса, жүйеңізге орнаттыңыз. Сондай-ақ Python кодын жазуды жеңілдету үшін мәтіндік редактор орнатқансыз. Терминал сеансында Python кодының үзінділерін іске қостыңыз және hello_world.py алғашқы бағдарламаңызды іске қостыңыз. Ақаулықтарды жою туралы аздап білген шығарсыз.

Келесі тарауда Python бағдарламаларында жұмыс істеуге болатын деректердің әртүрлі түрлерімен танысасыз және айнымалы мәндерді де пайдалана бастайсыз.

Айнымалылар және қарапайым дерек түрлері

ITUniver

2
Айнымалылар және қарапайым дерек түрлері

Бұл тарауда Python бағдарламаларында жұмыс істеуге болатын деректердің әртүрлі түрлері туралы білетін боласыз. Сондай-ақ бағдарламалардағы деректерді көрсету үшін айнымалы мәндерді пайдалануды үйренесіз.

hello_world.py іске қосылғанда шынымен не болады

hello_world.py іске қосылғанда Python не істейтінін егжей-тегжейлі қарастырайық. Белгілі болғандай, Python қарапайым бағдарламаны іске қосса да, біршама жұмыс істейді:

hello_world.py


        print("Hello Python world!")

Осы кодты іске қосқан кезде келесі нәтижені көресіз:


        Hello Python world!

hello_world.py файлын іске қосқан кезде .py соңы файлдың Python бағдарламасы екенін көрсетеді. Содан кейін редакторыңыз файлды Python интерпретаторы арқылы іске қосады, ол бағдарламаны бастан-аяқ оқиды және бағдарламадағы әрбір сөздің мағынасын анықтайды. Мысалы, аудармашы print сөзінен кейін жақшаны көргенде, ол экранға жақшаның ішінде не болса да басып шығарады.

Бағдарламаларды жазған кезде редактор (VS Code) бағдарламаның әртүрлі бөліктерін әртүрлі тәсілдермен бөлектейді. Мысалы, ол print() функцияның атауы екенін біледі және сол оны ерекше бір түспен көрсетеді. Ол "Hello Python world!" Python коды емес екенін біледі және бұл фразаны басқа түспен көрсетеді. Бұл мүмкіндік syntax highlighting/синтаксисті бөлектеу деп аталады және сіз өз бағдарламаларыңызды жаза бастағанда өте пайдалы.

Айнымалылар

hello_world.py ішінде айнымалы мәнді пайдаланып көрейік. Файлдың басына жаңа жол қосып, екінші Тіркесті өзгертіңіз:

hello_world.py


        message = "Hello Python world!"
        print(message)

Не болатынын көру үшін осы бағдарламаны іске қосыңыз. Сіз бұрын көрген нәтижені көруіңіз керек:


        Hello Python world!

Біз message атты айнымалы қостық. Әрбір айнымалы мәнге байланыстырылған, ал бұл өз кезегінде айнымалыға қатысты ақпарат. Бұл жағдайда мән "Hello Python world!" мәтіні болып табылады.

Айнымалыларды қосу Python аудармашысының жұмысын біршама арттырады. Ол бірінші Тіркесті өңдегенде, ол message айнымалысын "Hello Python world!" мәтінімен байланыстырады. Екінші жолға жеткенде, экранға message байланысты мәнді басып шығарады.

Екінші хабарды басып шығару үшін hello_world.py өзгерту арқылы осы бағдарламаны кеңейтейік. hello_world.py ішіне бос жол қосыңыз, содан кейін екі жаңа код жолын қосыңыз:


        message = "Hello Python world!"
        print(message)
        
        message = "Hello Python Crash Course world!"
        print(message)

Енді hello_world.py іске қосылғанда, сіз екі шығыс жолын көресіз:


        Hello Python world!
        Hello Python Crash Course world!

Бағдарламадағы айнымалының мәнін кез-келген уақытта өзгертуге болады және Python әрқашан оның ағымдағы мәнін қадағалап отырады.

Айнымалыларды атау және пайдалану

Python-да айнымалы мәндерді пайдаланған кезде бірнеше ережелер мен нұсқауларды есте сақтау керек. Осы ережелердің кейбірін бұзу қателерді тудырады; басқа нұсқаулар оқуға және түсінуге оңай кодты жазуға көмектеседі. Айнымалылармен жұмыс істеу кезінде келесі ережелерді есте сақтаңыз:

  • Айнымалы атауларында тек әріптер, сандар және астын сызулар болуы мүмкін. Олар әріптен немесе астын сызудан басталуы мүмкін, бірақ санмен емес. Мысалы, message_1 айнымалысын шақыруға болады, бірақ 1_message-ды емес.
  • Айнымалы атауларында бос орындарға рұқсат етілмейді, бірақ астын сызу айнымалы атауларындағы сөздерді бөлу үшін пайдаланылуы мүмкін. Мысалы, greeting_message жұмыс істейді, бірақ greeting message қателерді тудырады.
  • Python кілт сөздері мен функция атауларын айнымалы атаулар ретінде пайдаланудан аулақ болыңыз. Мысалы, айнымалы аты ретінде print сөзін қолданбаңыз; Python оны белгілі бір бағдарламалық мақсат үшін сақтаған. (Мына сілтемелерден "Python кілт сөздері мен кірістірілген функцияларды" қараңыз.)
  • Айнымалы атаулары қысқа, бірақ сипаттамалы болуы керек. Мысалы, name n-ге қарағанда жақсы, student_name s_n-ге қарағанда дұрыс және name_length length_of_persons_name-нен қарағанда жақсырақ.
  • Кіші әріп l және бас әріп O қолданғанда абай болыңыз, себебі олар 1 және 0 сандарымен шатастырылуы мүмкін.

Жақсы айнымалы атауларды жасауды үйрену үшін біраз тәжірибе қажет болуы мүмкін, әсіресе сіздің бағдарламаларыңыз қызықты әрі күрделі бола бастағанда. Көбірек бағдарламалар жазып, басқа адамдардың кодын оқи бастағанда, сіз мағыналы атауларды ойлап таба аласыз.

Айнымалыларды пайдалану кезінде атау қателеріне жол бермеу

Әрбір бағдарламашы қателеседі және көпшілігі күн сайын қателеседі. Жақсы бағдарламашылар қателер жасауы мүмкін болса да, олар сол қателерге қалай тиімді жауап беру керектігін де біледі. Бастапқыда жіберуі мүмкін қатені қарастырып, оны қалай түзетуге болатынын білейік.

Біз әдейі қате тудыратын кодты жазамыз. Қызғылт әріппен көрсетілген mesage, қате жазылған сөзді қоса, келесі кодты енгізіңіз:


        message = "Hello Python Crash Course reader!"
        print(mesage)

Бағдарламада қате орын алған кезде, Python аудармашысы мәселенің қай жерде екенін анықтауға көмектесу үшін барын салады. Интерпретатор бағдарлама сәтті орындалмаған кезде кері бақылауды қамтамасыз етеді. traceback/бақылау - аудармашы сіздің кодты орындауға әрекет жасаған кезде қиындыққа тап болған жазба. Міне, айнымалының атын байқаусызда қате жазғаннан кейін Python қамтамасыз ететін кері бақылау мысалы:


        Traceback (most recent call last):
           File "hello_world.py", line 2, in <module>
             print(mesage)
                  ^^^^^^
         NameError: name 'mesage' is not defined. Did you mean: 'message'?

Шығыс hello_world.py ❶ файлының 2-жолында қате орын алғанын хабарлайды. Аудармашы қатені жылдам анықтауға көмектесу үшін ❷ жолын көрсетеді және ол қандай қатені тапқанын айтады. Бұл жағдайда ол name error (ат қатесін) тапты және басып шығарылатын айнымалы mesage анықталмағанын хабарлайды. Python берілген айнымалы атауын анықтай алмайды. Name Error әдетте айнымалыны пайдаланудан бұрын оған мән беруді ұмытып кеткенімізді немесе айнымалының атын енгізу кезінде емле қатесін жібергенімізді білдіреді. Егер Python өзі танымайтын айнымалыға ұқсас атауды тапса, ол сіз қолданғыңыз келген атау осы ма деп сұрайды.

Бұл мысалда біз екінші Тіркестегі message айнымалы атауындағы s әрпін алып тастадық. Python аудармашысы кодтың емлені тексермейді, бірақ айнымалы атауларының дәйекті түрде жазылуын қамтамасыз етеді. Мысалы, айнымалы мәнді анықтайтын жолда message қате жазылғанда не болатынын қараңыз:


        mesage = "Hello Python Crash Course reader!"
        print(mesage)

Бұл жағдайда бағдарлама сәтті орындалады!


        Hello Python Crash Course reader!

Айнымалы атаулары сәйкес келеді, сондықтан Python ешқандай мәселені көрмейді. Бағдарламалау тілдері қатаң, бірақ олар жақсы және жаман емлені ескермейді. Нәтижесінде айнымалы атауларды жасауға және код жазуға тырысқанда ағылшын тілінің (өзге тілдердің де) емлесі мен грамматика ережелерін ескерудің қажеті жоқ.

Көптеген бағдарламалау қателері бағдарламаның бір жолындағы қарапайым, бір таңбадан тұратын қателер. Егер сіз осы қателердің бірін іздеуге ұзақ уақыт жұмсайтын болсаңыз, сіз өзге де көптеген осылай қате іздеуші бағдарламашылар қатарында екеніңізді біліңіз. Көптеген тәжірибелі және дарынды бағдарламашылар осы сияқты кішкентай қателерді іздеуге бірнеше сағат жұмсайды. Бағдарламалау өміріңізде жиі болатынын біле отырып, бұл туралы күліп, әрі қарай жалғастыруға тырысыңыз.

Айнымалыларды сілтеме деп айтсақ болады

Айнымалылар жиі мәндерді сақтауға болатын қораптар ретінде сипатталады. Бұл идея айнымалыны алғашқы бірнеше рет пайдаланғанда пайдалы болуы мүмкін, бірақ бұл айнымалы мәндердің Python-да ішкі түрде қалай көрсетілетінін сипаттаудың дәл жолы емес. Айнымалыларды мәндерге тағайындауға болатын сілтемелер ретінде қарастыру әлдеқайда жақсы. Сондай-ақ айнымалы белгілі бір мәнге сілтеме жасайды деп айтуға болады.

Бастапқы бағдарламаларыңызда бұл ерекшелік маңызды емес шығар, бірақ оны кейінірек емес, ертерек үйренген жөн. Бір сәтте айнымалыдан күтпеген әрекетті көресіз және айнымалы мәндердің қалай жұмыс істейтінін дәл түсіну кодыңызда не болып жатқанын анықтауға көмектеседі.

Тіркестер

Бағдарламалардың көпшілігі деректердің қандай да бір түрін анықтап, жинап, содан кейін онымен пайдалы әрекет жасайтындықтан, деректердің түрлерін анықтап алған дұрыс. Біз қарастыратын бірінші деректер түрі - string/тіркес. Тіркестер бір қарағанда қарапайым, бірақ оларды әртүрлі жолмен пайдалануға болады.

String/тіркес - бұл таңбалардың тізбегі.

Тіркес-ке ерекше назар аударыңыз, олар біз адамдар қолданатын сөз немесе сойлем емес. Бағдарламалау контекстінде тіркестер символдар тізбегі болып табылады. Олар әріптерден, сандардан және тыныс белгілері сияқты кез-келген басқа таңбалардан тұруы мүмкін. Тіркестер біз оларды жалпы түсінетіндей жай сөздер емес, оның орнына бір тіркес бірнеше толық сөйлем сияқты ұзын болуы мүмкін. Тіркестер әдетте жазылғандай дәл басып шығарылады.

Тырнақшалардың ішіндегі кез-келген нәрсе Python тілінде тіркес болып саналады және тіркесіңіздің айналасында бір немесе қос тырнақшаларды келесідей пайдалануға болады:


        "This is a string. Мынау тіркес."
        'This is also a string. Манау да тіркес.'

Бұл икемділік тіркесте тырнақшалар мен апострофтарды пайдалануға мүмкіндік береді:


        'I told my friend, "Python is my favorite language!"'
        "The language 'Python' is named after Monty Python, not the snake."
        "One of Python's strengths is its diverse and supportive community."

Тіркесті пайдаланудың кейбір жолдарын қарастырайық.

Тіркестегі регистрді әдістермен өзгерту

Тіркестермен орындауға болатын қарапайым әрекеттердің бірі - тіркестегі сөздердің регистрін өзгерту. Келесі кодты қарап, не болып жатқанын анықтауға тырысыңыз:

name.py


        name = "ada lovelace"
        print(name.title())

Осы файлды name.py ретінде сақтаңыз, содан кейін оны іске қосыңыз. Мына нәтижені көруіңіз керек:


        Ada Lovelace

Бұл мысалда name айнымалысы "ada lovelace" кіші әріптер тіркесіне сілтеме жасайды. title() әдісі print() шақыруындағы айнымалыдан кейін пайда болады. Method/әдіс - бұл Python деректер бөлігінде орындай алатын әрекет. name.title() ішіндегі name-нен кейінгі нүкте (.) Python-ға title() әдісі әрекетін name айнымалысына жасауды ұсынады. Әрбір әдістен кейін жақшалар жинағы болады, өйткені әдістер өз жұмысын орындау үшін жиі қосымша ақпаратты қажет етеді. Бұл ақпарат жақша ішінде беріледі. title() функциясына қосымша ақпарат қажет емес, сондықтан оның жақшалары бос.

title() әдісі әр сөзді тақырып регистріне өзгертеді, мұнда әрбір сөз бас әріптен басталады. Бұл пайдалы, мысалы, сіз бағдарламаңыздың Ada, ADA және ada кіріс мәндерін бірдей атау ретінде танып, олардың барлығын Ada ретінде көрсетуін қалауыңыз мүмкін.

Сонымен қатар регистрмен жұмыс істейтін бірнеше басқа пайдалы әдістер бар. Мысалы, тіркесті келесідей барлық бас әріптерге немесе барлық кіші әріптерге өзгертуге болады:


        name = "Ada Lovelace"
        print(name.upper())
        print(name.lower())

Бұл келесіні көрсетеді:


        ADA LOVELACE
        ada lovelace

lower() әдісі әсіресе деректерді сақтау үшін пайдалы. Сіз әдетте пайдаланушылар беретін бас әріпке сенгіңіз келмейді, сондықтан оларды сақтау алдында тіркестерді кіші әріпке түрлендіріңіз. Содан кейін ақпаратты көрсеткіңіз келгенде, әрбір тіркес үшін ең дұрыс келетін регистрді пайдаланасыз.

Тіркестің ішінде айнымалыларды пайдалану

Кейбір жағдайларда айнымалы мәнді тіркес ішінде пайдаланғыңыз келеді. Мысалы, аты мен тегін көрсету үшін екі айнымалы мәнді пайдаланғыңыз келуі мүмкін, содан кейін біреудің толық атын көрсету үшін сол мәндерді біріктіріңіз:

full_name.py


        first_name = "ada"
        last_name = "lovelace"
         full_name = f"{first_name} {last_name}"
        print(full_name)

Айнымалы мәнді тіркеске енгізу үшін ❶ ашу тырнақшасының алдына бірден f әрпін қойыңыз. Тіркестің ішінде пайдаланғыңыз келетін кез-келген айнымалының атының немесе атауларының айналасына жақшаларды қойыңыз. Тіркес көрсетілген кезде Python әрбір айнымалыны мәнімен ауыстырады.

Бұл тіркестер f-strings (f-тіркестер) деп аталады. f - format/пішім, себебі Python тіркесті жақшадағы кез-келген айнымалының атын оның мәнімен ауыстыру арқылы пішімдейді. Алдыңғы кодтың шығысы:

ada lovelace

Сіз f-тіркестерімен көп нәрсе істей аласыз. Мысалы, мұнда көрсетілгендей айнымалымен байланысты ақпаратты пайдалана отырып, толық хабарлар жасау үшін f-тіркесін пайдалануға болады:


        first_name = "ada"
        last_name = "lovelace"
        full_name = f"{first_name} {last_name}"
         print(f"Hello, {full_name.title()}!")

full_name(толық аты-жөні) ❶ пайдаланушымен сәлемдесетін сөйлемде пайдаланылады және title() әдісі аты-жөнді бас әріпке ауыстырады. Бұл код қарапайым, бірақ жақсы пішімделген сәлемдемені қайтарады:

Hello, Ada Lovelace!(Сәлеметсіз бе, Ада Лавлейс!)

Сонымен қатар хабарды жазу үшін f-тіркесін пайдалануға болады, содан кейін бүкіл хабарды айнымалыға тағайындауға болады:


        first_name = "ada"
        last_name = "lovelace"
        full_name = f"{first_name} {last_name}"
         message = f"Hello, {full_name.title()}!"
         print(message)

Бұл код та Hello, Ada Lovelace! хабарын көрсетеді, бірақ хабарды ❶ message айнымалысына тағайындау арқылы біз соңғы print() шақыруын әлдеқайда "таза" ❷ етеміз.

Tabs немесе Newlines (жаңа жолдар) арқылы тіркестерге бос орын қосу

Бағдарламалауда бос орын spaces (бос орындар), tabs(қойындылар) және end-of-line символдары сияқты кез-келген басып шығарылмайтын таңбаларды білдіреді. Пайдаланушыларға оқу оңай болатындай етіп шығысты ұйымдастыру үшін бос орынды пайдалануға болады.

Мәтінге tab қосу үшін \t таңбалар комбинациясын пайдаланыңыз:


        >>> print("Python")
        Python
        >>> print("\tPython")
            Python
        >>> print("\t\t\tPython")
                  Python

Тіркеске жаңа жол қосу үшін \n таңбалар комбинациясын пайдаланыңыз:


        >>> print("Languages:\nPython\nC\nJavaScript")
        Languages:
        Python
        C
        JavaScript

Сонымен қатар tabs(қойындылар) пен тіркестерді бір жолда біріктіруге болады. "\n\t" тіркесі Python-ға жаңа жолға өтуді және келесі тіркесті tab-пен бастауды ұсынады. Келесі мысал шығыстың төрт жолын жасау үшін бір ғана тіркесті қалай пайдалануға болатынын көрсетеді:


        >>> print("Languages:\n\tPython\n\tC\n\tJavaScript")
        Languages:
            Python
            C
            JavaScript

Жаңа жолдар мен tab(қойындылар) келесі екі тарауда өте пайдалы болады, себебі аз код тізбегі көптеген жолдар шығысын басып шығаратын болады. Жаңа жолдар мен таб оны оқуды оңайлатады

Бос орынды алып тастау

Бағдарламаларыңыздағы қосымша бос орындар шатастыруы мүмкін. Бағдарламашыларға 'python' және 'python ' бірдей көрінеді. Бірақ бағдарлама үшін олар екі түрлі тіркес. Python 'python ' ішіндегі қосымша бос орынды анықтайды және басқаша айтпасаңыз, оны маңызды деп санайды.

Бос орындарды әрқашан ескерген жөн, себебі сіз "екі тіркес бірдей ме?" тексерулер жасайтын боласыз. Маңызды мысалдардың бірі веб-сайтқа кірген кезде адамдардың пайдаланушы атын (логин) тексеруді қамтуы мүмкін. Қосымша бос орын әлдеқайда қарапайым жағдайларда да шатастыруы мүмкін. Бақытымызға орай, Python адамдар енгізетін деректерден қосымша бос орындарды жоюды жеңілдетеді.

Python тіркестің оң және сол жағында қосымша бос орынды іздей алады. Тіркестің оң жағында бос орын жоқ екеніне көз жеткізу үшін rstrip() әдісін пайдаланыңыз:


         >>> favorite_language = 'python '
         >>> favorite_language
        'python '
         >>> favorite_language.rstrip()
        'python'
         >>> favorite_language
        'python '

favorite_language-ге байланысты мән тіркестің соңында қосымша бос орынды қамтиды. Терминал сеансында Python-нан осы мәнді сұраған кезде, ❷ мәнінің соңындағы бос орынды көре аласыз. rstrip() әдісі favorite_language ❸ айнымалысына әрекет еткенде, бұл қосымша бос орын жойылды. Дегенмен, ол уақытша ғана жойылады. Егер favorite_language мәнін қайтадан сұрасаңыз, тіркес қосымша бос орынды қоса, енгізілген кездегідей бастапқы қалыпында екенін көресіз ❹.

Тіркестен бос орынды біржола жою үшін жою әдісі әрекет мәнді айнымалы атымен байланыстыру керек:


        >>> favorite_language = 'python '
         >>> favorite_language = favorite_language.rstrip()
        >>> favorite_language
        'python'

❶ Тіркестен бос орынды жою үшін тіркестің оң жағындағы бос орынды алып тастаңыз, содан кейін осы жаңа мәнді бастапқы айнымалы мәнмен байланыстырыңыз. Айнымалының мәнін өзгерту бағдарламалауда жиі жасалады. Бағдарлама орындалғанда немесе пайдаланушы енгізуіне жауап ретінде айнымалы мәнді осылайша жаңартуға болады.

Сонымен қатар бос орынды lstrip() әдісі арқылы тіркестің сол жағынан немесе strip() арқылы бірден екі жағынан алып тастауға болады:


         >>> favorite_language = ' python '
         >>> favorite_language.rstrip()
        ' python'
         >>> favorite_language.lstrip()
        'python '
         >>> favorite_language.strip()
        'python'

❶ Бұл мысалда біз басында және соңында бос орын бар мәннен бастаймыз. Одан кейін қосымша бос орынды ❷ оң жағынан, ❸ сол жақтан алып тастаймыз және соңында екі жағынан ❹. Осы strip функцияларымен тәжірибе жасау тіркестерді манипуляциялаумен танысуға көмектеседі. Шын өмірде бұл ажырату/strip функциялары қолданушы енгізген ақпаратты бағдарламада сақтағанға дейін тазалап, өңдеп алу үшін жиі пайдаланылады.

Префикстерді жою (Removing Prefixes)

Тіркестермен жұмыс істегенде тағы бір жалпы тапсырма префиксті жою болып табылады. Мысалы https:// префиксі бар URL мекенжайын қарастырыңыз. Біз бұл префиксті алып тастағымыз келеді, соның арқасында тек қолданушылар енгізуі қажетті URL бөлігі біздің басты назарда болады. Мұны істеу жолы:


        >>> ituniver_url = 'https://ituivner.kz'
        >>> ituniver_url.removeprefix('https://')
        'ituniver.kz'

Айнымалының атын, одан соң нүктеден кейін, removeprefix() әдісін енгізіңіз. Жақшаның ішіне бастапқы жолдан алып тастағыңыз келетін префиксті енгізіңіз.

Бос орынды жою әдістері сияқты, removeprefix() бастапқы тіркесті өзгеріссіз қалдырады. Жаңа мәнді префиксі жойылған түрінде сақтағыңыз келсе, оны бастапқы айнымалыға қайта тағайындаңыз немесе оны жаңа айнымалыға тағайындаңыз:


        >>> simple_url = ituniver_url.removeprefix('https://')

Мекенжай жолағында URL мекенжайын көргенде және https:// бөлігі көрсетілмегенде, браузер артында removeprefix() сияқты әдісті пайдаланып жатқан болуы мүмкін. көріністер.

Тіркестермен жұмыс істегенде синтаксистік қателерді болдырмау

Сіз бағдарламадан жиі көретін қателердің бірі - синтаксистік қате. Синтаксистік қате/Syntax Error Python бағдарламаңыздың бір бөлігін жарамды Python коды ретінде танымағанда орын алады. Мысалы, бір тырнақшаның ішінде апострофты қолдансаңыз, қате жібересіз. Бұл Python бірінші жалғыз тырнақша мен апостроф арасындағы барлық нәрсені тіркес ретінде түсіндіретіндіктен орын алады. Содан кейін ол мәтіннің қалған бөлігін қателерді тудыратын Python коды ретінде түсіндіруге тырысады.

Міне, жалғыз және қос тырнақшаларды қалай дұрыс қолдану керек. Бұл бағдарламаны apostrophe.py ретінде сақтаңыз, содан кейін оны іске қосыңыз:

apostrophe.py


        message = "One of Python's strengths is its diverse community."
        print(message)

Апостроф қос тырнақшалар жинағында пайда болады, сондықтан Python аудармашысы тіркесті дұрыс оқуда қиындық туғызбайды:


        One of Python's strengths is its diverse community.

Дегенмен, егер сіз жалғыз тырнақшаларды қолдансаңыз, Python Тіркестің қай жерде аяқталу керектігін анықтай алмайды:


        message = 'One of Python's strengths is its diverse community.'
        print(message)

Келесі нәтижені көресіз:


            File "apostrophe.py", line 1
            message = 'One of Python's strengths is its diverse community.'
                                                                         ^
        SyntaxError: unterminated string literal (detected at line 1)

Шығармада қате соңғы жалғыз тырнақшадан кейін бірден орын алғанын көре аласыз ❶. Бұл синтаксистік қате аудармашы кодтағы бір нәрсені жарамды Python коды ретінде танымайтынын көрсетеді және мәселе дұрыс тырнақша көрсетілмеген тіркес болуы мүмкін деп ойлайды. Қателер әртүрлі көздерден келуі мүмкін, мен олардың пайда болуына қарай кейбір жиі кездесетіндерін атап өтемін. Python кодын дұрыс жазуды үйренген кезде синтаксистік қателерді жиі көруіңіз мүмкін. Синтаксистік қателер де қатенің ең аз нақты түрі болып табылады, сондықтан оларды анықтау және түзету қиын және көңілсіз болуы мүмкін. Егер сіз тым көп қатеге жиі тап болсаңыз, С қосымшасыдағы ұсыныстарды қараңыз.

Сандар

Сандар бағдарламаның негізгі элементінің бірі. Мысалы банк аккаунтындағы счеттар, бухгалтерлік бағдарламалар, қосымшалардағы сандар, ойындардағы ұпайларды сақтау, визуализациялардағы деректерді көрсету, веб-қосымшаларда ақпаратты сақтау және т.б. үшін сандар бағдарламалауда жиі пайдаланылады. Python сандарды қалай қолданылатынына байланысты әртүрлі әдістермен өңдейді. Алдымен Python бүтін сандарды қалай басқаратынын қарастырайық, себебі олармен жұмыс істеу ең қарапайым.

Бүтін сандар

Python тіліндегі бүтін сандарды қосуға (+), азайтуға (-), көбейтуге (*) және бөлуге (/) болады.


        >>> 2 + 3
        5
        >>> 3 - 2
        1
        >>> 2 * 3
        6
        >>> 3 / 2
        1.5

Терминал сеансында Python жай ғана операцияның нәтижесін қайтарады. Python дәрежені көрсету үшін екі көбейту таңбасын пайдаланады:


        >>> 3 ** 2
        9
        >>> 3 ** 3
        27
        >>> 10 ** 6
        1000000

Python амалдардың ретін де қолдайды, сондықтан бір өрнекте бірнеше әрекетті пайдалануға болады. Сондай-ақ, жақшаларды әрекеттер ретін өзгерту үшін пайдалануға болады, осылайша Python өрнекті сіз көрсеткен ретпен бағалай алады. Мысалы:


        >>> 2 + 3*4
        14
        >>> (2 + 3) * 4
        20

Бұл мысалдардағы интервал Python өрнектерді қалай бағалайтынына әсер етпейді; бұл жай ғана кодты оқып жатқанда басымдылыққа ие әрекеттерді тезірек анықтауға көмектеседі.

Floats

Python ондық нүктесі бар кез-келген санды float деп атайды. Бұл термин көптеген бағдарламалау тілдерінде қолданылады және ондық бөлшек санның кез-келген орнында пайда болуы мүмкін екенін білдіреді. Әрбір бағдарламалау тілі ондық сандарды дұрыс басқару үшін мұқият жасалуы керек, сондықтан ондық нүкте қай жерде пайда болса да, сандар дұрыс әрекет етеді.

Көбінесе қалтқыларды олардың әрекеті туралы алаңдамай пайдалануға болады. Жай ғана пайдаланғыңыз келетін сандарды енгізіңіз, сонда Python сіз күткен нәрсені жасайды:


        >>> 0.1 + 0.1
        0.2
        >>> 0.2 + 0.2
        0.4
        >>> 2 * 0.1
        0.2
        >>> 2 * 0.2
        0.4

Дегенмен, кейбір жағдайларда қайтарылатын жауапта ондық таңбалардың ұзақ-шұбырған саны шығып қалуы мүмкін болатынын ескеріңіз:


        >>> 0.2 + 0.1
        0.30000000000000004
        >>> 3 * 0.1
        0.30000000000000004

Бұл барлық тілдерде орын алады және ол туралы қатты алаңдаудың қажеті жоқ. Python нәтижені мүмкіндігінше дәл көрсетудің жолын табуға тырысады, бұл компьютерлердің сандарды ішкі түрде көрсетуінің ерекшелігіне байланысты кейде қиын. Әзірге қосымша ондық бөлшектерді елемеңіз; II бөлімдегі жобаларда қажет болғанда қосымша орындармен жұмыс істеу жолдарын үйренесіз.

Бүтін және қалқымалы сандар / Integers and Floats

кез-келген екі санды бөлген кезде, тіпті олар бүтін сан болатын бүтін сандар болса да, сіз әрқашан қалқымалы мән аласыз:


        >>> 4/2
        2.0

Егер кез-келген басқа операцияда бүтін сан мен қалқымалы мәнді араластырсаңыз, сіз де қалқымалы мән аласыз:


        >>> 1 + 2.0
        3.0
        >>> 2 * 3.0
        6.0
        >>> 3.0 ** 2
        9.0

Шығыс бүтін сан болса да, қалқымалы мәнді пайдаланатын кез-келген операцияда Python әдепкі бойынша қалқымалы мәнді береді.

Сандардағы астын сызу

Ұзын сандарды жазғанда үлкен сандарды оқуға ыңғайлы ету үшін астын сызу арқылы сандарды топтауға болады:


        >>> universe_age = 14_000_000_000

Төменгі сызу арқылы анықталған санды басып шығарған кезде, Python тек сандарды басып шығарады:


        >>> print(universe_age)
        14000000000

Python осы мән түрлерін сақтаған кезде астын сызуларды елемейді. Цифрларды үш-үштен не өзгеше топтасаңыз да айырмашылығы жоқ. Python үшін 1000, 1_000, 10_00 бірдей мән. Бұл мүмкіндік бүтін сандар үшін де, қалқымалы сандар үшін де жұмыс істейді.

Бірден бірнеше мән тағайындау

Кодтың бір жолын пайдаланып бірнеше айнымалыға мәндерді тағайындауға болады. Бұл бағдарламаларды қысқартуға және оларды оқуды жеңілдетуге көмектеседі; сандар жиынын инициализациялау кезінде бұл әдісті жиі пайдаланасыз.

Мысалы, x, y және z айнымалы мәндерін нөлге қалай инициализациялауға болады:


        >>> x, y, z = 0, 0, 0

Айнымалы атауларын үтірмен бөліп, мәндермен де солай істеу керек, Python әрбір мәнді сәйкес айнымалыға тағайындайды. Мәндердің саны айнымалылар санына сәйкес келсе болды, Python оларды бір-біріне дұрыс сәйкестендіреді.

Тұрақтылар / Constants

Тұрақты - бұл мәні бағдарламаның қызмет ету мерзімі ішінде өзгеріссіз қалатын айнымалы. Python-да кіріктірілген тұрақты дерек типі жоқ, бірақ Python бағдарламашылары айнымалы мәнді тұрақты ретінде қарастыру және ешқашан өзгертілмеу керектігін көрсету үшін барлық бас әріптерді пайдаланады:


        MAX_CONNECTIONS = 5000

Кодыңызда айнымалы мәнді тұрақты мән ретінде қарастырғыңыз келсе, айнымалының атын барлық бас әріптермен жазыңыз.

Comments / Түсініктемелер

Comments көптеген бағдарламалау тілдерінде өте пайдалы мүмкіндік болып табылады. Бағдарламаларыңызда осы уақытқа дейін жазғаныңыздың бәрі Python коды. Бағдарламаларыңыз ұзағырақ және күрделене түскен сайын, сіз шешіп жатқан мәселеге жалпы көзқарасыңызды сипаттайтын бағдарламаларға ескертпелерді қосуыңыз керек. Comments/түсініктеме бағдарламалар ішінде ауызекі тілде жазбалар жазуға мүмкіндік береді. Оны адамдар оқиды. Python интерпретаторы мүледем елемейді

Түсініктемелерді қалай жазасыз?

Python тілінде хэш белгісі (#) түсініктемені көрсетеді. Кодыңыздағы хэш белгісінен кейінгі кез-келген нәрсені Python аудармашысы елемейді. Мысалы:

comment.py


        # Say hello to everyone.
        print("Hello Python people!")

Python бірінші жолды елемейді және екінші жолды орындайды.


        Hello Python people!

Қандай түсініктемелерді жазу керек?

Түсініктеме жазудың негізгі себебі - кодыңыз не істеу керек екенін және оны қалай жұмыс істейтінін түсіндіру. Сіз үлкендеу жобамен жұмыс істеу барысында барлық бөліктердің бір-біріне қалай сәйкес келетінін түсініп, біліп тұрасыз. Бірақ біраз уақыттан кейін жобаға оралғанда, кейбір мәліметтерді ұмытып кетуіңіз мүмкін. Сіз әрқашан кодты біраз уақыт зерттеп, сегменттердің қалай жұмыс істейтінін анықтай аласыз, бірақ жақсы түсініктемелер жазу жалпы көзқарасыңызды нақты қорытындылау арқылы уақытыңызды үнемдейді.

Егер сіз кәсіби бағдарламашы болғыңыз келсе немесе басқа бағдарламашылармен жұмыс істегіңіз келсе, мағыналы түсініктемелер жызып үйреніңіз. Бүгінгі таңда бағдарламалық жасақтаманың көпшілігі бір компаниядағы қызметкерлер тобымен немесе open-source жобада бірге жұмыс істейтін адамдар тобымен бірлесіп жазылады. Білікті бағдарламашылар кодты оқығанда түсініктемелерді көреміз деп күтеді, сондықтан бағдарламаларыңызға сипаттамалық түсініктемелерді қосуды қазірден бастаған дұрыс. Кодыңызда түсінікті, қысқа түсініктемелер жазу - жаңа бастаған бағдарламашы ретінде қалыптастыруға болатын ең пайдалы әдеттердің бірі.

Түсініктеме жазу туралы шешім қабылдағанда, бірдеңені тиімді етудің ақылға қонымды жолын ойлап таппас бұрын бірнеше тәсілдерді қарастыру керек пе еді деп өзіңізден сұраңыз; егер солай болса, шешіміңіз туралы түсініктеме жазыңыз. Артқа оралып, сирек түсініктеме жазылған бағдарламаға түсініктеме жазғаннан гөрі, қосымша түсініктемелерді кейінірек жою оңайырақ. Бұдан былай код бөлімдерін түсіндіруге көмектесу үшін осы кітаптағы мысалдардағы түсініктемелерді қолданатын боламын.

Python дзені

Тәжірибелі Python бағдарламашылары сізді күрделіліктен аулақ болуға және мүмкіндігінше қарапайымдылыққа ұмтылуға шақырады. Python қауымдастығының философиясы Тим Питерстің «Питон дзенінде» қамтылған. Жақсы Python кодын жазудың осы қысқаша принциптер жинағын көру үшін интерпретаторда import this енгізу арқылы қол жеткізе аласыз. Мен бұл жерде «Python дзенін» толық көшірмеймін, бірақ Python бағдарламашысы ретінде сіз үшін олардың неліктен маңызды болуы керектігін түсінуге көмектесу үшін бірнеше жолмен бөлісемін.


        >>> import this
        The Zen of Python, by Tim Peters
        Beautiful is better than ugly.

Python бағдарламашылары код әдемі және талғампаз (elegant) болуы мүмкін деген ұғымды қабылдайды. Бағдарламалауда адамдар мәселелерді шешеді. Бағдарламашылар әрқашан мәселелердің жақсы жобаланған, тиімді және тіпті әдемі шешімдерін құрметтейді. Python туралы көбірек біліп, оны көбірек код жазу үшін пайдаланған кезде, біреу бір күні сіз жазған кодты қарап: «Уау, бұл керемет әдемі код!» деп айтуы мүмкін.

Simple is better than complex / Күрделіден гөрі қарапайым.
Егер сізде қарапайым және күрделі шешім арасында таңдау болса және екеуі де жұмыс істесе, қарапайым шешімді пайдаланыңыз. Кодыңызды сақтау оңайырақ болады және сізге және басқаларға кейінірек сол кодты құрастыру оңайырақ болады.

Complex is better than complicated. / Күрделі қиыннан қарағанда жақсы
Шынайы өмір бейберекет, кейде мәселені қарапайым шешу мүмкін емес. Бұл жағдайда жұмыс істейтін ең қарапайым шешімді пайдаланыңыз.

Readability counts / Оқуға оңайлық есептеледі
Тіпті кодыңыз күрделі болса да, оны оқуға болатын етіп жасаңыз. Күрделі кодтауды қамтитын жобада жұмыс істеп жатқанда, сол код үшін ақпараттық түсініктемелер жазуға назар аударыңыз.

There should be one-- and preferably only one --obvious way to do it.
Мұны істеудің бір және жақсырақ бір ғана жолы болуы керек.
Егер екі Python бағдарламашысынан бір мәселені шешу сұралса, олар жеткілікті түрде үйлесімді шешімдерді табуы керек. Бұл бағдарламалауда шығармашылыққа орын жоқ дегенді білдірмейді. Керісінше, шығармашылық үшін көп орын бар! Дегенмен, бағдарламалаудың көп бөлігі үлкенірек, креативті жобадағы қарапайым жағдайларға шағын, жалпы тәсілдерді қолданудан тұрады. Бағдарламаларыңыздың бұрандалары басқа Python бағдарламашыларына түсінікті болуы керек.

Now is better than never.
Сіз өміріңіздің қалған бөлігін Python-ның және жалпы бағдарламалаудың барлық қыр-сырын үйренуге жұмсай аласыз, бірақ содан кейін сіз ешқашан ешқандай жобаны аяқтамайсыз. Керемет код жазуға тырыспаңыз; жұмыс істейтін кодты жазыңыз, содан кейін сол жоба үшін кодты жақсарту немесе жаңа нәрсеге көшу туралы шешім қабылдаңыз.

Келесі тарауға өтіп, көбірек қызықты тақырыптарды зерттей бастағанда, осы қарапайымдылық пен түсінікті философияны есте сақтауға тырысыңыз. Тәжірибелі бағдарламашылар сіздің кодыңызды көбірек құрметтейді және сізге кері байланыс беруге және қызықты жобаларда сізбен бірлесіп жұмыс істеуге қуанышты болады.

Қорытынды

Бұл тарауда айнымалылармен жұмыс істеуді үйрендіңіз. Сіз түсінікті айнымалы атауларды пайдалануды және name error (атау қателері) мен SyntaxError(синтаксистік қателерді) олар туындаған кезде шешуді үйрендіңіз. Сіз тіркестердің не екенін және оларды кіші әріптерді, бас әріптерді және тақырып регистрін пайдалану арқылы қалай көрсету керектігін білдіңіз. Сіз шығысты ұқыпты ұйымдастыру үшін бос орынды пайдалана бастадыңыз және тіркестен қажет емес элементтерді жою жолын үйрендіңіз. Сіз бүтін және қалқымалы сандармен жұмыс істей бастадыңыз және сандық деректермен жұмыс істеудің кейбір тәсілдерін үйрендіңіз. Сондай-ақ кодыңызды өзіңізге және басқаларға оқуды жеңілдету үшін түсіндірме түсініктемелер жазуды үйрендіңіз. Соңында, кодты мүмкіндігінше қарапайым сақтау философиясы туралы оқыдық.

3-тарауда тізімдер деп аталатын деректер құрылымдарында ақпарат жинақтарын сақтау жолын үйренесіз. Сондай-ақ тізіммен жұмыс істеуді, сол тізімдегі кез-келген ақпаратты өңдеуді үйренесіз.

Тізімдерге кіріспе

ITUniver

3
Тізімдерге кіріспе

Осы және келесі тарауда тізімдер деген не екенін және тізімдегі элементтермен жұмысты қалай бастау керектігін үйренесіз. Тізімдер сізге бірнеше элементтер немесе миллиондаған элементтер болса да, ақпарат жиынын бір жерде сақтауға мүмкіндік береді. Тізімдер Python бағдарламасының жаңа бағдарламашыларға оңай қол жетімді ең қуатты мүмкіндіктерінің бірі және олар бағдарламалаудағы көптеген маңызды ұғымдарды біріктіреді.

Тізім дегеніміз не?

List/тізім - белгілі бір реттегі элементтер жиынтығы. Сіз әліпбидің әріптерін, 0-ден 9-ға дейінгі сандарды немесе отбасыңыздағы барлық адамдардың есімдерін қамтитын тізім жасай аласыз. Тізімге қалаған кез-келген нәрсені қоюға болады және тізімдегі элементтер бір-біріне қандай да бір түрде қатысты болуы міндетті емес. Тізім әдетте бірнеше элементтерді қамтитындықтан, тізімнің атауын әріптер, цифрлар немесе аттары сияқты көпше етіп жасаған дұрыс.

Python тілінде тік бұрышты жақшалар ([]) тізімді көрсетеді және тізімдегі жеке элементтер үтірмен бөлінген. Мұнда велосипедтердің бірнеше түрі бар тізімнің қарапайым мысалы берілген:

bicycles.py


        bicycles = ['trek', 'cannondale', 'redline', 'specialized']
        print(bicycles)

Егер Python-нан тізімді басып шығаруды сұрасаңыз, Python төртбұрышты жақшаларды қоса алғанда тізімнің көрінісін береді:


        ['trek', 'cannondale', 'redline', 'specialized']

Бағдарламаны қолданушылар көретін нәтиже мұндай болғанын қаламаймыз, сондықтан тізімдегі жеке элементтерге қалай қол жеткізуге болатынын білейік.

Тізімдегі элементтерге қол жеткізу

Тізімдер реттелген жинақтар болып табылады, сондықтан Python-ға қалаған элементтің орнын немесе индексін айту арқылы тізімдегі кез-келген элементке қол жеткізуге болады. Тізімдегі элементке қол жеткізу үшін тізімнің атын, содан кейін төртбұрышты жақшаға алынған элементтің индексін жазыңыз.

Мысалы, bicycles тізіміндегі бірінші велосипедті шығарып алайық:


        bicycles = ['trek', 'cannondale', 'redline', 'specialized']
        print(bicycles[0])

Тізімнен бір элемент сұраған кезде, Python тек сол элементті төртбұрышты жақшасыз қайтарады:


          trek
        

Біз қолданушылар көретін нәтиже осындай болғанын қалаймыз: таза, ұқыпты пішімделген нәтиже.

Сонымен қатар осы тізімдегі кез-келген элементте 2-тарауда оқыған тіркес әдістерін пайдалануға болады. Мысалы, title() әдісін қолдану арқылы көрнекі көріну үшін 'trek' элементін пішімдеуге болады:


        bicycles = ['trek', 'cannondale', 'redline', 'specialized']
        print(bicycles[0].title())

Бұл мысал алдыңғы мысалмен бірдей нәтиже береді, тек 'Trek' бас әріппен жазылады.

Индекс орындары 1 емес, 0-ден басталады

Python тізімдегі бірінші элементті 1-позицияда емес, 0-позицияда деп санайды. Бұл көптеген бағдарламалау тілдеріне қатысты және оның себебі тізім әрекеттерінің төменгі (машина тіліне жақын) деңгейде жүзеге асырылуымен байланысты. Егер күтпеген нәтижелер алсаңыз, қарапайым, бірақ жиі кездесетін қателік жіберіп жатырсыз ба деп өзіңізден сұраңыз.

Тізімдегі екінші элементтің индексі 1. Бұл санау жүйесін пайдаланып, тізімдегі орнынан бірді алып тастау арқылы тізімнен қалаған кез-келген элементті алуға болады. Мысалы, тізімдегі төртінші элементке қол жеткізу үшін 3-индекстегі элементті сұрайсыз.

Келесі код 1 индексіндегі және 3 индексіндегі велосипедтерді сұрайды:


        bicycles = ['trek', 'cannondale', 'redline', 'specialized']
        print(bicycles[1])
        print(bicycles[3])

Бұл код тізімдегі екінші және төртінші велосипедтерді қайтарады:


        cannondale
        specialized

Python-да тізімдегі соңғы элементке қол жеткізуге арналған арнайы синтаксис бар. Егер сіз -1 индексіндегі элементті сұрасаңыз, Python әрқашан тізімдегі соңғы элементті қайтарады:


        bicycles = ['trek', 'cannondale', 'redline', 'specialized']
        print(bicycles[-1])

Бұл код 'specialized' мәнін қайтарады. Бұл синтаксис өте пайдалы, себебі сіз тізімнің ұзақтығын білмей-ақ тізімдегі соңғы элементтерге жиі қол жеткізгіңіз келеді. Бұл конвенция басқа теріс индекс мәндеріне де таралады. -2 индексі тізімнің соңынан екінші элементті қайтарады, -3 индексі соңынан үшінші элементті қайтарады және т.б.

Тізімдегі жеке мәндерді пайдалану

Тізімдегі жеке мәндерді кез-келген басқа айнымалы сияқты пайдалануға болады. Мысалы, тізімдегі мәнге негізделген хабарлама жасау үшін f-strings пайдалануға болады.

Тізімнен бірінші велосипедті шығарып көрейік және сол мәнді пайдаланып хабар жазайық:


        bicycles = ['trek', 'cannondale', 'redline', 'specialized']
        message = f"My first bicycle was a {bicycles[0].title()}."
        
        print(message)

Біз bicycles[0] мәнін пайдаланып сөйлем құраймыз және оны message айнымалысына тағайындаймыз. Шығару тізімдегі бірінші велосипед туралы қарапайым сөйлем:


        My first bicycle was a Trek.

Элементтерді өзгерту, қосу және жою

Сіз жасайтын тізімдердің көпшілігі динамикалық болады, яғни бағдарлама өз курсын орындаған кезде тізімді құрасыз, содан кейін оған элементтерді қосасыз және жоясыз. Мысалы, ойыншы бөтен планеталықтарды (aliens, инопланетяне) аспаннан атуы керек ойын жасай аласыз. Бөтен планеталықтардың бастапқы жинағын тізімде сақтауға болады, содан кейін бөтен планеталықты атып түсірген сайын тізімнен алып тастауға болады. Экранда жаңа бөтен планеталық пайда болған сайын оны тізімге қосасыз. Бөтен планеталықтар тізімі ойын барысында ұзарады және қысқарады.

Тізімдегі элементтерді өзгерту

Элементті өзгерту синтаксисі тізімдегі элементке қатынасу синтаксисіне ұқсас. Элементті өзгерту үшін тізімнің атын, одан кейін өзгерткіңіз келетін элементтің индексін пайдаланыңыз, содан кейін сол элементке тағайындағыңыз келетін жаңа мәнді беріңіз.

Мысалы, бізде мотоциклдер тізімі бар делік және тізімдегі бірінші элемент 'honda'. Бұл бірінші элементтің мәнін тізім жасалғаннан кейін өзгерте аламыз:

motorcycles.py


        motorcycles = ['honda', 'yamaha', 'suzuki']
        print(motorcycles)
        
        motorcycles[0] = 'ducati'
        print(motorcycles)

Мұнда біз бірінші элемент ретінде 'honda' болатын мотоциклдер тізімін анықтаймыз. Содан кейін бірінші элементтің мәнін 'ducati' етіп өзгертеміз. Шығару бірінші элементтің өзгертілгенін көрсетеді, ал тізімнің қалған бөлігі өзгеріссіз қалады:


        ['honda', 'yamaha', 'suzuki']
        ['ducati', 'yamaha', 'suzuki']

Тізімдегі бірінші элементтің ғана емес, кез-келген элементтің мәнін өзгертуге болады.

Тізімге элементтер қосу

Көптеген себептерге байланысты тізімге жаңа элемент қосқыңыз келуі мүмкін. Мысалы, ойында жаңа өзге планеталықтардың пайда болуын, визуализацияға жаңа деректерді қосуды немесе өзіңіз жасаған веб-сайтқа жаңа тіркелген пайдаланушыларды қосқыңыз келуі мүмкін. Python бар тізімдерге жаңа деректерді қосудың бірнеше жолын ұсынады.

Тізім соңына элементтер қосу

Тізімге жаңа элемент қосудың ең қарапайым жолы - элементті тізімге қосу/append. Элементті тізімге қосқанда, жаңа элемент тізімнің соңына қосылады. Алдыңғы мысалдағыдай тізімді пайдаланып, тізімнің соңына жаңа 'ducati' элементін қосамыз:


        motorcycles = ['honda', 'yamaha', 'suzuki']
        print(motorcycles)
        
        motorcycles.append('ducati')
        print(motorcycles)

Мұнда append() әдісі тізімнің басқа элементтерінің ешқайсысына әсер етпей, тізімнің соңына 'ducati' қосады:


        ['honda', 'yamaha', 'suzuki']
        ['honda', 'yamaha', 'suzuki', 'ducati']

append() әдісі тізімдерді динамикалық түрде құруды жеңілдетеді. Мысалы, бос тізімнен бастай аласыз, содан кейін append() шақыруларының қатарын пайдаланып тізімге элементтерді қоса аласыз. Бос тізімді пайдаланып, тізімге 'honda', 'yamaha' және 'suzuki' элементтерін қосайық:


        motorcycles = []
        
        motorcycles.append('honda')
        motorcycles.append('yamaha')
        motorcycles.append('suzuki')
        
        print(motorcycles)

Нәтижедегі тізім алдыңғы мысалдардағы тізімдермен бірдей көрінеді:


        ['honda', 'yamaha', 'suzuki']

Тізімдерді құрудың бұл әдісі өте кең таралған, себебі бағдарлама іске қосылғанға дейін пайдаланушылар бағдарламада сақтағысы келетін деректерді жиі біле алмайсыз. Тізімді басқаруды қолданушыларға беру үшін қолданушылардың мәндерін сақтайтын бос тізімді анықтаудан бастаңыз. Содан кейін берілген әрбір жаңа мәнді осы жасаған тізімге қосыңыз.

Тізімге элементтерді енгізу

Жаңа элементті insert() әдісі арқылы тізімдегі кез-келген орынға қосуға болады. Мұны жаңа элементтің индексі мен жаңа элементтің мәнін көрсету арқылы орындайсыз:


        motorcycles = ['honda', 'yamaha', 'suzuki']
        
        motorcycles.insert(0, 'ducati')
        print(motorcycles)

Бұл мысалда тізімнің басына 'ducati' мәнін енгіземіз. insert() әдісі 0 позициясында бос орынды ашады және 'ducati' мәнін сол жерде сақтайды:


        ['ducati', 'honda', 'yamaha', 'suzuki']

Бұл әрекет тізімдегі әрбір басқа мәнді бір позицияға оңға жылжытады.

Тізімнен элементтерді жою

Көбінесе тізімнен элементті немесе элементтер жинағын өшіргіңіз келеді. Мысалы, ойыншы бөтен планеталықты аспаннан атып түсіргенде, сіз оны белсенді өзге планеталықтар тізімінен алып тастағыңыз келуі мүмкін. Немесе пайдаланушы сіз жасаған веб-бағдарламада аккаунт, жеке жазбасынан бас тартуды шешкенде, ол пайдаланушыны белсенді пайдаланушылар тізімінен жойғыңыз келеді. Элементті тізімдегі орнына немесе мәніне қарай жоюға болады.

del амалы арқылы элементті жою

Егер тізімнен жойғыңыз келетін элементтің орнын білсеңіз, del амалын пайдалана аласыз:


        motorcycles = ['honda', 'yamaha', 'suzuki']
        print(motorcycles)
        
        del motorcycles[0]
        print(motorcycles)

Мұнда мотоциклдер тізімінен бірінші элементті, 'honda' жою үшін del операторын қолданамыз:


        ['honda', 'yamaha', 'suzuki']
        ['yamaha', 'suzuki']

Егер оның индексін білсеңіз, del операторы арқылы тізімдегі кез-келген орыннан элементті жоюға болады. Мысалы, 'yamaha' деген екінші элементті тізімнен қалай алып тастау керек:


        motorcycles = ['honda', 'yamaha', 'suzuki']
        print(motorcycles)
        
        del motorcycles[1]
        print(motorcycles)

Екінші мотоцикл тізімнен жойылды:


        ['honda', 'yamaha', 'suzuki']
        ['honda', 'suzuki']

Екі мысалда del амалы пайдаланылғаннан кейін тізімнен жойылған мәнге енді қол жеткізе алмайсыз.

pop() әдісі арқылы элементті жою

Кейде элементті тізімнен жойғаннан кейін оның мәнін пайдаланғыңыз келеді. Мысалы, жаңа ғана атып түсірілген бөтен планеталықтың x және y позициясын алғыңыз келуі мүмкін, осылайша сол позицияда жарылыс салуға болады. Веб қолданбасында пайдаланушыны белсенді мүшелер тізімінен алып тастап, одан кейін сол пайдаланушыны белсенді емес мүшелер тізіміне қосқыңыз келуі мүмкін.

pop() әдісі тізімдегі соңғы элементті жояды, бірақ оны жойғаннан кейін сол элементпен жұмыс істеуге мүмкіндік береді. pop термині тізімді элементтер дестесі ретінде ойлаудан және бір элементті стектің жоғарғы жағынан шығару деген ұғымнан шыққан. Бұл аналогта стектің жоғарғы элементі тізімнің соңғы элементіне сәйкес келеді.

Мотоциклдер тізімінен мотоциклді шығарып көрейік:


         motorcycles = ['honda', 'yamaha', 'suzuki']
        print(motorcycles)
        
         popped_motorcycle = motorcycles.pop()
         print(motorcycles)
         print(popped_motorcycle)

Біз мотоциклдер ❶ тізімін анықтау және басып шығарудан бастаймыз. Содан кейін тізімнен мәнді шығарып, сол мәнді popped_motorcycle ❷ айнымалысына тағайындаймыз. Мәннің тізімнен жойылғанын көрсету үшін ❸ тізімді басып шығарамыз. Содан кейін жойылған мәнге әлі де қол жеткізе алатынымызды дәлелдеу үшін ❹ алып тасталған мәнді басып шығарамыз.

Шығыс 'suzuki' мәні тізімнің соңынан жойылғанын және енді popped_motorcycle айнымалысына тағайындалғанын көрсетеді:


        ['honda', 'yamaha', 'suzuki']
        ['honda', 'yamaha']
        suzuki

Бұл pop() әдісі қалай пайдалы болуы мүмкін? Елестетіп көріңізші, тізімдегі мотоциклдер оларды иелік ету мерзіміне сәйкес хронологиялық тәртіпте сақталып тұр делік. Олай болса, біз соңғы сатып алған мотоцикл туралы амалды басып шығару үшін pop() әдісін пайдалана аламыз:


        motorcycles = ['honda', 'yamaha', 'suzuki']
        
        last_owned = motorcycles.pop()
        print(f"The last motorcycle I owned was a {last_owned.title()}.")

Шығармада біздегі ең соңғы мотоцикл туралы қарапайым сөйлем:


        The last motorcycle I owned was a Suzuki.
Тізімдегі кез-келген орыннан элементтерді шығару

Жойылатын элементтің индексін жақшаға қосу арқылы тізімдегі кез-келген орыннан элементті жою үшін pop() әдісін пайдалана аласыз:


        motorcycles = ['honda', 'yamaha', 'suzuki']
        
        first_owned = motorcycles.pop(0)
        print(f"The first motorcycle I owned was a {first_owned.title()}.")

Біз тізімдегі бірінші мотоциклді шығарудан бастаймыз, содан кейін сол мотоцикл туралы хабарды басып шығарамыз. Шығарылым менің иелігімдегі алғашқы мотоциклді сипаттайтын қарапайым сөйлем:


        The first motorcycle I owned was a Honda.

pop() әдісін пайдаланған сайын, сіз жұмыс істейтін элемент енді тізімде сақталмайтынын есте сақтаңыз.

Егер del амалынан немесе pop() әдісін пайдалану керектігін білмесеңіз, оны шешудің қарапайым жолы бар: элементті толық жойа отырып оны ешбір жолмен пайдаланбайтын болсаңыз del операторын пайдаланыңыз; ал егер сіз оны жою кезінде элементті пайдаланғыңыз келсе, pop() әдісін пайдаланыңыз.

Мәні бойынша элементті жою

Кейде тізімнен өшіргіңіз келетін мәннің орнын білмейсіз. Егер сіз жойғыңыз келетін элементтің мәнін ғана білсеңіз, remove() әдісін пайдалана аласыз.

Мысалы, мотоциклдер тізімінен 'ducati' мәнін жойғымыз келеді делік:


        motorcycles = ['honda', 'yamaha', 'suzuki', 'ducati']
        print(motorcycles)
        
        motorcycles.remove('ducati')
        print(motorcycles)

Мұнда remove() әдісі Python-ға тізімде 'ducati' қай жерде пайда болатынын анықтауды және сол элементті жоюды айтады:


        ['honda', 'yamaha', 'suzuki', 'ducati']
        ['honda', 'yamaha', 'suzuki']

Сонымен қатар тізімнен жойылатын мәнмен жұмыс істеу үшін remove() әдісін пайдалануға болады. 'ducati' мәнін алып тастап, оны тізімнен алып тастау себебін басып шығарайық:


         motorcycles = ['honda', 'yamaha', 'suzuki', 'ducati']
        print(motorcycles)
        
         too_expensive = 'ducati'
         motorcycles.remove(too_expensive)
        print(motorcycles)
         print(f"\nA {too_expensive.title()} is too expensive for me.")

motorcycles тізімін анықтағаннан кейін too_expensive деп аталатын айнымалыға 'ducati' мәнін тағайындаймыз. ❷ Содан кейін бұл айнымалы мәнді Python жүйесіне ❸ тізімінен қай мәнді жою керектігін айту үшін пайдаланамыз. 'ducati' мәні ❹ тізімінен жойылды, бірақ әлі де too_expensive айнымалысы арқылы қол жетімді, соның арқасында мотоциклдер тізімінен 'ducati' мотоциклін неліктен алып тастағанымыз туралы амалды басып шығаруға мүмкіндік болады:


        ['honda', 'yamaha', 'suzuki', 'ducati']
        ['honda', 'yamaha', 'suzuki']
        
        A Ducati is too expensive for me.

Тізімді ұйымдастыру

Көбінесе тізімдер алдын ала болжауға келмейтін тәртіпте жасалады, себебі пайдаланушылар деректерін беру ретін әрқашан басқара алмайсыз. Көптеген жағдайларда одан қашып құтыла алмағанмен, сіз жиі өз ақпаратыңызды белгілі бір ретпен ұсынғыңыз келеді. Кейде тізіміңіздің бастапқы ретін сақтағыңыз келеді, ал басқа уақытта бастапқы тізім ретін өзгерткіңіз келеді. Python жағдайға байланысты тізімдеріңізді ұйымдастырудың бірнеше түрлі жолдарын ұсынады.

sort() әдісімен тізімді тұрақты түрде сұрыптау

Python-ның sort() әдісі тізімді сұрыптауды салыстырмалы түрде жеңілдетеді. Бізде көліктер тізімі бар және оларды алфавит бойынша сақтау үшін тізімнің ретін өзгерткіміз келеді делік. Тапсырманы қарапайым ету үшін тізімдегі барлық мәндер кіші әріппен жазылады делік:

cars.py


        cars = ['bmw', 'audi', 'toyota', 'subaru']
        cars.sort()
        print(cars)

sort() әдісі тізім ретін біржола өзгертеді. Көліктер енді алфавиттік тәртіпте және біз ешқашан бастапқы ретке қайта алмаймыз:


        ['audi', 'bmw', 'subaru', 'toyota']

Сонымен қатар reverse=True аргументін sort() әдісіне беру арқылы бұл тізімді кері алфавиттік ретпен сұрыптауға болады. Келесі мысал автокөліктер тізімін кері алфавиттік ретпен сұрыптайды:


        cars = ['bmw', 'audi', 'toyota', 'subaru']
        cars.sort(reverse=True)
        print(cars)

Тағы да тізімнің реті біржола өзгереді:


        ['toyota', 'subaru', 'bmw', 'audi']

Sorted() функциясы арқылы тізімді уақытша сұрыптау

Тізімнің бастапқы ретін сақтау, бірақ оны сұрыпталған ретпен көрсету үшін sorted() функциясын пайдалануға болады. sorted() функциясы тізімді белгілі бір ретпен көрсетуге мүмкіндік береді, бірақ тізімнің нақты ретіне әсер етпейді.

Бұл функцияны көліктер тізімінде қолданып көрейік.


        cars = ['bmw', 'audi', 'toyota', 'subaru']
        
         print("Here is the original list:")
        print(cars)
        
         print("\nHere is the sorted list:")
        print(sorted(cars))
        
         print("\nHere is the original list again:")
        print(cars)

Біз алдымен тізімді бастапқы ретімен ❶, содан кейін алфавиттік тәртіппен басып шығарамыз. Тізім жаңа ретпен көрсетілгеннен кейін, біз тізім әлі де бастапқы ретімен сақталғанын көреміз ❸:


        Here is the original list:
        ['bmw', 'audi', 'toyota', 'subaru']
        
        Here is the sorted list:
        ['audi', 'bmw', 'subaru', 'toyota']
        
         Here is the original list again:
        ['bmw', 'audi', 'toyota', 'subaru']

sorted() функциясы пайдаланылғаннан кейін тізім әлі де бастапқы ретімен ❶ бар екенін ескеріңіз. sorted() функциясы тізімді кері алфавиттік тәртіпте көрсеткіңіз келсе, reverse=True аргументін де қабылдай алады.

Тізімді кері ретпен басып шығару

Тізімнің бастапқы ретін өзгерту үшін reverse() әдісін қолдануға болады. Бастапқыда біз көліктер тізімін хронологиялық тәртіпте олардың иелік ету мерзіміне сәйкес сақтасақ, тізімді кері хронологиялық ретпен оңай реттей аламыз:


        cars = ['bmw', 'audi', 'toyota', 'subaru']
        print(cars)
        
        cars.reverse()
        print(cars)

reverse() алфавит бойынша кері сұрыптамайтынына назар аударыңыз; ол жай ғана тізімнің ретін өзгертеді:

        ['bmw', 'audi', 'toyota', 'subaru']
        ['subaru', 'toyota', 'audi', 'bmw']

reverse() әдісі тізім ретін біржолата өзгертеді, бірақ сол тізімге бір секундтан кейін reverse() қолдану арқылы бастапқы ретке кез-келген уақытта оралуға болады. уақыт.

Тізім ұзындығын табу

Тізім ұзындығын len() функциясын пайдалану арқылы жылдам табуға болады. Бұл мысалдағы тізімде төрт элемент бар, сондықтан оның ұзындығы 4:


        >>> cars = ['bmw', 'audi', 'toyota', 'subaru']
        >>> len(cars)
        4

len() ойында әлі де атылуы қажет өзге планеталықтардың санын анықтау, визуализацияда басқаруға тиіс деректер көлемін анықтау қажет болғанда пайдалы болады. , немесе басқа тапсырмалармен қатар веб-сайтта тіркелген пайдаланушылар санын анықтаңыз.

Тізімдермен жұмыс істеу кезіндегі индекс қателерін болдырмау

Тізімдермен бірінші рет жұмыс істегенде жиі кездесетін қатенің бір түрі бар. Сізде үш элементтен тұратын тізім бар делік және сіз төртінші элементті сұрадыңыз:

motorcycles.py


        motorcycles = ['honda', 'yamaha', 'suzuki']
        print(motorcycles[3])

Бұл мысал индекс қатесіне әкеледі:


        Traceback (most recent call last):
          File "motorcycles.py", line 2, in <module>
            print(motorcycles[3])
                  ~~~~~~~~~~~^^^
        IndexError: list index out of range

Python сізге 3-индекстегі элементті беруге тырысады. Бірақ ол тізімді іздеген кезде, motorcycles ішіндегі бірде-бір элементте 3 индекс болмайды. Тізімдерде индекстеу off-by-one болғандықтан, тізімдерге бұл қате тән. (off-by-one деп отырғаны, 0-индексте 1-элемент, 1-индескте 2-элемент т.с.с кете беретіні айтылып тұр) Адамдар үшінші орында 3-элемент деп ойлайды, өйткені олар 1-ден санай бастайды. Бірақ Python-да үшінші элемент 2-ші нөмірде, себебі ол 0-ден индекстеуді бастайды.

Индекс қатесі Python сіз сұраған индекстен элементті таба алмайтынын білдіреді. Егер бағдарламаңызда индекс қатесі орын алса, сұралған индексті бір ретке келтіріп көріңіз. Содан кейін нәтижелердің дұрыс екенін көру үшін бағдарламаны қайта іске қосыңыз.

Тізімдегі соңғы элементке қол жеткізгіңіз келсе, -1 индексін пайдалану керек екенін есте сақтаңыз. Тізім соңғы рет кіріп көргеннен кейін өлшемі өзгерсе де, бұл әрқашан жұмыс істейді:


        motorcycles = ['honda', 'yamaha', 'suzuki']
        print(motorcycles[-1])

-1 индексі әрқашан тізімдегі соңғы элементті қайтарады, бұл жағдайда 'suzuki' мәні:


        suzuki

Бұл әдіс бос тізімнен соңғы элементті сұраған кезде ғана қателік туғызады:


        motorcycles = []
        print(motorcycles[-1])

motorcycles ішінде ешбір элемент жоқ, сондықтан Python басқа индекс қатесін қайтарады:


        Traceback (most recent call last):
          File "motorcyles.py", line 3, in <module>
            print(motorcycles[-1])
                  ~~~~~~~~~~~^^^^
        IndexError: list index out of range

Егер индекс қатесі орын алса және оны шешу жолын таба алмасаңыз, тізіміңізді басып шығарып көріңіз немесе тізімнің ұзындығын басып шығарыңыз. Сіздің тізіміңіз сіз ойлағаннан әлдеқайда өзгеше болуы мүмкін, әсіресе оны сіздің бағдарламаңыз динамикалық түрде басқарса. Нақты тізімді немесе тізімдегі элементтердің нақты санын көру осындай логикалық қателерді сұрыптауға көмектеседі.

Қорытынды

Бұл тарауда сіз тізімдер деген не екенін және тізімдегі жеке элементтермен қалай жұмыс істеу керектігін білдіңіз. Сіз тізімді анықтауды және элементтерді қосу және жою жолын үйрендіңіз. Көрсету мақсатында тізімдерді тұрақты және уақытша сұрыптауды үйрендіңіз. Сондай-ақ тізімнің ұзындығын қалай табуға болатынын және тізімдермен жұмыс істегенде индекс қателерін болдырмауды үйрендіңіз.

4-тарауда тізімдегі элементтермен тиімдірек жұмыс істеуді үйренесіз. Кодтың бірнеше жолын пайдаланып тізімдегі әрбір элементті айналдыра отырып, тіпті тізімде мыңдаған немесе миллиондаған элементтер болса да, тиімді жұмыс істей аласыз.

Тізімдермен жұмыс істеу

ITUniver

4
Тізімдермен жұмыс істеу

3-тарауда қарапайым тізім жасауды үйрендіңіз және тізімдегі жеке элементтермен жұмыс істеуді үйрендіңіз. . Бұл тарауда тізімнің ұзақтығына қарамастан, бірнеше код жолын пайдаланып, бүкіл тізімді қалай айналдыру керектігін үйренесіз. Цикл тізімдегі әрбір элементпен бірдей әрекетті немесе әрекеттер жинағын орындауға мүмкіндік береді. Нәтижесінде мыңдаған, тіпті миллиондаған элементтерді қоса алғанда, кез-келген ұзындықтағы тізімдермен тиімді жұмыс істей аласыз.

Бүкіл тізім бойынша айналым

Бағдарламаларда әрбір элементпен бірдей тапсырманы орындай отырып, тізімдегі барлық жазбаларды тексеретін жағдай жиі болады. Мысалы, ойында экрандағы әрбір элементті бірдей мөлшерде жылжытқыңыз келуі мүмкін. Сандар тізімінде әрбір элементте бірдей статистикалық әрекетті орындағыңыз келуі мүмкін. Немесе сіз веб-сайттағы мақалалар тізімінен әрбір тақырыпты көрсеткіңіз келуі мүмкін. Тізімдегі әрбір элементпен бірдей әрекетті орындағыңыз келсе, Python бағдарламасының for циклін пайдалана аласыз.

Бізде сиқыршылардың есімдерінің тізімі бар және тізімдегі әрбір атауды басып шығарғымыз келеді делік. Біз мұны тізімнен әрбір атауды жеке-жеке шығарып алу арқылы жасай аламыз, бірақ бұл тәсіл бірнеше мәселені тудыруы мүмкін. Біріншіден, мұны атаулардың ұзақ тізімімен жасау қайта-қайта бір әрекетті қайталауды талап етеді. Сондай-ақ, тізімнің ұзындығы өзгерген сайын кодымызды өзгертуге тура келеді. for циклін пайдалану Python-ға бұл мәселелерді ішкі басқаруға мүмкіндік беру арқылы осы қос мәселенің екеуін де болдырмайды.

Сиқыршылар тізіміндегі әрбір атауды басып шығару үшін for циклін қолданайық:

magicians.py


        magicians = ['alice', 'david', 'carolina']
        for magician in magicians:
            print(magician)

Біз 3-тараудағы сияқты тізімді анықтаудан бастаймыз. Содан кейін for циклін анықтаймыз. Бұл жол Python-ға magicians тізімінен атауды шығарып, оны magician айнымалысымен байланыстыруды тапсырады. Содан кейін біз Python-ға magician-ға тағайындалған атауды басып шығаруды айтамыз. Содан кейін Python осы соңғы екі әрекетті тізімдегі әрбір атау үшін бір рет қайталайды. Бұл кодты «Сиқыршылар тізіміндегі әрбір сиқыршы үшін сиқыршының атын басып шығарыңыз» деп оқу көмектесуі мүмкін. Ал print тізімдегі әрбір атауды қарапайым басып шығару болып табылады:


        alice
        david
        carolina

Циклге жақынырақ қарау

Цикл маңызды, себебі, компьютерлер қайталанатын тапсырмаларды автоматтандырудың ең кең тараған тәсілдерінің бірі осы циклді пайдалану. Мысалы, біз magicians.py ішінде пайдаланған қарапайым циклде Python бастапқыда циклдің бірінші жолын оқиды:


        for magician in magicians:

Бұл жол Python-ға magicians тізімінен бірінші мәнді шығарып алуды және оны magician айнымалысымен байланыстыруды айтады. Бұл бірінші мән 'alice'. Содан кейін Python келесі жолды оқиды:


          print(magician)

Python әлі 'alice' болып табылатын ағымдағы magician мәнін басып шығарады. Тізімде көбірек мәндер болғандықтан, Python циклдің бірінші жолына қайтады:


        for magician in magicians:

Python тізімдегі келесі атауды, 'david' алады және бұл мәнді magician айнымалысымен байланыстырады. Содан кейін Python келесі жолды орындайды:


          print(magician)

Python magician қолданбасының ағымдағы мәнін қайтадан басып шығарады, ол енді 'david'. Python бүкіл циклды тізімдегі соңғы мәнмен тағы бір рет қайталайды, 'carolina'. Тізімде басқа мәндер болмағандықтан, Python бағдарламаның келесі жолына өтеді. Бұл жағдайда for циклінен кейін ештеңе келмейді, сондықтан бағдарлама аяқталады.

Циклдерді бірінші рет пайдаланған кезде тізімде қанша элемент болса да, қадамдар жинағы тізімдегі әрбір элемент үшін бір рет қайталанатынын есте сақтаңыз. Тізімде миллион элемент болса, Python бұл қадамдарды миллион рет қайталайды және әдетте өте жылдам.

Өзіңіз for циклін жазғанда есте сақтайтын тағы бір нәрсе тізімдегі әрбір элементпен байланыстырылатын уақытша айнымалы үшін қалаған кез-келген атауды таңдауға болады. Дегенмен, тізімнен бір элементті білдіретін мағыналы атауды таңдау пайдалы. Мысалы, мысықтар тізімі, иттер тізімі және элементтердің жалпы тізімі үшін for циклін бастаудың жақсы жолы:


        for cat in cats:
        for dog in dogs:
        for item in list_of_items:

Бұл атау конвенциялары for цикліндегі әрбір элементте орындалатын әрекетті қадағалауға көмектеседі. Дара және көпше атауларды пайдалану код бөлімі тізімдегі бір элементпен немесе бүкіл тізіммен жұмыс істейтінін анықтауға көмектеседі.

For циклінде көбірек жұмыс істеу

Сіз for цикліндегі әрбір элементпен шамамен кез-келген нәрсені жасай аласыз. Әрбір сиқыршыға керемет трюк жасағанын айтып, хабарлама басып шығару арқылы алдыңғы мысалға сүйенейік:

magicians.py


        magicians = ['alice', 'david', 'carolina']
        for magician in magicians:
            print(f"{magician.title()}, that was a great trick!")

Бұл кодтың жалғыз айырмашылығы - біз әр сиқыршыға сол сиқыршының аты-жөнінен бастап хабарлама құрастырамыз. Цикл арқылы бірінші рет magician мәні 'alice' болады, сондықтан Python бірінші хабарды 'Алиса' атымен бастайды. Екінші рет өткенде хабар 'David' деп басталады, ал үшінші рет өткенде, хабар 'Каролина' деп басталады.

Шығыс тізімдегі әрбір сиқыршы үшін жекелендірілген хабарламаны көрсетеді:


        Alice, that was a great trick!
        David, that was a great trick!
        Carolina, that was a great trick!

Сондай-ақ for циклінің ішінде код жолының кез-келген санын жаза аласыз. for magician in magicians жолынан кейінгі әрбір шегініс жол цикл ішінде /inside the loop деп қарастырылады және әрбір шегініс жол тізімдегі әрбір мән үшін бір рет орындалады. Сондықтан тізімдегі әрбір мәнмен қалағаныңызша жұмыс жасай аласыз.

Хабарымызға екінші жолды қосып, әрбір сиқыршыға олардың келесі айла-ғажабын асыға күтетінімізді айтамыз:


        magicians = ['alice', 'david', 'carolina']
        for magician in magicians:
            print(f"{magician.title()}, that was a great trick!")
            print(f"I can't wait to see your next trick, {magician.title()}.\n")

print() параметріне шақыруды екі жолда да шегіндіргендіктен, әрбір жол тізімдегі әрбір сиқыршы үшін бір рет орындалады. Екінші print() шақыруындағы жаңа жол ("\n") цикл арқылы әрбір өткеннен кейін бос жолды кірістіреді. Бұл, тізімдегі әрбір адам үшін дұрыс топтастырылған хабарлар жинағын жасайды:


        Alice, that was a great trick!
        I can't wait to see your next trick, Alice.
        
        David, that was a great trick!
        I can't wait to see your next trick, David.
        
        Carolina, that was a great trick!
        I can't wait to see your next trick, Carolina.

Сіз for циклдерінде қалағаныңызша жолдарды пайдалана аласыз. Шын өмірде-бағдарламаңызда for циклін пайдаланған кезде тізімдегі әрбір элементпен бірнеше түрлі әрекеттерді орындау жиі пайдалы болады.

for циклінен кейін бірдеңе жасау

for циклі орындалып болғаннан кейін не болады? Әдетте, сіз шығыс код блогын қорытындылауды немесе бағдарламаңыз орындауы керек басқа жұмысқа көшуді қалайсыз.

for циклінен кейін шегініссіз жазылған кез-келген код жолдары қайталанбай бір рет орындалады. Жалпы сиқыршылар тобына тамаша қойылым көрсеткендері үшін алғысымызды білдірейік. Барлық жеке хабарлар басып шығарылғаннан кейін осы топтық хабарды көрсету үшін біз алғыс хабарламасын for циклінен кейін шегініссіз орналастырамыз:


        magicians = ['alice', 'david', 'carolina']
        for magician in magicians:
            print(f"{magician.title()}, that was a great trick!")
            print(f"I can't wait to see your next trick, {magician.title()}.\n")
        
        print("Thank you, everyone. That was a great magic show!")

print() әдісіне алғашқы екі шақыру, бұрын көргеніңіздей, тізімдегі әрбір сиқыршы үшін бір рет қайталанады. Дегенмен, соңғы жол шегініссіз болғандықтан, ол тек бір рет басып шығарылады:


        Alice, that was a great trick!
        I can't wait to see your next trick, Alice.
        
        David, that was a great trick!
        I can't wait to see your next trick, David.
        
        Carolina, that was a great trick!
        I can't wait to see your next trick, Carolina.
        
        Thank you, everyone. That was a great magic show!

Деректерді for циклі арқылы өңдеген кезде, шегініссіз жаңа код жолын жазу бүкіл деректер-жиынында орындалған әрекетті қорытындылаудың жақсы әдісі екенін көресіз. Мысалы, ойынды инициализациялау үшін for циклін ойынның кейіпкерлер тізімін қарап шығу және экранда әрбір кейіпкерді басып шығару арқылы пайдалануға болады. Содан кейін экранға барлық кейіпкерлер тартылғаннан кейін Ойынды бастау түймесі көрсетілетін осы циклден кейін қосымша код жазуыңызға болады.

Шегініс қателерін болдырмау

Python код жолы немесе код жолдар тобының бағдарламаның қалған бөлігімен байланысын анықтау үшін шегіністерді пайдаланады. Алдыңғы мысалдарда жеке сиқыршыларға хабарламаларды басып шығаратын жолдар for циклінің бөлігі болды, себебі олар шегініспен жазылған. Python шегінісін пайдалану кодты оқуды өте оңай етеді. Негізінде Python анық көрнекі құрылымы бар ұқыпты пішімделген кодты жазуға мәжбүрлеу үшін бос орынды пайдаланады деп айтсақ та болады. Ұзақ Python бағдарламаларында сіз бірнеше түрлі деңгейлерде шегінген код блоктарын байқайсыз. Бұл шегініс деңгейлері жалпы бағдарлама ұйымы туралы шолып түсінік алуға көмектеседі.

Дұрыс шегініске негізделген кодты жазуды бастағанда, бірнеше жалпы шегініс қателері / indentation errors бар екенін біліп жүріңіз. Мысалы, адамдар кейде шегіністі қажет етпейтін код жолдарын шегіндіреді немесе шегінісін қажет ететін жолдарды шегінуді ұмытады. Бұл қателердің мысалдарын қазір көру болашақта оларды болдырмауға және олар жеке бағдарламаларыңызда пайда болған кезде оларды түзетуге көмектеседі.

Кең таралған шегініс қателерінің кейбірін қарастырайық.

Шегіністі ұмыту

Әрқашан циклдегі for операторынан кейінгі жолды шегіндіріңіз. Ұмытып қалсаңыз, Python сізге мынаны еске салады:

magicians.py


        magicians = ['alice', 'david', 'carolina']
        for magician in magicians:
         print(magician)

print() әдісін шақыру шегінуі керек, бірақ бұл жерде олай емес. Python шегінген блокты күткенде және оны таппағанда, ол қай жолда ақаулық бар екенін білуге мүмкіндік береді:

  File "magicians.py", line 3
            print(magician)
            ^
        IndentationError: expected an indented block after 'for' statement on line 2

Әдетте мұндай шегініс қатесін for амалынан кейін бірден жолды немесе жолдарды шегініс жасау арқылы шешуге болады.

Басқа қосымша жолдарды шегінуді ұмыту

Кейде сіздің циклыңыз қатесіз орындалады, бірақ күтілетін нәтиже бермейді. Бұл циклде бірнеше тапсырманы орындауға тырысқанда және оның кейбір жолдарын шегіністі ұмытып кеткенде орын алуы мүмкін.

Мысалы, әрбір сиқыршыға келесі трюкті асыға күтетінімізді көрсететін циклдегі екінші жолдағы шегіністі ұмытып кеткенімізде осылай болады:


        magicians = ['alice', 'david', 'carolina']
        for magician in magicians:
            print(f"{magician.title()}, that was a great trick!")
         print(f"I can't wait to see your next trick, {magician.title()}.\n")

print() ❶ екінші рет шақырылғанда шегініс болуы керек, бірақ Python кем дегенде біреуін тапқандықтан for амалынан кейінгі шегініс жолында ол қате туралы есеп бермейді. Нәтижесінде, бірінші print() шақыруы тізімдегі әрбір атау үшін бір рет орындалады, себебі ол шегініспен белгіленеді. Екінші print() шақыруы шегініссіз, сондықтан ол цикл жұмысы аяқталғаннан кейін бір рет орындалады. magician-мен байланысты соңғы мән 'carolina' болғандықтан, ол «келесі трюкті күтеміз» хабарын алатын жалғыз адам Каролина:


        Alice, that was a great trick!
        David, that was a great trick!
        Carolina, that was a great trick!
        I can't wait to see your next trick, Carolina.

Бұл логикалық қате. Синтаксис жарамды Python коды, бірақ код қалаған нәтижені бермейді, себебі оның логикасында мәселе туындайды. Тізімдегі әрбір элемент үшін бір рет қайталанатын белгілі бір әрекетті көргіңіз келсе және ол бір рет орындалса, жолға немесе жолдар тобына жай ғана шегініс жетпей тұрған жоқ па екенін анықтаңыз.

Қажетсіз шегініс

Егер сіз шегіністі қажет етпейтін жолды байқаусызда шегіндірсеңіз, Python сізге күтпеген шегініс туралы хабарлайды:

hello_world.py


        message = "Hello Python world!"
            print(message)

Бізге print() шақыруына шегініс жасаудың қажеті жоқ, себебі ол циклдің бөлігі емес; демек, Python қате туралы хабарлайды:


        File "hello_world.py", line 2
            print(message)
            ^
        IndentationError: unexpected indent

Нақты себеп, қажеттілік болған кезде ғана шегініс жасау арқылы күтпеген шегініс қателерінен аулақ бола аласыз. Осы алғашқы жазып жатқан бағдарламаларда for цикліндегі әрбір элемент үшін қайталағыңыз келетін әрекеттер шегініс жасауыңыз керек жалғыз жолдар.

Циклдан кейін қажетсіз шегініс

Егер цикл аяқталғаннан кейін іске қосылатын кодты байқаусызда шегіндірсеңіз, бұл код тізімдегі әрбір элемент үшін бір рет қайталанады. Кейде бұл Python қате туралы хабарлауға шақырады, бірақ көбінесе бұл логикалық қатеге әкеледі.

Мысалы, жақсы шоу көрсеткені үшін топ ретінде сиқыршыларға алғыс білдірген жолды байқаусызда шегіндірген кезде не болатынын көрейік:

magicians.py


        magicians = ['alice', 'david', 'carolina']
        for magician in magicians:
            print(f"{magician.title()}, that was a great trick!")
            print(f"I can't wait to see your next trick, {magician.title()}.\n")
        
           print("Thank you everyone, that was a great magic show!")

❶ Соңғы жолда шегініс болғандықтан, ол тізімдегі әрбір адам үшін бір рет басып шығарылады:


        Alice, that was a great trick!
        I can't wait to see your next trick, Alice.
        
        Thank you everyone, that was a great magic show!
        David, that was a great trick!
        I can't wait to see your next trick, David.
        
        Thank you everyone, that was a great magic show!
        Carolina, that was a great trick!
        I can't wait to see your next trick, Carolina.
        
        Thank you everyone, that was a great magic show!

Бұл «Басқа қосымша жолдарды шегінуді ұмыту» бөліміндегіге ұқсас тағы бір логикалық қате. Python сіз кодыңызбен не істеуге тырысып жатқаныңызды білмейді, ол жарамды синтаксисте жазылған барлық кодты іске қосады. Егер әрекет бірнеше рет қайталанса, ол тек бір рет орындалуы керек болса, код дұрыс жұмыс істеуі үшін артық шегіністі жою қажет болуы мүмкін.

Қос нүктені ұмыту

for операторының соңындағы қос нүкте Python-ға келесі жолды циклдің басы ретінде түсінуді ұсынады.


        magicians = ['alice', 'david', 'carolina']
         for magician in magicians
            print(magician)

❶ Егер қос нүктені қоюды байқаусызда ұмытып кетсеңіз, синтаксистік қатені аласыз, себебі Python нақты не істегіңіз келетінін білмейді:


        File "magicians.py", line 2
            for magician in magicians
                                     ^
        SyntaxError: expected ':'

Python қос нүктені ұмытып кеткеніңізді немесе күрделі циклды орнату үшін қосымша код жазғыңыз келетінін білмейді. Егер интерпретатор ықтимал түзетуді анықтай алса, ол осы жерде "expected ':' жолдың соңында қос нүкте күтіледі" деген сияқты біреуін ұсынады. Кейбір қателерді Python оңай тауып, оны түзетудің айқын, оңай жолдарын көрсете алады. Ал енді кейбір қателерді шешу қиынырақ, тіпті қажетті түзету тек бір таңба, кішкентай белгіше болса да. Кішкентай түзетуді табу үшін көп уақыт қажет болғанда, өзіңізді кінәлемеңіз; Сіз бұл тәжірибеде жалғыз емессіз.


Сандық тізімдер жасау

Сандар жинағын сақтаудың көптеген себептері бар. Мысалы, сіз ойындағы әрбір кейіпкердің орнын бақылап отыруыңыз керек және ойыншының жоғары ұпайларын да қадағалағыңыз келуі мүмкін. Деректерді визуализациялауда температуралар, қашықтықтар, популяция өлшемдері немесе ендік пен бойлық мәндері сияқты сандық жиындардың басқа түрлерімен бірге әрдайым дерлік жұмыс істейсіз.

Тізімдер сандар жиынын сақтау үшін өте қолайлы және Python сандар тізімдерімен тиімді жұмыс істеуге көмектесетін әртүрлі құралдарды ұсынады. Бұл құралдарды қалай тиімді пайдалану керектігін түсінгеннен кейін, тізімдеріңізде миллиондаған элементтер болса да, кодыңыз жақсы жұмыс істейді.

range() функциясын пайдалану

Python бағдарламасының range() функциясы сандар қатарын құруды жеңілдетеді. Мысалы, келесідей сандар қатарын басып шығару үшін range() функциясын пайдалануға болады:

first_numbers.py


        for value in range(1, 5):
            print(value)

Бұл код 1-ден 5-ке дейінгі сандарды басып шығару керек сияқты көрінгенімен, 5 санын басып шығармайды:


        1
        2
        3
        4

Бұл мысалда range() тек 1-ден 4-ке дейінгі сандарды басып шығарады. Бұл бағдарламалау тілдерінде жиі кездесетін бір-бірден басқа әрекеттің нәтижесі. range() функциясы Python-ды сіз берген бірінші мәнде санауды бастайды және ол сіз берген екінші мәнге жеткенде тоқтайды. Ол осы екінші мәнде тоқтайтындықтан, шығыс ешқашан бұл жағдайда 5 болатын соңғы мәнді қамтымайды.

1-ден 5-ке дейінгі сандарды басып шығару үшін range(1, 6) қолданасыз:


        for value in range(1, 6):
            print(value)

Бұл жолы шығыс 1-де басталып, 5-те аяқталады:


        1
        2
        3
        4
        5

Егер нәтиже range() пайдалану кезінде күткеннен өзгеше болса, соңғы мәнді 1-ге реттеп көріңіз.

Сонымен қатар range() тек бір аргумент жібере аласыз және ол сандар тізбегін 0-ден бастайды. Мысалы, range(6) сандарды қайтарады 0-ден 5-ке дейін.

Сандар тізімін жасау үшін range() функциясын пайдалану

Егер сандар тізімін жасағыңыз келсе, range() нәтижелерін list() функциясы арқылы тікелей тізімге түрлендіруге болады. list() функциясын range() функциясына шақыру айналасына орасаңыз, нәтиже сандар тізімі болады.

Алдыңғы бөлімдегі мысалда біз жай ғана сандар қатарын басып шығардық. Сол сандар жиынын тізімге түрлендіру үшін list() пайдалана аламыз:


        numbers = list(range(1, 6))
        print(numbers)

Бұл нәтиже:


        [1, 2, 3, 4, 5]

Сонымен қатар Python-ға кейбір сандарды өткізіп жібер деп айта аламыз, ол үшін range() функциясын пайдалана аламыз. Үшінші аргументті range() параметрі ретінде берсеңіз, Python сандарды жасау кезінде үшінші параметр мәнін қадам өлшемі ретінде пайдаланады.

Мысалы, 1 мен 10 арасындағы жұп сандарды қалай тізімдей аламыз:

even_numbers.py


        even_numbers = list(range(2, 11, 2))
        print(even_numbers)

Бұл мысалда range() функциясы 2 мәнінен басталады, содан кейін сол мәнге 2 қосады. Ол 11 соңғы мәнге жеткенше немесе өткенше 2 санын қайталап қосады және мына нәтижені шығарады:


        [2, 4, 6, 8, 10]

Сіз range() функциясын пайдалана отырып, кез-келген дерлік сандар жиынын жасай аласыз. Мысалы, алғашқы 10 санның дәреже (яғни, 1-ден 10-ға дейінгі әрбір бүтін санның квадраты) тізімін қалай жасауға болатынын қарастырыңыз. Python тілінде екі жұлдызша (**) дәрежені білдіреді. Алғашқы 10 санның дәрежесін тізімге қалай қоюға болады:

square_numbers.py


        squares = []
        for value in range(1, 11):
             square = value ** 2
             squares.append(square)
        
        print(squares)

Біз squares (дәреже) деп аталатын бос тізімнен бастаймыз. Содан кейін біз Python-ға range() функциясы арқылы 1-ден 10-ға дейінгі әрбір мәнді айналып өт деп айтамыз. Цикл ішінде ағымдағы мән дәрежеленеді және square ❶ айнымалысына тағайындалады. ❷ square әрбір жаңа мәні squares тізіміне қосылады. Соңында, цикл орындалып болған кезде, дәрежелер тізімі басып шығарылады:


        [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Бұл кодты қысқаша жазу үшін, уақытша square айнымалы мәнін қалдырыңыз және әрбір жаңа мәнді тікелей тізімге қосыңыз:


        squares = []
        for value in range(1,11):
            squares.append(value**2)
        
        print(squares)

Бұл жол алдыңғы тізімдегі for циклінің ішіндегі жолдар сияқты жұмыс істейді. Циклдегі әрбір мән дәрежеленеді, содан кейін бірден квадраттар тізіміне қосылады.

Күрделірек тізімдер жасаған кезде осы тәсілдердің кез келгенін пайдалануға болады. Кейде уақытша айнымалыны пайдалану кодты оқуды жеңілдетеді; басқа уақытта бұл кодты қажетсіз ұзартады. Бірінші кезекте сіз барынша түсінікті кодты жазуға назар аударыңыз және ол сіз қалаған нәрсені жасайтын болсын. Содан кейін кодты қарап шығу кезінде тиімдірек әдістерді іздеңіз.

Сандар тізімі бар қарапайым статистика

Сандар тізімдерімен жұмыс істеу кезінде бірнеше Python функциялары пайдалы. Мысалы, сандар тізімінің минималды, максимум және қосындысын оңай табуға болады:


        >>> digits = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
        >>> min(digits)
        0
        >>> max(digits)
        9
        >>> sum(digits)
        45

Тізімді түсіну / List Comprehensions

squares тізімін жасау үшін бұрын сипатталған тәсіл кодтың үш немесе төрт жолын пайдаланудан тұрды. Тізімді түсіну дәл сол тізімді кодтың бір жолында жасауға мүмкіндік береді. Тізімді түсіну for циклін және жаңа элементтерді құруды бір жолға біріктіреді және әрбір жаңа элементті автоматты түрде қосады. Тізімді түсіну әрқашан жаңадан бастаушыларға ұсынылмайды, бірақ мен оларды осында қостым, себебі сіз оларды басқа адамдардың кодын қарай бастағанда бірден көресіз.

Келесі мысал сіз бұрын көрген дәреже сандардың бірдей тізімін жасайды, бірақ тізімді түсінуді пайдаланады:

squares.py


        squares = [value**2 for value in range(1, 11)]
        print(squares)

Осы синтаксисті пайдалану үшін, тізімге түсінікті сипаттама беретін squares сияқты атаудан бастаңыз. Содан кейін тікбұрышты жақшалар жұбын ашыңыз және жаңа тізімде сақтағыңыз келетін мәндердің өрнегін анықтаңыз. Бұл мысалдағы өрнек мәнді екінші дәрежеге көтеретін value**2 болып табылады. Одан кейін өрнекке енгізгіңіз келетін сандарды жасау үшін for циклін жазыңыз және төртбұрышты жақшаны жабыңыз. Бұл мысалдағы for циклі 1-ден 10-ға дейінгі мәндерді value**2 амалына тағайындау арқылы түрлендіреді. for амалының соңында қос нүкте қойылмайтынын ескеріңіз.

Нәтиже сіз бұрын көрген дәрежеленген сандар тізімі болып табылады:


        [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Тізімді түсінуді өз бетіңізше жазу үшін тәжірибе қажет, бірақ қарапайым тізімдерді жасау ыңғайлы болғаннан кейін олардың пайдалы екенін табасыз. Тізімдерді жасау үшін кодтың үш немесе төрт жолын жазып жатқанда және ол қайталанатындай сезіне бастағанда, тізімді түсінуді өз бетіңізше жазуды қарастырыңыз.


Тізім бөлігімен жұмыс

3-тарауда тізімдегі жеке элементтерге қалай қол жеткізуге болатынын білдіңіз және осы тарауда тізімдегі элементтердің барлығымен жұмыс істеуді қарадық. Сондай-ақ Python тілінде slice/кесінді деп аталатын әдіспен тізімдегі элементтердің белгілі бір тобымен жұмыс істеуге болады.

Тізімді кесу

Тізімді "кесу" үшін сіз жұмыс істегіңіз келетін бірінші және соңғы элементтердің индексін көрсетесіз. range() функциясы сияқты, Python сіз көрсеткен екінші индекстің алдындағы элементте тоқтайды. Тізімдегі алғашқы үш элементті шығару үшін сіз 0 және 3 индекстерін сұрайсыз, ол сізге 0, 1, 2 элементтерін қайтарады.

Келесі мысал командадағы ойыншылардың тізімін қамтиды:

players.py


        players = ['charles', 'martina', 'michael', 'florence', 'eli']
        print(players[0:3])

Бұл код тізімнің бір бөлігін басып шығарады. Шығару тізімнің құрылымын сақтайды және тізімдегі алғашқы үш ойыншыны қамтиды:


        ['charles', 'martina', 'michael']

Сіз тізімнің кез-келген ішкі жиынын жасай аласыз. Мысалы, тізімдегі екінші, үшінші және төртінші элементтерді қаласаңыз, кесуді 1 индексінен бастайсыз және оны 4 индексінде аяқтайсыз:


        players = ['charles', 'martina', 'michael', 'florence', 'eli']
        print(players[1:4])

Бұл жолы кесінді 'martina' деп басталып, 'florence'-пен аяқталады:


        ['martina', 'michael', 'florence']

Егер сіз кесіндідегі бірінші индексті өткізіп алсаңыз, Python сіздің кесінді тізімнің басында автоматты түрде бастайды:


        
        players = ['charles', 'martina', 'michael', 'florence', 'eli']
        print(players[:4])

Бастау индексі болмаса, Python тізімнің басынан басталады:


        ['charles', 'martina', 'michael', 'florence']

Тізімнің соңын қамтитын кесінді қажет болса, ұқсас синтаксис жұмыс істейді. Мысалы, үшінші элементтен соңғы элементке дейінгі барлық элементтерді алғыңыз келсе, 2 индексінен бастап, екінші индексті жазбай тастап кетуге болады:


        
        players = ['charles', 'martina', 'michael', 'florence', 'eli']
        print(players[2:])

Python үшінші элементтен тізімнің соңына дейінгі барлық элементтерді қайтарады:


        ['michael', 'florence', 'eli']

Бұл синтаксис тізімнің ұзындығына қарамастан тізімнің кез-келген нүктесінен соңына дейін барлық элементтерді шығаруға мүмкіндік береді. Теріс индекс элементті тізімнің соңынан белгілі бір қашықтыққа қайтаратынын еске түсірейік; сондықтан тізімнің соңынан кез-келген бөлікті шығаруға болады. Мысалы, тізімдегі соңғы үш ойыншыны шығарғымыз келсе, players[-3:]: бөлігін пайдалана аламыз.


        players = ['charles', 'martina', 'michael', 'florence', 'eli']
        print(players[-3:])

Бұл соңғы үш ойыншының атын басып шығарады және ойыншылар тізімі өлшемі өзгерген сайын жұмысын жалғастырады.

Кескін арқылы цикл

Тізімдегі элементтердің ішкі жиынын айналғыңыз келсе, for циклінде кесінді пайдалануға болады. Келесі мысалда біз алғашқы үш ойыншыны айналдырамыз және олардың атын қарапайым тізімнің бөлігі ретінде басып шығарамыз:


        players = ['charles', 'martina', 'michael', 'florence', 'eli']
        
        print("Here are the first three players on my team:")
         for player in players[:3]:
            print(player.title())

❶ Ойыншылардың бүкіл тізімін айналдырудың орнына, Python тек алғашқы үш атауды ғана айналдырады:

Here are the first three players on my team:
        Charles
        Martina
        Michael

Кесінділер бірқатар жағдайларда өте пайдалы. Мысалы, сіз ойын жасаған кезде, ойыншы ойнауды аяқтаған сайын тізімге ойыншының соңғы ұпайын қоса аласыз. Содан кейін тізімді төмендеу ретімен сұрыптау және алғашқы үш ұпайды қамтитын бөлікті алу арқылы ойыншының үздік үш ұпайын алуға болады. Деректермен жұмыс істегенде, деректеріңізді белгілі бір өлшемдегі бөліктерде өңдеу үшін кесектерді пайдалануға болады. Немесе веб-бағдарламаны жасап жатқанда, әр бетте ақпараттың тиісті көлемі бар беттер қатарында ақпаратты көрсету үшін бөліктерді пайдалануға болады.

Тізімді көшіру

Көбінесе бұрыннан бар тізімнен бастап, сол тізімнің негізінде мүлдем жаңа тізім жасағыңыз келеді. Тізімді көшіру қалай жұмыс істейтінін және тізімді көшіру пайдалы болатын бір жағдайды қарастырайық.

Тізімді көшіру үшін бірінші индексті және екінші индексті ([:]) жазбай тастап кетіп, бүкіл түпнұсқа тізімді қамтитын бөлікті жасауға болады. Бұл Python-ға бірінші элементтен басталып, соңғы элементпен аяқталатын, бүкіл тізімнің көшірмесін жасайтын кесінді жасауды ұсынады.

Мысалы, бізде сүйікті тағамдардың тізімі бар және досыңызға ұнайтын тағамдардың бөлек тізімін жасағымыз келеді делік. Бұл досымызға әзірге біздің тізімдегі барлық нәрсе ұнайды, сондықтан біз өз тізімін көшіру арқылы олардың тізімін жасай аламыз:

foods.py


        my_foods = ['pizza', 'falafel', 'carrot cake']
         friend_foods = my_foods[:]
        
        print("My favorite foods are:")
        print(my_foods)
        
        print("\nMy friend's favorite foods are:")
        print(friend_foods)

Біріншіден, my_foods деп аталатын өзімізге ұнайтын тағамдардың тізімін жасаймыз. Содан кейін біз friend_foods деп аталатын жаңа тізім жасаймыз. ❶ my_foods басы-соңы индекстерін көрсетпей бөлігін сұрау арқылы my_foods толық көшірмесін жасаймыз, және көшірмені friend_foods айнымалысына тағайындаймыз. Әрбір тізімді басып шығарған кезде олардың екеуінде де бірдей тағамдар бар екенін көреміз:


        My favorite foods are:
        ['pizza', 'falafel', 'carrot cake']
        
        My friend's favorite foods are:
        ['pizza', 'falafel', 'carrot cake']

Бізде екі бөлек тізім бар екенін дәлелдеу үшін біз әрбір тізімге жаңа тағам қосып, әр тізімде сәйкес адамның сүйікті тағамдарын қадағалайтынын көрсетеміз:


        my_foods = ['pizza', 'falafel', 'carrot cake']
         friend_foods = my_foods[:]
        
         my_foods.append('cannoli')
         friend_foods.append('ice cream')
        
        print("My favorite foods are:")
        print(my_foods)
        
        print("\nMy friend's favorite foods are:")
        print(friend_foods)

❶ Алдыңғы мысалдағыдай сияқты my_foods ішіндегі түпнұсқа элементтерді жаңа friend_foods тізіміне көшіреміз. Әрі қарай, әр тізімге жаңа тағам қосамыз: ❷ 'cannoli' my_foods тізіміне қосамыз және ❸ 'ice cream' friend_foods ішіне қосамыз. Содан кейін осы тағамдардың әрқайсысы тиісті тізімде бар-жоғын білу үшін екі тізімді басып шығарамыз:


        My favorite foods are:
        ['pizza', 'falafel', 'carrot cake', 'cannoli']
        
        My friend's favorite foods are:
        ['pizza', 'falafel', 'carrot cake', 'ice cream']

Шығармада 'cannoli' енді менің сүйікті тағамдар тізімінде пайда болғанымен, 'ice cream' жоқ екенін көрсетеді. 'ice cream' енді досымыздың тізімінде пайда болғанын көріп отырмыз, бірақ 'cannoli' мұнда жоқ. Егер біз жай ғана friend_foods параметрін my_foods мәніне тең етіп қойсақ, екі бөлек тізім жасамас едік. Мысалы, тізімді кесінді пайдаланбай көшіруге әрекеттенгенде не болады:


        my_foods = ['pizza', 'falafel', 'carrot cake']
        
        # This doesn't work:
        friend_foods = my_foods
        
        my_foods.append('cannoli')
        friend_foods.append('ice cream')
        
        print("My favorite foods are:")
        print(my_foods)
        
        print("\nMy friend's favorite foods are:")
        print(friend_foods)

my_foods көшірмесін friend_foods айнымалысына тағайындаудың орнына, біз friend_foods параметрін my_foods мәніне тең етіп орнаттық. Бұл синтаксис шын мәнінде Python-ға жаңа friend_foods айнымалысын my_foods-пен бұрыннан байланыстырылған тізіммен байланыстыруды айтады, сондықтан енді екі айнымалы мән де бір тізімді көрсетеді. Нәтижесінде, 'cannoli'-ды my_foods ішіне қосқанда, ол friend_foods ішінде де пайда болады. Сол сияқты 'ice cream' екі тізімде де пайда болады, бірақ ол код жазу кезінде тек friend_foods ішіне қосылған сияқты көрінген еді.

Шығыс екі тізімнің қазір бірдей екенін көрсетеді, бұл біз қалағандай емес:


        My favorite foods are:
        ['pizza', 'falafel', 'carrot cake', 'cannoli', 'ice cream']
        
        My friend's favorite foods are:
        ['pizza', 'falafel', 'carrot cake', 'cannoli', 'ice cream']

Tuples / Таплз

Тізімдер бағдарламаның жұмыс істеу уақытында өзгеруі мүмкін элементтер жинақтарын сақтау үшін жақсы жұмыс істейді. Тізімдерді өзгерту мүмкіндігі веб-сайттағы пайдаланушылар тізімімен немесе ойындағы кейіпкерлер тізімімен жұмыс істегенде өте маңызды. Дегенмен, кейде өзгерте алмайтын элементтер тізімін жасағыңыз келеді. Кортеждер дәл осылай жасауға мүмкіндік береді. Python өзгермейтін мәндерді immutable деп белгілейді, ал өзгермейтін тізім - кортеж деп аталады.

Кортежді анықтау

Тікбұрышты жақшаның орнына қарапайым жақшаларды пайдаланатынын ескермесек, кортеж тізімге ұқсайды. Кортежді анықтағаннан кейін тізімдегідей әрбір элементтің индексін пайдалану арқылы жеке элементтерге қол жеткізуге болады.

Мысалы, бізде әрқашан белгілі бір өлшем болуы керек тіктөртбұрыш болса, өлшемдерді кортежге қою арқылы оның өлшемі өзгермейтініне көз жеткізе аламыз:

dimensions.py


        dimensions = (200, 50)
        print(dimensions[0])
        print(dimensions[1])

Тікбұрышты жақшаның орнына қарапайым жақшаларды пайдаланып, dimensions кортежін анықтаймыз. Содан кейін тізімдегі элементтерге қол жеткізу үшін қолданып жүрген синтаксисті пайдалана отырып, кортеждегі әрбір элементті жеке басып шығарамыз:


        200
        50

dimensions кортежіндегі элементтердің бірін өзгертуге әрекеттенсек, не болатынын көрейік:


        dimensions = (200, 50)
        dimensions[0] = 250

Бұл код бірінші элементтің мәнін өзгертуге тырысады, бірақ Python TypeError қатесін қайтарады. Біз осы класс түрінде орындалмайтын кортежді өзгертуге тырысып жатқандықтан, Python бізге кортеждегі элементке жаңа мән тағайындай алмайтынымызды айтады:


        Traceback (most recent call last):
          File "dimensions.py", line 2, in <module>
            dimensions[0] = 250
        TypeError: 'tuple' object does not support item assignment

Бұл пайдалы, өйткені код жолы тіктөртбұрыштың өлшемдерін өзгертуге тырысқанда Python қатені шығарғанын қалаймыз.

Кортеждегі барлық мәндер арқылы айналым

Тізімдегідей for циклін пайдаланып кортеждегі барлық мәндерді айналдыра аласыз:


        dimensions = (200, 50)
        for dimension in dimensions:
            print(dimension)

Python тізімдегідей кортеждегі барлық элементтерді қайтарады:


        200
        50

Кортеждің үстінен жазу

Кортежді өзгерте алмасаңыз да, кортежді көрсететін айнымалыға жаңа мән тағайындай аласыз. Мысалы, егер біз осы тіктөртбұрыштың өлшемдерін өзгерткіміз келсе, біз бүкіл кортежді қайта анықтай аламыз:


        dimensions = (200, 50)
        print("Original dimensions:")
        for dimension in dimensions:
            print(dimension)
        
        dimensions = (400, 100)
        print("\nModified dimensions:")
        for dimension in dimensions:
            print(dimension)

Алғашқы төрт жол бастапқы кортежді анықтайды және бастапқы өлшемдерді басып шығарады. Содан кейін біз жаңа кортежді dimensions айнымалысымен байланыстырамыз және жаңа мәндерді басып шығарамыз. Python бұл жолы ешқандай қате жібермейді, себебі айнымалыны қайта тағайындау жарамды:


        Original dimensions:
        200
        50
        
        Modified dimensions:
        400
        100

Тізімдермен салыстырғанда кортеждер қарапайым деректер құрылымдары болып табылады. Бағдарламаның қызмет ету мерзімі бойы өзгертілмейтін мәндер жинағын сақтағыңыз келгенде оларды пайдаланыңыз.


Кодыңызды сәндеу

Енді сіз ұзағырақ бағдарламалар жазып жатқандықтан, кодты дәйекті түрде стильдеуді үйренгеніңіз жөн. Кодыңызды оқуды барынша жеңілдету үшін уақыт бөліңіз. Оңай оқылатын код жазу бағдарламаларыңыздың не істеп жатқанын бақылауға көмектеседі және басқаларға кодыңызды түсінуге көмектеседі.

Python бағдарламашылары барлығының коды шамамен бірдей құрылымдалғанын қамтамасыз ету үшін бірнеше сәндеу конвенцияларымен келісті. Таза Python кодын жазуды үйренгеннен кейін, сіз басқа біреудің Python кодының жалпы құрылымын түсінуіңіз керек, егер олар бірдей нұсқауларды орындаса. Егер сіз белгілі бір сәтте кәсіби бағдарламашы болғыңыз келсе, жақсы әдеттерді дамыту үшін осы нұсқауларды орындауды мүмкіндігінше тезірек бастауыңыз керек.

Стиль нұсқаулығы

Біреу Python тіліне өзгеріс енгізгісі келгенде, олар Python жақсарту ұсынысын (PEP) жазады. Ең көне PEP-тердің бірі PEP 8 болып табылады, ол Python бағдарламашыларына өз кодтарын стильдеу бойынша нұсқау береді. PEP 8 өте ұзақ, бірақ оның көп бөлігі осы уақытқа дейін көргеннен гөрі күрделірек кодтау құрылымдарына қатысты.

Python стиль нұсқаулығы код жазылғаннан гөрі жиі оқылатынын түсініп жазылған. Сіз кодты бір рет жазасыз, содан кейін жөндеуді бастаған кезде оны оқуды бастайсыз. Бағдарламаға мүмкіндіктер қосқанда, кодты оқуға көбірек уақыт жұмсайсыз. Кодыңызды басқа бағдарламашылармен бөліскен кезде, олар сіздің кодыңызды да оқиды.

Жазуға оңайырақ код жазу немесе оқуға оңай код жазу арасындағы таңдауды ескере отырып, Python бағдарламашылары сізді оқуға оңай код жазуды әрдайым дерлік ұсынады. Төмендегі нұсқаулар басынан бастап анық код жазуға көмектеседі.

Шегініс

PEP 8 шегініс деңгейінде төрт бос орынды пайдалануды ұсынады. Төрт бос орынды пайдалану оқу мүмкіндігін жақсартады, сонымен қатар әр жолда шегіністердің бірнеше деңгейіне орын қалдырады.

Мәтінді өңдеу құжатында адамдар шегініс үшін бос орындардың орнына tab-ты жиі пайдаланады. Бұл мәтінді өңдеу құжаттары үшін жақсы жұмыс істейді, бірақ tab бос орындармен араласқан кезде Python аудармашысы шатастырады. Әрбір мәтін өңдегіші TAB пернесін пайдалануға мүмкіндік беретін параметрді қамтамасыз етеді, бірақ содан кейін әрбір tab-ты белгіленген бос орындар санына түрлендіреді. Сіз міндетті түрде TAB пернесін пайдалануыңыз керек, бірақ сонымен бірге редакторыңыз құжатқа tab-ты емес, бос орындарды кірістіретін етіп орнатылғанын тексеріңіз.

Файлдағы tab-тар мен бос орындарды араластыру диагностикалау өте қиын мәселелерге әкелуі мүмкін. tab пен бос орындар аралас деп ойласаңыз, файлдағы барлық tab-тарды көптеген редакторларда бос орындарға түрлендіруге болады.

Қатар-жол ұзындығы

Көптеген Python бағдарламашылары әр жолдың 80 таңбадан аз болуын ұсынады. Тарихи түрде бұл нұсқаулық көптеген компьютерлер терминал терезесіндегі бір жолға тек 79 таңбаны сыйдыра алатындықтан дамыды. Қазіргі уақытта адамдар экрандарына әлдеқайда ұзын қатарларды сыйдыра алады, бірақ 79 таңбадан тұратын стандартты сызық ұзындығын сақтаудың басқа да себептері бар.

Кәсіби бағдарламашылар жиі бір экранда бірнеше файлды ашады және стандартты жол ұзындығын пайдалану оларға экранда қатар ашық тұрған екі немесе үш файлдағы барлық жолдарды көруге мүмкіндік береді. PEP 8 сонымен қатар барлық түсініктемелеріңізді әр жолға 72 таңбамен шектеуді ұсынады, себебі үлкенірек жобалар үшін автоматты құжаттаманы жасайтын кейбір құралдар түсініктеме берілген жолдың басында пішімдеу таңбаларын қосады.

Жолдың ұзындығына арналған PEP 8 нұсқаулары қатып қалған заңмен белгіленбеген және кейбір бағдарламашылар мен топтар 99 таңбалық шектеуді қалайды. Үйреніп жатқанда кодыңыздағы жол ұзындығы туралы тым көп алаңдамаңыз, бірақ бірлесіп жұмыс істейтін адамдар әрқашан дерлік PEP 8 нұсқауларын орындайтынын ескеріңіз. Көптеген редакторлар бұл шектеулердің қай жерде екенін көрсететін визуалды белгіні, әдетте экрандағы тік сызықты орнатуға мүмкіндік береді.

Бос жолдар

Бағдарлама бөліктерін көрнекі түрде топтау үшін бос жолдарды пайдаланыңыз. Файлдарды реттеу үшін бос жолдарды пайдалану керек, бірақ оны шамадан тыс жасамаңыз. Осы кітапта келтірілген мысалдарды орындау арқылы сіз дұрыс тепе-теңдікті сақтауыңыз керек. Мысалы, сізде тізімді құрайтын кодтың бес жолы және сол тізіммен бірдеңе жасайтын тағы үш жол болса, екі бөлімнің арасына бос жолды қойған дұрыс. Дегенмен, екі бөлімнің арасына үш немесе төрт бос жолды қоюға болмайды.

Бос жолдар кодтың іске қосылуына әсер етпейді, бірақ олар кодтың оқылуына әсер етеді. Python аудармашысы кодыңыздың мағынасын түсіндіру үшін көлденең шегіністерді пайдаланады, бірақ ол тік аралықты елемейді.

Басқа стиль нұсқаулары

PEP 8-де сәндеу бойынша көптеген қосымша ұсыныстар бар, бірақ нұсқаулардың көпшілігі осы кезде жазып жатқаныңызға қарағанда күрделірек бағдарламаларға қатысты. Күрделі Python құрылымдарын үйренген сайын, мен PEP 8 нұсқауларының тиісті бөліктерін бөлісемін.

Қорытынды

Бұл тарауда сіз тізімдегі элементтермен қалай тиімді жұмыс істеу керектігін үйрендіңіз. Сіз for циклінің көмегімен тізіммен жұмыс істеуді, Python бағдарламасының бағдарламаны құрылымдау үшін шегіністерді қалай пайдаланатынын және кейбір жалпы шегініс қателерін болдырмауды үйрендіңіз. Сіз қарапайым сандық тізімдерді, сондай-ақ сандық тізімдерде орындауға болатын бірнеше әрекеттерді жасауды үйрендіңіз. Элементтердің ішкі жиынымен жұмыс істеу үшін тізімді кесу жолын және тізімдерді кесінді арқылы дұрыс көшіру жолын үйрендіңіз. Сондай-ақ өзгермейтін мәндер жинағын қорғау дәрежесін қамтамасыз ететін кортеждер туралы және оқуды жеңілдету үшін барған сайын күрделі кодты қалай стильдеу керектігін білдіңіз.

5-тарауда сіз if амалдарын пайдалану арқылы әртүрлі шарттарға сәйкес жауап беруді үйренесіз. Сіз іздеген жағдайға немесе ақпарат түріне сәйкес жауап беру үшін шартты сынақтардың салыстырмалы түрде күрделі жинақтарын біріктіруді үйренесіз. Сондай-ақ тізімнен таңдалған элементтермен нақты әрекеттерді орындау үшін тізімді айналдыру кезінде if операторларын пайдалануды үйренесіз.

if амалы

ITUniver

5
if амалы

Бағдарламалау көбінесе шарттар жинағын зерттеуді және сол шарттар негізінде қандай әрекетті орындау керектігін шешуді қамтиды. Python бағдарламасының if амалы бағдарламаның ағымдағы күйін тексеруге және сол күйге сәйкес жауап беруге мүмкіндік береді.

Бұл тарауда сіз кез-келген қызығушылық жағдайын тексеруге мүмкіндік беретін шартты сынақтарды жазуды үйренесіз. Сіз қарапайым if операторларын жазуды үйренесіз және өзіңіз қалаған нақты шарттар болған кезде анықтау үшін if операторларының күрделірек қатарын жасауды үйренесіз. Содан кейін бұл тұжырымдаманы тізімдерге қолданасыз, осылайша тізімдегі элементтердің көпшілігін бір жолмен өңдейтін, бірақ нақты мәндері бар белгілі элементтерді басқа жолмен өңдейтін for циклін жаза аласыз.

Қарапайым мысал

Келесі мысал if сынақтарының ерекше жағдайларға қалай дұрыс жауап беруге мүмкіндік беретінін көрсетеді. Елестетіп көріңізші, сізде көліктер тізімі бар және сіз әр көліктің атын басып шығарғыңыз келеді. Автокөлік атаулары жеке атаулар болып табылады, сондықтан көптеген автомобильдердің атаулары бас әріппен басылуы керек. Дегенмен, 'bmw' атауының барлық әріптері бас әріптермен басылып шығуы керек. Келесі код көлік атауларының тізімін аралайды және 'bmw' мәнін іздейді. Мән 'bmw' болғанда, тек бірінші әріп емес, барлық әрібі бас әріппен басылады:

cars.py


        cars = ['audi', 'bmw', 'subaru', 'toyota']
        
        for car in cars:
            if car == 'bmw':
                print(car.upper())
            else:
                print(car.title())

❶ Бұл мысалдағы цикл алдымен car-дың ағымдағы мәні 'bmw' екенін тексереді. Егер солай болса, мән бас әріппен басылады. Егер car мәні 'bmw' мәнінен басқа нәрсе болса, ол атау ретінде бірінші әріпі бас әріппен басылады:


        Audi
        BMW
        Subaru
        Toyota

Бұл мысал осы тарауда білетін бірқатар ұғымдарды біріктіреді. Бағдарламадағы шарттарды тексеру үшін қолдануға болатын сынақ түрлерін қарастырудан бастайық.

Шартты сынақтар

Әр if амалының негізінде True немесе False ретінде бағаланатын өрнек жатыр және ол шартты сынақ деп аталады. Python if операторындағы кодтың орындалу керектігін шешу үшін True және False мәндерін пайдаланады. Егер шартты сынақ True деп бағаланса, Python if операторынан кейінгі кодты орындайды. Егер сынақ False деп бағаланса, Python if амалынан кейінгі кодты елемейді.

Теңдікті тексеру

Шартты сынақтардың көпшілігі айнымалының ағымдағы мәнін бізге қажетті белгілі бір мәнімен салыстырады. Ең қарапайым шартты тест айнымалы мәннің қызығушылық мәніне тең екендігін тексереді:


        >>> car = 'bmw'
        >>> car == 'bmw'
        True

Бірінші жол car мәнін 'bmw' мәніне бір теңдік белгісін пайдаланып тағайындап-орнатады, мұны сіз бұрыннан көп рет көргенсіз. Келесі жол қос теңдік белгісін (==) пайдалану арқылы car мәні 'bmw' екенін тексереді. Бұл теңдік операторы оператордың сол және оң жағындағы мәндер сәйкес келсе, True мәнін, ал сәйкес келмесе, False мәнін қайтарады. Бұл мысалдағы мәндер сәйкес келеді, сондықтан Python True қайтарады.

car мәні 'bmw' мәнінен басқа кез-келген болса, бұл сынақ False мәнін қайтарады:


        >>> car = 'audi'
        >>> car == 'bmw'
        False

Бір теңдік белгісі шын мәнінде амал болып табылады; мұнда кодтың бірінші жолын «car мәнін 'audi'-ға тең етіп орнатыңыз» деп оқи аласыз. Екінші жағынан, қос теңдік белгісі сұрақ қояды: «car мәні 'bmw' мәніне тең бе?» Бағдарламалау тілдерінің көпшілігі теңдік белгілерді осылайша пайдаланады.

Теңдікке тексеру кезінде регистрді елемеу

Python тілінде теңдік сынағы регистрді ескереді. Мысалы, бас әрібі бар және жоқ әртүрлі екі мән тең деп саналмайды:


        >>> car = 'Audi'
        >>> car == 'audi'
        False

Егер жағдай маңызды болса, бұл әрекет тиімді. Бірақ егер регистр маңызды болмаса және оның орнына жай ғана айнымалының мәнін тексергіңіз келсе, салыстыруды бастамас бұрын айнымалының мәнін кіші әріпке түрлендіруге болады:


        >>> car = 'Audi'
        >>> car.lower() == 'audi'
        True

Бұл сынақ 'Audi' мәні қалай пішімделгеніне қарамастан, True мәнін қайтарады, себебі сынақ енді регистрді ескермейді. lower() әдісі бастапқыда car ішінде сақталған мәнді өзгертпейді, сондықтан салыстыруды бастапқы айнымалыға әсер етпестен орындауға болады:


        >>> car = 'Audi'
        >>> car.lower() == 'audi'
        True
        >>> car
        'Audi'

Алдымен car айнымалысына бас әріппен жазылған 'Audi' жолын тағайындаймыз. Содан кейін car мәнін кіші әріпке түрлендіреміз және кіші әріпті 'audi' жолымен салыстырамыз. Екі жол сәйкес келеді, сондықтан Python True қайтарады. car ішінде сақталған мәнге lower() әдісі әсер етпегенін көреміз.

Веб-сайттар пайдаланушылар осыған ұқсас түрде енгізетін деректер үшін белгілі бір ережелерді бекітеді. Мысалы, сайт басқа адамның пайдаланушы атының бас әріптерінің өзгеруін ғана емес, әрбір пайдаланушының шынымен бірегей пайдаланушы аты бар екеніне көз жеткізу үшін осындай шартты сынақты пайдалана алады. Біреу жаңа пайдаланушы атын жібергенде, бұл жаңа пайдаланушы аты кіші әріпке түрлендіріледі және барлық бар пайдаланушы аттарының кіші әріптерімен салыстырылады. Бұл тексеру кезінде 'John' кез-келген нұсқасы бұрыннан қолданыста болса, 'John' сияқты пайдаланушы аты қабылданбайды.

Теңсіздікті тексеру

Екі мәннің тең еместігін анықтағыңыз келгенде, теңсіздік операторын (!=) пайдалануға болады. Теңсіздік операторын пайдалану жолын қарастыру үшін басқа if операторын қолданайық. Біз қалайтын пиццаның ингредиентін айнымалы түрде сақтаймыз, содан кейін егер адам анчоусқа тапсырыс бермесе, хабарды басып шығарамыз:

toppings.py


        pizza_type = 'mushrooms'
        
        if pizza_type != 'anchovies':
            print("Hold the anchovies!")

Бұл код pizza_type мәнін 'anchovies/анчоус' мәнімен салыстырады. Бұл екі мән сәйкес келмесе, Python True мәнін қайтарады және if операторынан кейін кодты орындайды. Егер екі мән сәйкес келсе, Python False мәнін қайтарады және if амалынан кейін кодты іске қоспайды.

pizza_type мәні 'anchovies/анчоус' емес болғандықтан, print() функциясы орындалады:


          Hold the anchovies!

Сіз жазған шартты өрнектердің көпшілігі теңдікті тексереді, бірақ кейде теңсіздікті тексеру тиімдірек болады.

Сандық салыстырулар

Сандық мәндерді сынау өте қарапайым. Мысалы, келесі код адамның 18 жаста екенін тексереді:


        >>> age = 18
        >>> age == 18
        True

Сонымен қатар екі санның тең еместігін тексеруге болады. Мысалы, берілген жауап дұрыс болмаса, келесі код хабарды басып шығарады:

magic_number.py


        answer = 17
        if answer != 42:
            print("That is not the correct answer. Please try again!")

Шарт сынақтан өтеді, себебі answer (17) мәні 42 мәніне тең емес. Сынақ өткендіктен, шегініс код блогы орындалады:


        That is not the correct answer. Please try again!

Шартты амалдарыңызға әртүрлі математикалық салыстыруларды қосуға болады, мысалы, кіші, кіші немесе тең, үлкен және үлкен немесе тең:


        >>> age = 19
        >>> age < 21
        True
        >>> age <= 21
        True
        >>> age > 21
        False
        >>> age >= 21
        False

Әрбір математикалық салыстыруды if амалының бөлігі ретінде пайдалануға болады, ол сізді қызықтыратын нақты шарттарды анықтауға көмектеседі.

Бірнеше шарттарды тексеру

Бір уақытта бірнеше шарттарды тексергіңіз келуі мүмкін. Мысалы, кейде әрекетті орындау үшін True болу үшін екі шарт қажет болуы мүмкін. Басқа жағдайларда сізге тек бір шарттың True екені жеткілікті болуы мүмкін. and және or кілт сөздері осы жағдайларда сізге көмектесе алады.

Бірнеше шарттарды тексеру үшін and пайдалану

Екі шарттың екеуі де True екенін тексеру үшін екі шартты сынақты біріктіру үшін and кілт сөзін пайдаланыңыз; егер әрбірі сынақтан өтсе, жалпы өрнек True болып бағаланады. Егер сынақтардың бірі сәтсіз болса немесе екі сынақ те сәтсіз болса, өрнек False болып есептеледі.

Мысалы, екі адамның жасы 21-ден асқанын келесі сынақ арқылы тексеруге болады:


        >>> age_0 = 22
        >>> age_1 = 18
         >>> age_0 >= 21 and age_1 >= 21
        False
         >>> age_1 = 22
        >>> age_0 >= 21 and age_1 >= 21
        True

Біріншіден, біз екі жасты анықтаймыз, age_0 және age_1. ❶ Содан кейін екі жастың да 21 немесе одан жоғары екенін тексереміз. Сол жақтағы сынақ өтеді, бірақ оң жақтағы сынақ сәтсіз аяқталды, сондықтан жалпы шартты өрнек False мәніне бағаланады. Содан кейін age_1 мәнін 22 ❷ етіп өзгертеміз. age_1 мәні енді 21-ден үлкен, сондықтан жеке сынақтардың екеуі де өтіп, жалпы шартты өрнек True ретінде бағаланады.

Оқылуын жақсарту үшін жеке сынақтардың айналасында жақшаларды пайдалануға болады, бірақ олар қажет емес. Жақшаларды пайдалансаңыз, тест келесідей болады:


        (age_0 >= 21) and (age_1 >= 21)
Бірнеше шарттарды тексеру үшін or пайдалану

or кілт сөзі бірнеше шарттарды тексеруге мүмкіндік береді, және ол жеке сынақтардың біреуі ғана немесе екеуі де өткенде өтеді. or өрнегі жеке сынақтардың екеуі де сәтсіз болғанда ғана орындалмайды.

Екі жасты қайта қарастырайық, бірақ бұл жолы 21 жастан асқан бір ғана адамды іздейміз:


        >>> age_0 = 22
        >>> age_1 = 18
         >>> age_0 >= 21 or age_1 >= 21
        True
         >>> age_0 = 18
        >>> age_0 >= 21 or age_1 >= 21
        False

Біз қайтадан екі жас айнымалысынан бастаймыз. ❶ age_0 сынақтан өткендіктен, жалпы өрнек True мәніне бағаланады. Содан кейін age_0 мәнін 18-ге дейін төмендетеміз. Соңғы сынақта ❷, екі сынақ енді сәтсіз аяқталды және жалпы өрнек False мәніне бағаланады.

Мәннің тізімде бар-жоғын тексеру

Кейде әрекет жасамас бұрын тізімде белгілі бір мән бар-жоғын тексеру маңызды. Мысалы, веб-сайтта біреуді тіркеуді аяқтамас бұрын, жаңа пайдаланушы атының ағымдағы пайдаланушы аттары тізімінде бұрыннан бар-жоғын тексергіңіз келуі мүмкін. Карталау жобасында жіберілген орынның белгілі орындар тізімінде бар-жоғын тексергіңіз келуі мүмкін.

Нақты мәннің тізімде бұрыннан бар-жоғын білу үшін in кілт сөзін пайдаланыңыз. Пиццерия үшін жаза алатын кодты қарастырайық. Біз тұтынушы пицца үшін сұраған ингредиент тізімін жасаймыз, содан кейін тізімде белгілі бір ингредиенттің бар-жоғын тексереміз.


        >>> requested_toppings = ['mushrooms', 'onions', 'pineapple']
        >>> 'mushrooms' in requested_toppings
        True
        >>> 'pepperoni' in requested_toppings
        False

in кілт сөзі Python жүйесіне requested_toppings тізімінде 'mushrooms' және 'pepperoni' бар-жоғын тексеруге нұсқайды. Бұл әдіс өте күшті, себебі сіз маңызды мәндердің тізімін жасай аласыз, содан кейін тексеріп жатқан мән тізімдегі мәндердің біріне сәйкес келетінін оңай тексере аласыз.

Мәннің тізімде жоқтығын тексеру

Кейбір жағдайда мәннің тізімде жоқ екенін білу маңызды. Бұл жағдайда not кілт сөзін қолдануға болады. Мысалы, форумда пікір жазуға тыйым салынған пайдаланушылардың тізімін қарастырыңыз. Пайдаланушыға пікір жіберуге рұқсат бермес бұрын, пайдаланушыға тыйым салынғанын тексеруге болады:

banned_users.py


        banned_users = ['andrew', 'carolina', 'david']
        user = 'marie'
        
        if user not in banned_users:
            print(f"{user.title()}, you can post a response if you wish.")

Мұндағы if амалы анық оқылады. Егер user мәні banned_users тізімінде болмаса, Python True мәнін қайтарады және шегініс жолын орындайды.

Пайдаланушы 'marie' banned_users тізімінде жоқ, сондықтан ол оны пікір-жауап жариялауға шақыратын хабарды көреді:


        Marie, you can post a response if you wish.

Логикалық өрнектер / Boolean expressions

Бағдарламалау туралы көбірек білгенде, сіз белгілі бір уақытта Логикалық өрнек терминін естисіз. Логикалық өрнек шартты сынақтың басқа атауы ғана. Логикалық мән не True немесе False болып табылады, ол бағаланғаннан кейінгі шартты өрнектің мәні сияқты.

Логикалық мәндер көбінесе ойынның іске қосылуы немесе пайдаланушының веб-сайттағы белгілі бір мазмұнды өңдей алуы сияқты белгілі бір шарттарды қадағалау үшін пайдаланылады:


        game_active = True
        can_edit = False

Логикалық мәндер бағдарламаның күйін немесе бағдарламаңызда маңызды белгілі бір шартты бақылаудың тиімді жолын қамтамасыз етеді.

if амалы

Шартты сынақтарды түсінген кезде, if амалдарын жазуды бастауға болады. if амалдарының бірнеше түрі бар және олардың қайсысын пайдалануды таңдау тестілеу қажет шарттар санына байланысты болады. Шартты сынақтар туралы талқылауда if амалдарының бірнеше мысалын көрдіңіз, бірақ енді тақырыпты тереңірек зерттейік.

Қарапайым if амалдары

if операторының ең қарапайым түрі бір сынақ және бір әрекеттен тұрады:


        if conditional_test:
            do something

Сіз бірінші жолға кез-келген шартты сынақты және сынақтан кейінгі шегініс блокта кез-келген әрекетті қоюға болады. Егер шартты сынақ True деп бағаланса, Python if операторынан кейінгі кодты орындайды. Егер сынақ False деп бағаланса, Python if амалынан кейінгі кодты елемейді.

Адамның жасын көрсететін айнымалы мән бар делік және ол адамның дауыс беруге жасы жететінін білгіміз келеді. Келесі код адамның дауыс бере алатынын тексереді:

voting.py


        age = 19
        if age >= 18:
            print("You are old enough to vote!")

Python age мәні 18-ден үлкен немесе оған тең екенін бағалау үшін тексереді. Ол солай, сондықтан Python шегініспен жазылған print() шақыруын орындайды:


        You are old enough to vote!

Шегініс if операторларында for циклдеріндегідей рөл атқарады. Сынақтан өткен жағдайда if операторынан кейінгі барлық шегініс жолдар орындалады, ал егер сынақтан өтпесе, шегінген жолдардың бүкіл блогы еленбейді.

if амалынан кейін блокта қалағаныңызша код жолдары болуы мүмкін. Егер адам дауыс беруге жасы жетсе, оның әлі дауыс беруге тіркелген-тірілмегенін сұрайтын басқа нәтижені қосамыз:


        age = 19
        if age >= 18:
            print("You are old enough to vote!")
            print("Have you registered to vote yet?")

Шартты сынақтан өтіп, print() шақыруларының екеуі де шегініске ие, сондықтан екі жол да басып шығарылады:


        You are old enough to vote!
        Have you registered to vote yet?

Егер age мәні 18-ден аз болса, бұл бағдарлама ешқандай нәтиже бермейді.

if-else амалдары

Көбінесе шартты сынақтан өткенде бір әрекетті және барлық өзге жағдайларда басқа әрекетті орындағыңыз келеді. Python-ның if-else синтаксисі мұны мүмкін етеді. if-else блогы қарапайым if операторына ұқсайды, бірақ else операторы мынаны анықтауға мүмкіндік береді: шартты сынақ сәтсіз болғанда орындалатын әрекет немесе әрекеттер жиынтығы.

Егер адам дауыс беруге жасы жетсе, біз бұрынғы хабарды көрсетеміз, бірақ бұл жолы дауыс беруге жасы жетпейтін кез-келген адамға хабар қосамыз:


        age = 17
         if age >= 18:
            print("You are old enough to vote!")
            print("Have you registered to vote yet?")
         else:
            print("Sorry, you are too young to vote.")
            print("Please register to vote as soon as you turn 18!")

Егер ❶ шарт сынақтан өтсе, шегінген print() шақыруларының бірінші блогы орындалады. Егер сынақ False мәніне бағаланса, else блогы ❷ орындалады. age бұл жолы 18-ден аз болғандықтан, шартты сынақ сәтсіз аяқталады және else блогындағы код орындалады:


        Sorry, you are too young to vote.
        Please register to vote as soon as you turn 18!

Бұл код жұмыс істейді, себебі оны бағалауға болатын екі ғана жағдай бар: адам дауыс беруге жасы жеткілікті немесе дауыс беруге жасы жетпейді. if-else құрылымы Python әрқашан екі ықтимал әрекеттің бірін орындауын қалаған жағдайларда жақсы жұмыс істейді. Осындай қарапайым if-else тізбегінде екі әрекеттің бірі әрқашан орындалады.

if-elif-else тізбегі

Көбінесе екіден көп ықтимал жағдайды сынау керек болады және оларды бағалау үшін Python бағдарламасының if-elif-else синтаксисін пайдалануға болады. Python if-elif-else тізбегінде тек бір блокты орындайды. Ол әрбір шартты сынақты біреуі өткенше ретімен орындайды. Сынақтан өткен кезде, осы сынақтан кейінгі код орындалады және Python қалған сынақтарды өткізіп жібереді.

Көптеген нақты жағдайлар екіден көп мүмкін жағдайларды қамтиды. Мысалы, әртүрлі жас топтары үшін әртүрлі тарифтер алатын ойын-сауық паркін қарастырыңыз:

  • 4 жасқа толмағандар үшін кіру тегін.
  • 4 пен 18 жас аралығындағы кез-келген адам үшін рұқсат $25.
  • 18 жастан асқан кез-келген адам үшін рұқсат $40.

Адамның паркке кіру құнын анықтау үшін if амалынан қалай пайдалана аламыз? Келесі код адамның жас тобын тексереді, содан кейін кіру бағасы туралы хабарды басып шығарады:

amusement_park.py


        age = 12
         if age < 4:
            print("Your admission cost is $0.")
         elif age < 18:
            print("Your admission cost is $25.")
         else:
            print("Your admission cost is $40.")

if сынағы ❶ адамның 4 жасқа толмағанын тексереді. Сынақтан өткен кезде сәйкес хабарлама басып шығарылады және Python қалған сынақтарды өткізіп жібереді. elif жолы ❷ шын мәнінде басқа if сынағы болып табылады, ол тек қана алдыңғы сынақ сәтсіз болған жағдайда орындалады. Тізбектің осы нүктесінде біз адамның кем дегенде 4 жаста екенін білеміз, себебі бірінші сынақ сәтсіз аяқталды. Егер адам 18 жастан кіші болса, сәйкес хабарлама басып шығарылады және Python else блогын өткізіп жібереді. Егер if және elif сынақтарының екеуі де сәтсіз болса, Python кодты else блогында іске қосады.❸.

Бұл мысалда if сынағы ❶ False деп бағаланады, сондықтан оның код блогы орындалмайды. Дегенмен, elif сынағы True мәніне баға береді (12 саны 18-ден аз), сондықтан оның коды орындалады. Шығару бір сөйлемнен тұрады, пайдаланушыға кіру құны туралы хабарлайды:


        Your admission cost is $25.

17 жастан асқан кез-келген жас алғашқы екі сынақтың сәтсіз аяқталуына себеп болады. Мұндай жағдайларда else блогы орындалады және кіру бағасы $40 болады.

Кіру бағасын if-elif-else блогында басып шығарудың орнына, ішінде бағаны ғана орнату қысқарақ болар еді. if-elif-else тізбегі бағаланып болғаннан кейін орындалатын жалғыз print() шақыруы болады.


        age = 12
        
        if age < 4:
            price = 0
        elif age < 18:
            price = 25
        else:
            price = 40
        
        print(f"Your admission cost is ${price}.")

Шегіністі жолдар алдыңғы мысалдағыдай адамның жасына сәйкес price мәнін орнатады. Баға if-elif-else тізбегі арқылы орнатылғаннан кейін бөлек шегінбеген print() әдісіне шақыру адамның кіру бағасы туралы хабарды көрсету үшін осы мәнді пайдаланылады.

Бұл код алдыңғы мысалдағыдай нәтиже береді, бірақ if-elif-else тізбегінің мақсаты шектеулі. Бағаны анықтаудың және хабарламаны көрсетудің орнына, ол жай ғана кіру бағасын анықтайды. Тиімдірек болумен қатар, бұл қайта қаралған кодты өзгерту бастапқы тәсілге қарағанда оңайырақ. Шығарылатын хабардың мәтінін өзгерту үшін үш бөлек print() шақыруының орнына тек бір print() шақыруын өзгерту қажет.

Бірнеше elif блоктарын пайдалану

Кодыңызда қалағаныңызша көп elif блоктарын пайдалануға болады. Мысалы, ойын-сауық саябағы қарт адамдарға арналған жеңілдікті енгізетін болса, біреудің үлкендерге арналған жеңілдікке жарамдылығын анықтау үшін кодқа тағы бір шартты сынақ қосуға болады. 65 жастан асқан кез-келген адам тұрақты кіру ақысының жартысын немесе $20 төлейді делік:


        age = 12
        
        if age < 4:
            price = 0
        elif age < 18:
            price = 25
        elif age < 65:
            price = 40
        else:
            price = 20
        
        print(f"Your admission cost is ${price}.")

Бұл кодтың көпшілігі өзгеріссіз. Екінші elif блогы енді 40 АҚШ доллары мөлшеріндегі қабылдау ақысын тағайындамас бұрын, адамның жасы 65-тен төмен екенін тексереді. else блогында тағайындалған мәнді $20 етіп өзгерту керек екенін ескеріңіз, себебі бұл блокқа тек 65 жастан асқан адамдар ғана жетеді.

else блогын өткізіп жіберу

Python бағдарламасы if-elif тізбегінің соңында else блогын қажет етпейді. Кейде else блогы пайдалы. Басқа жағдайларда, қызықтыратын нақты шартқа жауап беретін қосымша elif амалынан пайдалану анық болады:


        age = 12
        
        if age < 4:
            price = 0
        elif age < 18:
            price = 25
        elif age < 65:
            price = 40
        elif age >= 65:
            price = 20
        
        print(f"Your admission cost is ${price}.")

Соңғы elif блогы адам 65 жаста немесе одан үлкен болған кезде $20 бағасын тағайындайды, бұл жалпы else блогынан сәл айқынырақ. Бұл өзгерту арқылы әрбір код блогы орындалу үшін арнайы сынақтан өтуі керек.

else блогы - бұл catchall операторы. Ол белгілі бір if немесе elif сынағымен сәйкес келмеген кез-келген шартқа сәйкес келеді және кейде жарамсыз немесе тіпті зиянды деректерді қамтуы мүмкін. Егер сізде сынап жатқан нақты соңғы шарт болса, соңғы elif блогын пайдалануды қарастырып, else блогын өткізіп жіберіңіз. Нәтижесінде кодыңыз тек дұрыс шарттарда жұмыс істейтініне сенімді боласыз.

Бірнеше шарттарды сынау

if-elif-else тізбегі өте жақсы, бірақ оны тек шартты сынақтың біреуі өткені қажет болғанда ғана қолданған дұрыс. Python бір сынақ өткеннен кейін, қалған сынақтарды тексермей, өткізіп жібереді. Бұл әрекет пайдалы, себебі ол тиімді-қысқа және белгілі бір жағдайды тексеруге мүмкіндік береді.

Дегенмен, кейде қызығушылықтың барлық шарттарын тексеру маңызды. Бұл жағдайда elif немесе else блоктары жоқ қарапайым if операторларының қатарын пайдалану керек. Бұл әдіс бірнеше шарт True болуы мүмкін болғанда және сіз True болатын әрбір шарт бойынша әрекет еткіңіз келсе мағынасы болады.

Пиццерия мысалын қайта қарастырайық. Егер біреу екі қабаты бар пицца сұраса, оның пиццасына екі қоспаны да қосуды ұмытпаңыз:

toppings.py


        requested_toppings = ['mushrooms', 'extra cheese']
        
        if 'mushrooms' in requested_toppings:
            print("Adding mushrooms.")
         if 'pepperoni' in requested_toppings:
            print("Adding pepperoni.")
        if 'extra cheese' in requested_toppings:
            print("Adding extra cheese.")
        
        print("\nFinished making your pizza!")

Біз сұралған қоспаларды қамтитын тізімнен бастаймыз. Бірінші if операторы адамның пиццаға саңырауқұлақ сұрағанын тексереді. Олай болса, толтыруды растайтын хабарлама басып шығарылады. Pepperoni ❶ сынағы elif немесе else емес, басқа қарапайым if амалы болып табылады, сондықтан бұл сынақ алдыңғы сынақтан өткен-өтпегеніне қарамастан орындалады. Соңғы if амалы алғашқы екі сынақтың нәтижелеріне қарамастан, қосымша ірімшік сұралғанын тексереді. Бұл үш тәуелсіз сынақ осы бағдарлама іске қосылған сайын орындалады.

Бұл мысалдағы әрбір шарт бағаланғандықтан, пиццаға саңырауқұлақтар да, қосымша ірімшіктер де қосылады:


        Adding mushrooms.
        Adding extra cheese.
        
        Finished making your pizza!

Егер біз if-elif-else блогын қолдансақ, бұл код дұрыс жұмыс істемейді, себебі код тек бір сынақтан өтеді, одан кейін жұмысын тоқтатады. Бұл келесідей болады:


        requested_toppings = ['mushrooms', 'extra cheese']
        
        if 'mushrooms' in requested_toppings:
            print("Adding mushrooms.")
        elif 'pepperoni' in requested_toppings:
            print("Adding pepperoni.")
        elif 'extra cheese' in requested_toppings:
            print("Adding extra cheese.")
        
        print("\nFinished making your pizza!")

'mushrooms' сынағы бірінші тапсырылатын сынақ, сондықтан саңырауқұлақтар пиццаға қосылады. Дегенмен, 'extra cheese/қосымша ірімшік' және 'pepperoni' мәндері ешқашан тексерілмейді, өйткені Python if-elif-else тізбегінде бірінші сынақтан басқа сынақтарды өткізбейді. Тұтынушының бірінші қалауы қосылады, бірақ оның барлық басқа қалаған өзге ингредиенттері қосылмай қалады:


        Adding mushrooms.
        
        Finished making your pizza!

Қорыта айтқанда, тек бір код блогының іске қосылуын қаласаңыз, if-elif-else тізбегін пайдаланыңыз. Егер кодтың бірнеше блогын іске қосу қажет болса, тәуелсіз if амалдарының қатарын пайдаланыңыз.

if амалын Тізіммен қолдану

Тізімдер мен if операторларын біріктірген кезде қызықты жұмыстарды орындауға болады. Тізімдегі кейбір мәндерге қарағанда басқаша өңдеуді қажет ететін арнайы мәндер де болады. Ауысым болған кезде мейрамханада белгілі бір заттардың болуы не болмауы сияқты өзгеретін жағдайларды тиімді басқара аласыз. Сондай-ақ, кодыңыз барлық ықтимал жағдайларда сіз күткендей жұмыс істейтінін дәлелдей бастай аласыз.

Арнайы элементтерді тексеру

Бұл тарау тізімдегі басқа мәндерге қарағанда ерекше форматта басып шығаруды қажет ететін 'bmw' сияқты арнайы мәнді қалай өңдеу керектігін көрсететін қарапайым мысалдан басталды. Қазір сізде шартты сынақтар және if амалдары туралы негізгі түсінік болған соң, тізімдегі арнайы мәндерді қалай көруге және сол мәндерді дұрыс өңдеуге болатынын егжей-тегжейлі қарастырайық.

Пиццерия мысалымен жалғастырайық. Пиццерия пиццаға тағам дайындалып жатқан кезде қосымша ингредиент қосылған сайын хабарлама көрсетеді. Бұл әрекеттің кодын тұтынушы сұраған қоспалар тізімін жасау және пиццаға қосылған әрбір ингредиент туралы хабарлау үшін циклды пайдалану арқылы өте тиімді жазуға болады:

toppings.py


        requested_toppings = ['mushrooms', 'green peppers', 'extra cheese']
        
        for requested_topping in requested_toppings:
            print(f"Adding {requested_topping}.")
        
        print("\nFinished making your pizza!")

Шығарылым қарапайым, себебі бұл код қарапайым for циклі:


        Adding mushrooms.
        Adding green peppers.
        Adding extra cheese.
        
        Finished making your pizza!

Бірақ пиццерияда жасыл бұрыш таусылып қалса ше? for циклінің ішіндегі if операторы бұл жағдайды дұрыс өңдей алады:


        requested_toppings = ['mushrooms', 'green peppers', 'extra cheese']
        
        for requested_topping in requested_toppings:
            if requested_topping == 'green peppers':
                print("Sorry, we are out of green peppers right now.")
            else:
                print(f"Adding {requested_topping}.")
        
        print("\nFinished making your pizza!")

Бұл жолы біз әрбір сұралған элементті пиццаға қоспас бұрын тексереміз. if операторы адамның жасыл бұрыш сұрағанын тексереді. Олай болса, біз оларға неге жасыл бұрыш ала алмайтындығы туралы хабарды көрсетеміз. else блогы барлық басқа қоспалардың пиццаға қосылуын қамтамасыз етеді.

Шығарылым әрбір сұралған толтырудың тиісті түрде өңделгенін көрсетеді.


        Adding mushrooms.
        Sorry, we are out of green peppers right now.
        Adding extra cheese.
        
        Finished making your pizza!

Тізім бос емес екенін тексеру

Біз осы уақытқа дейін жұмыс істеген әрбір тізім туралы қарапайым болжам жасадық: біз әрбір тізімде кем дегенде бір элемент бар деп болжадық. Алдағы уақытта біз пайдаланушыларға тізімде сақталатын ақпаратты беруге рұқсат етеміз, сондықтан цикл іске қосылған сайын тізімде элементтер бар деп есептей алмаймыз. Бұл жағдайда for циклін іске қоспас бұрын тізімнің бос не бос емес екенін тексеру пайдалы.

Мысал ретінде пиццаны жасамас бұрын сұралған ингредиенттер тізімінің бос екенін тексеріп көрейік. Тізім бос болса, біз пайдаланушыға кеңес береміз және олардың қарапайым пицца алғысы келетініне көз жеткіземіз. Тізім бос болмаса, біз пиццаны алдыңғы мысалдардағыдай жасаймыз:


        requested_toppings = []
        
        if requested_toppings:
            for requested_topping in requested_toppings:
                print(f"Adding {requested_topping}.")
            print("\nFinished making your pizza!")
        else:
            print("Are you sure you want a plain pizza?")

Бұл жолы біз сұралған қоспалардың/ингредиенттердің бос тізімінен бастаймыз. for цикліне тікелей өтудің орнына, біз алдымен жылдам тексеру жасаймыз. Тізім атауы if операторында пайдаланылған кезде, тізімде кем дегенде бір элемент болса, Python True қайтарады; бос тізім False болып есептеледі. Егер requested_toppings шартты сынақтан өтсе, біз алдыңғы мысалда пайдаланған бірдей for циклін орындаймыз. Шартты сынақ сәтсіз аяқталса, біз тұтынушыдан қоспасы жоқ қарапайым пиццаны қалайтынын сұрайтын хабарды басып шығарамыз.

Бұл жағдайда тізім бос, сондықтан нәтиже пайдаланушы шынымен қарапайым пиццаны қалайтынын сұрайды:


        Are you sure you want a plain pizza?

Егер тізім бос болмаса, нәтиже пиццаға қосылған әрбір сұралған қоспаны көрсетеді.

Бірнеше тізімді пайдалану

Адамдар кез-келген нәрсені сұрайды, әсіресе бұл пицца қоспаларына қатысты. Егер тұтынушы шынымен пиццаға фри картоп алғысы келсе ше? Енгізгеніңіз әрекет етпес бұрын мағыналы екеніне көз жеткізу үшін тізімдер мен if амалдарын пайдалана аласыз.

Пицца жасамас бұрын, әдеттен тыс ингредиент сұрауларына назар аударайық. Келесі мысал екі тізімді анықтайды. Біріншісі - пиццериядағы қолжетімді қоспалар тізімі, екіншісі - пайдаланушы сұраған қоспалар тізімі. Бұл жолы requested_toppings ішіндегі әрбір элемент пиццаға қоспас бұрын қолжетімді қоспалар тізімімен салыстырылады:


        available_toppings = ['mushrooms', 'olives', 'green peppers',
                              'pepperoni', 'pineapple', 'extra cheese']
        
         requested_toppings = ['mushrooms', 'french fries', 'extra cheese']
        
        for requested_topping in requested_toppings:
             if requested_topping in available_toppings:
                print(f"Adding {requested_topping}.")
             else:
                print(f"Sorry, we don't have {requested_topping}.")
        
        print("\nFinished making your pizza!")

Біріншіден, біз осы пиццериядағы қолжетімді қоспалар тізімін анықтаймыз. Назар аударыңыз, егер пиццерияда қоспалардың тұрақты таңдауы болса, бұл кортеж болуы мүмкін. Содан кейін біз тұтынушы сұраған қоспалар тізімін жасаймыз. Бұл мысалда толтыруға әдеттен тыс сұрау бар: 'француз фри' ❶. Содан кейін біз сұралған қоспалар тізімін айналдырамыз. Цикл ішінде біз әрбір сұралған қосымшаның шын мәнінде қол жетімді толтырулар тізімінде бар-жоғын тексереміз ❷. Егер солай болса, біз пиццаға сол қоспаны қосамыз. Сұралған үстіңгі жағы қол жетімді толтырулар тізімінде болмаса, else блогы ❸ іске қосылады. else блогы пайдаланушыға қандай қоспалар қолжетімсіз екенін көрсететін хабарды басып шығарады.

Бұл код синтаксисі таза, ақпарат беретін нәтиже береді:


        Adding mushrooms.
        Sorry, we don't have french fries.
        Adding extra cheese.
        
        Finished making your pizza!

Кодтың бірнеше жолында біз нақты әлемдегі жағдайды өте тиімді басқардық!

If амалдарын сәндеу

Осы тараудағы әрбір мысалда сіз жақсы сәндеу әдеттерін көрдіңіз. PEP 8 шартты сынақтарды сәндеуге арналған жалғыз ұсыныс - ==, >= және <= сияқты салыстыру операторларының айналасында жалғыз бос орынды пайдалану. Мысалы:


        if age < 4:

төмендегіден жақсырақ:


        if age<4:

Мұндай интервал Python кодыңызды түсіндіру тәсіліне әсер етпейді; бұл сізге және басқаларға кодты оқуды жеңілдетеді.

Қорытынды

Бұл тарауда сіз әрқашан True немесе False деп бағаланатын шартты сынақтарды жазуды үйрендіңіз. Сіз қарапайым if операторларын, if-else тізбектерін және if-elif-else тізбектерді жазуды үйрендіңіз. Сіз бұл құрылымдарды сынау қажет нақты шарттарды анықтау және бағдарламаларыңызда сол шарттар орындалғанын білу үшін пайдалана бастадыңыз. for циклінің тиімділігін пайдалануды жалғастыра отырып, сіз тізімдегі кейбір элементтерді басқа элементтерге қарағанда басқаша өңдеуді үйрендіңіз. Сіз сондай-ақ Python стилі бойынша ұсыныстарды қайта қарап шықтыңыз, ол барған сайын күрделене түсетін бағдарламаларды оқуға және түсінуге салыстырмалы түрде оңай болуын қамтамасыз ету үшін.

6-тарауда сіз Python сөздіктері туралы біле аласыз. Сөздік тізімге ұқсас, бірақ ол ақпарат бөліктерін қосуға мүмкіндік береді. Сіз сөздіктерді құруды, оларды айналдыруды және оларды тізімдермен және if амалдарымен бірге пайдалануды үйренесіз. Сөздіктер туралы білу сізге шынайы өмірдегі жағдайлардың бұдан да кең ауқымын модельдеуге мүмкіндік береді.

Сөздік

ITUniver

6
Сөздік

Бұл тарауда сіз Python сөздіктерін пайдалануды үйренесіз, ол сізге байланысты ақпарат бөліктерін қосуға мүмкіндік береді. Ақпарат сөздікте болғаннан кейін оған қалай қол жеткізуге болатынын және сол ақпаратты қалай өзгерту керектігін үйренесіз. Сөздіктер ақпараттың шексіз көлемін сақтай алатындықтан, мен сізге сөздіктегі деректерді қалай цикл арқылы өту керектігін көрсетемін. Оған қоса, сөздіктерді тізімдерге, тізімдерді сөздіктерге, тіпті сөздіктерді басқа сөздіктерге орналастыруды үйренесіз.

Сөздіктерді түсіну нақты әлемдегі әртүрлі нысандарды дәлірек модельдеуге мүмкіндік береді. Сіз адамды білдіретін сөздікті жасай аласыз, содан кейін сол адам туралы қалағаныңызша ақпаратты сақтай аласыз. Сіз олардың атын, жасын, орналасқан жерін, мамандығын және сипаттауға болатын адамның кез-келген басқа аспектілерін сақтай аласыз. Сөздер мен олардың мағыналары тізімі, адамдардың есімдері мен олардың сүйікті сандар тізімі, таулар мен олардың биіктіктері тізімі және т.б. сияқты сәйкес келетін кез-келген екі ақпарат түрін сақтай аласыз.

Қарапайым сөздік

Түрлі түстер мен нүкте мәндері болуы мүмкін өзге планеталықтар қатысатын ойынды қарастырыңыз. Бұл қарапайым сөздік белгілі бір бөтен планеталық туралы ақпаратты сақтайды:

alien.py


        alien_0 = {'color': 'green', 'points': 5}
        
        print(alien_0['color'])
        print(alien_0['points'])

alien_0 сөздігі бөтеннің түсі мен нүкте мәнін сақтайды. Соңғы екі жол осы жерде көрсетілгендей ақпаратқа қол жеткізеді және көрсетеді:


        green
        5

Көптеген жаңа бағдарламалау концепциялары сияқты сөздіктерді пайдалану тәжірибені қажет етеді. Сөздіктермен біраз уақыт жұмыс істегеннен кейін, олардың нақты жағдайды қаншалықты тиімді үлгілей алатынын көресіз.

Сөздіктермен жұмыс

Python тіліндегі сөздіккілт-мән жұптарының жинағы. Әрбір кілт мәнге байланыстырылған және сол кілтпен байланысты мәнге кіру үшін кілтті пайдалануға болады. Кілттің мәні сан, тіркес, тізім немесе басқа сөздік болуы мүмкін. Шын мәнінде, сөздіктегі мән ретінде Python тілінде жасауға болатын кез-келген нысанды пайдалануға болады.

Python тілінде сөздік алдыңғы мысалда көрсетілгендей жақшаның ішіндегі кілт-мән жұптары қатары бар жақшаға ({}) оралған:


        alien_0 = {'color': 'green', 'points': 5}

Кілт-мән жұбы - бір-бірімен байланысты мәндер жинағы. Кілтті бергенде, Python сол кілтпен байланысты мәнді қайтарады. Әрбір кілт оның мәніне қос нүкте арқылы қосылады және жеке кілт-мән жұптары үтірмен бөлінеді. Сөздікте қалағаныңызша кілт-мән жұптарын сақтауға болады.

Ең қарапайым сөздікте alien_0 сөздігінің осы өзгертілген нұсқасында көрсетілгендей дәл бір кілт-мән жұбы бар:


        alien_0 = {'color': 'green'}

Бұл сөздік alien_0 туралы ақпараттың бір бөлігін сақтайды: өзге планеталықтың түсі. Мұнда 'color' тіркесі осы сөздіктегі кілт болып табылады және оның байланысты мәні 'green' болып табылады.

Сөздіктегі мәндерге қол жеткізу

Кілтпен байланысты мәнді алу үшін сөздіктің атын беріңіз, содан кейін кілтті мына жерде көрсетілгендей төртбұрышты жақшалар жинағына қойыңыз:

alien.py


        alien_0 = {'color': 'green'}
        print(alien_0['color'])

Бұл alien_0 сөздігіндегі 'color' кілтімен байланысты мәнді қайтарады:


        green

Сөздікте кілт-мән жұптарының шектеусіз саны болуы мүмкін. Мысалы, мұнда екі кілт-мән жұбы бар түпнұсқа alien_0 сөздігі берілген:


        alien_0 = {'color': 'green', 'points': 5}

Енді alien_0 түсін немесе нүкте мәніне қол жеткізе аласыз. Ойыншы осы бөтен планетаны атып түсірсе, келесі кодты пайдаланып оның қанша ұпай жинауы керектігін білуге болады:


        alien_0 = {'color': 'green', 'points': 5}
        
        new_points = alien_0['points']
        print(f"You just earned {new_points} points!")

Сөздік анықталғаннан кейін біз 'points' кілтімен байланысты мәнді сөздіктен аламыз. Содан кейін бұл мән new_points айнымалысына тағайындалады. Соңғы жол ойыншының қанша ұпай жинағаны туралы амалды басып шығарады:


        You just earned 5 points!

Егер бұл кодты бөтен планеталық атып түсірілген сайын іске қоссаңыз, соңында қорытынды ұпай мәні шығарылады.

Жаңа кілт-мән жұптарын қосу

Сөздіктер динамикалық құрылымдар болып табылады және сіз кез-келген уақытта сөздікке жаңа кілт-мән жұптарын қоса аласыз. Жаңа кілт-мән жұбын қосу үшін сөздіктің атын, одан кейін жаңа кілтті жаңа мәнмен бірге төртбұрышты жақшаға бересіз.

Қараңыз, alien_0 сөздігіне екі жаңа ақпарат қосайық: бөтеннің x- және y-координаталары, бұл бізге бөгде планеталықтарды экранның белгілі бір орнында көрсетуге көмектеседі. Бөтен планеталықты экранның сол жақ шетіне, жоғарыдан 25 пиксел төмен орналастырайық. Экран координаттары әдетте экранның жоғарғы сол жақ бұрышынан басталатындықтан, біз x-координатасын 0 және жоғарғы жағынан 25 пиксельге орнату арқылы бөгде планеталықты экранның сол жақ шетіне орналастырамыз. Оның y-координатын оң 25 мәніне орнату керек, мұнда көрсетілгендей:

alien.py


        alien_0 = {'color': 'green', 'points': 5}
        print(alien_0)
        
        alien_0['x_position'] = 0
        alien_0['y_position'] = 25
        print(alien_0)

Біз жұмыс істеп жатқан сөздікті анықтаудан бастаймыз. Содан кейін біз оның ақпаратының суретін көрсете отырып, осы сөздікті басып шығарамыз. Содан кейін сөздікке жаңа кілт-мән жұбын қосамыз: кілт 'x_position' және мәні 0. 'y_position' кілті үшін де солай істейміз. Өзгертілген сөздікті басып шығарған кезде біз екі қосымша кілт-мән жұбын көреміз:


        {'color': 'green', 'points': 5}
        {'color': 'green', 'points': 5, 'x_position': 0, 'y_position': 25}

Сөздіктің соңғы нұсқасында төрт кілт-мән жұбы бар. Екі бастапқы кілт түс пен ұпай мәнін, ал тағы екеуі бөтен планеталықтың орнын көрсетеді.

Сөздіктер анықталған ретін сақтайды. Сөздікті басып шығарғанда немесе оның элементтерін айналдырғанда (циклмен өткенде) элементтерді сөздікке қосылған ретпен көресіз.

Бос сөздіктен бастау

Кейде бос сөздіктен бастап, оған әрбір жаңа элементті қосу ыңғайлы немесе тіпті қажет. Бос сөздікті толтыруды бастау үшін бос жақшалар жинағы бар сөздікті анықтаңыз, содан кейін әрбір кілт-мән жұбын өз жолына қосыңыз. Мысалы, мына тәсілді пайдаланып alien_0 сөздігін құру жолы берілген:

alien.py


        alien_0 = {}
        
        alien_0['color'] = 'green'
        alien_0['points'] = 5
        
        print(alien_0)

Біз алдымен бос alien_0 сөздігін анықтаймыз, содан кейін оған түс пен ұпай мәндерін қосамыз. Нәтиже – біз алдыңғы мысалдарда пайдаланған сөздік:


        {'color': 'green', 'points': 5}

Әдетте пайдаланушы берген деректерді сөздікте сақтау немесе кілт-мән жұптарының көп санын автоматты түрде жасайтын код жазу кезінде бос сөздіктерді пайдаланасыз.

Сөздіктегі мәндерді өзгерту

Сөздіктегі мәнді өзгерту үшін төртбұрышты жақшадағы кілтпен сөздіктің атын, содан кейін сол кілтпен байланыстырғыңыз келетін жаңа мәнді беріңіз. Мысалы, ойын барысында жасылдан сарыға өзгеретін бөтен планеталықты қарастырайық:

alien.py


        alien_0 = {'color': 'green'}
        print(f"The alien is {alien_0['color']}.")
        
        alien_0['color'] = 'yellow'
        print(f"The alien is now {alien_0['color']}.")

Алдымен alien_0 сөздігін анықтаймыз, онда тек бөтеннің түсі ғана бар; содан кейін 'color' кілтімен байланысты мәнді 'yellow' мәніне өзгертеміз. Шығару бөтеннің шынымен жасылдан сарыға өзгергенін көрсетеді:


        The alien is green.
        The alien is now yellow.

Қызықтырақ мысал үшін әртүрлі жылдамдықпен қозғала алатын бөтен планеталықтың орнын бақылап көрейік. Біз бөтен планеталықтың ағымдағы жылдамдығын көрсететін мәнді сақтаймыз, содан кейін оны бөтен планеталықтың қаншалықты оңға қарай жылжыту керектігін анықтау үшін пайдаланамыз:


        alien_0 = {'x_position': 0, 'y_position': 25, 'speed': 'medium'}
        print(f"Original position: {alien_0['x_position']}")
        
        # Бөтен планеталықты оңға жылжытыңыз.
        # Бөтен планеталықтың ағымдағы жылдамдығына қарай...
        # ... қаншалықты алысқа жылжыту керектігін анықтаңыз.
         if alien_0['speed'] == 'slow':
            x_increment = 1
        elif alien_0['speed'] == 'medium':
            x_increment = 2
        else:
            # Мынау жылдам қозғалатын бөтен планеталық
            x_increment = 3
        
        # Жаңа позиция ескі позицияға қосылып жаңа қорытынды орын шығады.
         alien_0['x_position'] = alien_0['x_position'] + x_increment
        
        print(f"New position: {alien_0['x_position']}")

Біз бастапқы x/y позициясы және 'medium' жылдамдығы бар бөтен планеталықты анықтаудан бастаймыз. Қарапайымдылық үшін түс пен ұпай мәндерін алып тастадық, бірақ егер сіз осы кілт-мән жұптарын қоссаңыз, бұл мысал бәрібір дәл осылай жұмыс істейтін болады. Сондай-ақ, бөгде планеталықтың оңға қарай қаншалықты қозғалатынын көру үшін x_position бастапқы мәнін басып шығарамыз.

if-elif-else тізбегі бөтен планеталықтың қаншалықты оңға жылжу керектігін анықтайды және бұл мәнді x_increment айнымалысына тағайындайды. Бөтен планеталықтың жылдамдығы 'slow/баяу' болса, ол бір бірлік оңға жылжиды; егер жылдамдық 'medium/орташа' болса, ол екі бірлік оңға жылжиды; ал егер 'fast/жылдам' болса, ол үш бірлік оңға жылжиды. Өсу есептеліп болған соң, ❷ ол алғашқы x_position мәніне қосылады және нәтиже сөздіктің соңғы x_position мәнінде сақталады.

Бұл мысалдағы бөтен планеталық орташа жылдамдықты болғандықтан, оның орны екі бірлік оңға жылжытылады:


        Original x-position: 0
        New x-position: 2

Бұл әдіс өте тамаша: бөтен планеталық сөздігіндегі бір мәнді өзгерту арқылы сіз бөтеннің жалпы әрекетін өзгерте аласыз. Мысалы, осы орташа жылдамдықтағы бөтен планеталықты жылдам қозғалатын бөтен планеталыққа айналдыру үшін мына жолды қосасыз:


        alien_0['speed'] = 'fast'

if-elif-else блогы келесі жолы код іске қосылғанда x_increment мәніне үлкенірек мән тағайындайды.

Кілт-мән жұптарын жою

Сөздікте сақталған ақпараттың бір бөлігі қажет болмағанда, кілт-мән жұбын толығымен жою үшін del операторын пайдалануға болады. Ал del қажет ететін барлық ақпарат - сөздіктің атауы және сіз алып тастағыңыз келетін кілт.

Мысалы, 'points' кілтін alien_0 сөздігінен оның мәнімен бірге алып тастаймыз:

alien.py


        alien_0 = {'color': 'green', 'points': 5}
        print(alien_0)
        
         del alien_0['points']
        print(alien_0)

del амалы Python-ға alien_0 сөздігінен 'points' кілтін және сол кілтпен байланысты мәнді жоюды ұсынады. Шығару 'points' кілті және оның 5 мәні сөздіктен жойылғанын көрсетеді, бірақ сөздіктің қалған бөлігінде әрине ешқандай өзгеріс болмайды:


        {'color': 'green', 'points': 5}
        {'color': 'green'}

Ұқсас нысандар сөздігі

Алдыңғы мысал ойындағы бір нысан, бөтен планеталық туралы әртүрлі ақпаратты сақтауды қамтыды. Сондай-ақ сөздікті көптеген нысандар туралы ақпараттың бір түрін сақтау үшін пайдалануға болады. Мысалы, сіз бірнеше адаммен сауалнама жүргізгіңіз келеді делік және олардан олардың сүйікті бағдарламалау тілі қандай екенін сұраңыз. Сөздік қарапайым сауалнама нәтижелерін сақтау үшін пайдалы, мысалы:

favorite_languages.py


        favorite_languages = {
            'jen': 'python',
            'sarah': 'c',
            'edward': 'rust',
            'phil': 'python',
            }

Көріп отырғаныңыздай, біз үлкенірек сөздікті бірнеше жолға бөлдік. Әрбір кілт сауалнамаға жауап берген адамның аты болып табылады және әрбір мән олардың тіл таңдауы болып табылады. Сөздікті анықтап ақпаратты жазу үшін сізге бірнеше жол қажет екенін білсеңіз, ашылатын жақшадан кейін ENTER пернесін басыңыз. Содан кейін келесі тіркесті бір деңгейде шегіндіріңіз (төрт бос орын) және бірінші кілт-мән жұбын жазыңыз, одан кейін үтірді жазыңыз. Осы сәттен бастап ENTER пернесін басқан кезде мәтіндік өңдегіш бірінші кілт-мән жұбына сәйкес келу үшін барлық келесі кілт-мән жұптарын автоматты түрде шегіндіруі керек.

Сөздікті анықтауды аяқтағаннан кейін, соңғы кілт-мән жұбынан кейін жаңа жолға жабу жақшасын қосып, сөздіктегі пернелермен туралануы үшін оны бір деңгейде шегіндіріңіз. Соңғы кілт-мән жұбынан кейін үтірді де қою жақсы тәжірибе, сондықтан келесі жолға жаңа кілт-мән жұбын қосуға дайын боласыз.

Сауалнамаға қатысқан адамның аты берілген бұл сөздікті пайдалану үшін оның сүйікті тілін оңай іздеуге болады:

favorite_languages.py


        favorite_languages = {
            'jen': 'python',
            'sarah': 'c',
            'edward': 'rust',
            'phil': 'python',
            }
        
         language = favorite_languages['sarah'].title()
        print(f"Sarah's favorite language is {language}.")

Сара қай тілді таңдағанын көру үшін келесі мәнді сұраймыз:


        favorite_languages['sarah']

Біз бұл синтаксисті ❶ Сараның таңдаулы тілін favorite_languages сөздігінен алу және оны language айнымалысына тағайындау үшін қолданамыз. Мұнда жаңа айнымалы жасау әлдеқайда түсінікті-таза print() шақыруын жасайды. Шығару Сараның сүйікті тілін көрсетеді:


        Sarah's favorite language is C.

Сіз дәл осы синтаксисті сөздікте ұсынылған кез-келген тұлғамен пайдалана аласыз.

Мәндерге қол жеткізу үшін get() пайдалану

Сөздіктен сізді қызықтыратын мәнді алу үшін төртбұрышты жақшаға алынған кілтті пайдалану бір ықтимал ақаулықты тудыруы мүмкін: егер сіз сұраған кілт жоқ болса, қате пайда болады.

Ұпай мәні орнатылмаған бөгде планеталықтың ұпай мәнін сұрағанда не болатынын көрейік:

alien_no_points.py


        alien_0 = {'color': 'green', 'speed': 'slow'}
        print(alien_0['points'])

Бұл KeyError қатесін көрсететін кері бақылауға (traceback) әкеледі:


        Traceback (most recent call last):
          File "alien_no_points.py", line 2, in <module>
            print(alien_0['points'])
                  ~~~~~~~^^^^^^^^^^
        KeyError: 'points'

Осы сияқты қателерді жалпы өңдеу жолы туралы толығырақ 10-тараудан біле аласыз. Сөздіктер үшін арнайы бар сұралған кілт жоқ болғанда қайтарылатын әдепкі мәнді орнату үшін get() әдісін қолдануға болады.

get() әдісі бірінші аргумент ретінде кілтті қажет етеді. Екінші қосымша аргумент ретінде кілт жоқ болса, қайтарылатын мәнді беруге болады:


        alien_0 = {'color': 'green', 'speed': 'slow'}
        
        point_value = alien_0.get('points', 'No point value assigned.')
        print(point_value)

'points' кілті сөздікте бар болса, сәйкес мәнді аласыз. Олай болмаса, әдепкі мәнді аласыз. Бұл жағдайда points/ұпайлар жоқ және қатенің орнына түсінікті хабар аламыз:


        No point value assigned.

Егер сіз сұраған кілт жоқ болуы мүмкін болса, шаршы жақшаның орнына get() әдісін қолданып көріңіз.

Сөздік арқылы айналым

Бір Python сөздігі бірнеше кілт-мән жұптарын немесе миллиондаған жұптарды қамтуы мүмкін. Сөздікте деректердің үлкен көлемі болуы мүмкін болғандықтан, Python сөздікті айналдыруға (цикл арқылы өтуге) мүмкіндік береді. Сөздіктер ақпаратты әртүрлі тәсілдермен сақтау үшін пайдаланылуы мүмкін; сондықтан олар арқылы өтудің бірнеше түрлі жолдары бар. Сөздікті барлық кілт-мән жұптары, оның кілттері немесе мәндері арқылы циклмен айналып өтуге болады.

Барлық кілт-мән жұптары арқылы айналым

Циклдің әртүрлі тәсілдерін зерттемес бұрын, пайдаланушы туралы ақпаратты веб-сайтта сақтауға арналған жаңа сөздікті қарастырайық. Келесі сөздік бір адамның логин-атын, есімін және тегін сақтайды:

user.py


        user_0 = {
            'username': 'efermi',
            'first': 'enrico',
            'last': 'fermi',
            }

Алдыңғы тараулардағы алған біліміңізбен user_0 туралы кез-келген жалғыз ақпаратқа қол жеткізе аласыз. Бірақ осы пайдаланушы сөздігінде сақталған ақпараттың барлығын көргіңіз келсе ше? Ол үшін for циклін пайдаланып сөздікті айналдыра аласыз:


        user_0 = {
            'username': 'efermi',
            'first': 'enrico',
            'last': 'fermi',
            }
        
        for key, value in user_0.items():
            print(f"\nKey: {key}")
            print(f"Value: {value}")

Сөздікке for циклін жазу үшін әрбір кілт-мән жұбында кілт пен мәнді сақтайтын екі айнымалыға атаулар жасайсыз. Осы екі айнымалы үшін қалаған кез-келген атауларды таңдауға болады. Егер айнымалы атаулары үшін қысқартуларды пайдалансаңыз, бұл код дәл осылай жұмыс істейтін еді, мысалы:


        for k, v in user_0.items()

for амалының екінші жартысы сөздік атауын және одан кейін келетін items() әдісін қамтиды, items() әдісі кілт-мән жұптарының тізбегін қайтарады. for циклі осы жұптардың әрқайсысын берілген екі айнымалыға тағайындайды. Алдыңғы мысалда біз айнымалы мәндерді әрбір key/кілтті басып шығару үшін қолданамыз, содан кейін кілтпен байланысты value/мәнді басып шығару үшін. Бірінші print() шақыруындағы "\n" шығыстағы әрбір кілт-мән жұбының алдында бос жолдың кірістірілуін қамтамасыз етеді:


        Key: username
        Value: efermi
        
        Key: first
        Value: enrico
        
        Key: last
        Value: fermi

Барлық кілт-мән жұптарын айналдыру әсіресе алдында көрсетілген favorite_languages.py мысалы сияқты сөздіктер үшін жақсы жұмыс істейді, ол көптеген әртүрлі кілттер үшін бірдей ақпаратты сақтайды. favorite_languages сөздігін айналдырсаңыз, сөздіктегі әрбір адамның атын және олардың сүйікті бағдарламалау тілін аласыз. Кілттер әрқашан адамның атына сілтеме жасайтындықтан және мән әрқашан тіл болғандықтан, циклде key орнына name және value орнына language айнымалы мәндерін қолданамыз. Бұл цикл ішінде не болып жатқанын бақылауды жеңілдетеді:

favorite_languages.py


        favorite_languages = {
            'jen': 'python',
            'sarah': 'c',
            'edward': 'rust',
            'phil': 'python',
            }
        
        for name, language in favorite_languages.items():
            print(f"{name.title()}'s favorite language is {language.title()}.")

Бұл код Python-ға сөздіктегі әрбір кілт-мән жұбын айналдыруды ұсынады. Әр жұп арқылы жұмыс істегенде кілт name айнымалысына, ал мән language айнымалысына тағайындалады. Бұл сипаттама атаулар print() шақыруының не істеп жатқанын көруді әлдеқайда жеңілдетеді.

Енді кодтың бірнеше жолында біз сауалнамадағы барлық ақпаратты көрсете аламыз:


        Jen's favorite language is Python.
        Sarah's favorite language is C.
        Edward's favorite language is Rust.
        Phil's favorite language is Python.

Егер сөздігіміз мың, тіпті миллион адамнан алынған сауалнама нәтижелерін сақтаса, циклдің бұл түрі жақсы жұмыс істейтін еді.

Сөздіктегі барлық кілт сөздерді айналдыру

keys() әдісі сөздіктегі барлық мәндермен жұмыс істеу қажет болмағанда пайдалы. favorite_languages сөздігін қарап шығып, сауалнамаға қатысқандардың барлығының атын басып шығарайық:


        favorite_languages = {
            'jen': 'python',
            'sarah': 'c',
            'edward': 'rust',
            'phil': 'python',
            }
        
        for name in favorite_languages.keys():
            print(name.title())

Бұл for циклі Python-ға favorite_languages сөздігінен барлық кілттерді шығарып, оларды name айнымалысына бір-бірден тағайындауды ұсынады. Шығармада сауалнамаға қатысқандардың барлығының есімі көрсетіледі:


        Jen
        Sarah
        Edward
        Phil

Кілт сөздерді айналдыру сөздікті айналдыру кезінде әдепкі әрекет болып табылады, сондықтан егер сіз былай деп жазсаңыз, екі кодтың нәтижесі бірдей болады:


        for name in favorite_languages:

орнына мынау:


        for name in favorite_languages.keys():

Кодыңызды оқуды жеңілдететін болса, keys() әдісін анық пайдалануды таңдауға болады немесе қаласаңыз, оны өткізіп жіберуге болады.

Сіз ағымдағы кілтті пайдалану арқылы цикл ішінде өзіңізге маңызды кез-келген кілтпен байланысты мәнге қол жеткізе аласыз. Бірнеше досыңызға олар таңдаған тілдер туралы хабарлама басып шығарайық. Бұрынғыдай сөздіктегі атауларды қайталаймыз, бірақ атау достарымыздың біріне сәйкес келгенде, олардың сүйікті тілі туралы хабарды көрсетеміз:


        favorite_languages = {
              'jen': 'python',
              'sarah': 'c',
              'edward': 'rust',
              'phil': 'python',
            }
        
        friends = ['phil', 'sarah']
        for name in favorite_languages.keys():
            print(f"Hi {name.title()}.")
        
             if name in friends:
                 language = favorite_languages[name].title()
                print(f"\t{name.title()}, I see you love {language}!")

Біріншіден, біз хабарды басып шығарғымыз келетін достар тізімін жасаймыз. Цикл ішінде біз әр адамның атын басып шығарамыз. ❶ Содан кейін біз жұмыс істеп жатқан name friends тізімінде бар-жоғын тексереміз. ❷ Егер солай болса, біз сөздік атауын және кілті ретінде name ағымдағы мәнін пайдаланып, адамның сүйікті тілін анықтаймыз. Содан кейін біз олардың сүйікті бағдарламалау тілін көрсететін арнайы сәлемдемені басып шығарамыз.

Әр адамның аты басылған, бірақ біздің достарымыз арнайы хабарлама алады:


        Hi Jen.
        Hi Sarah.
            Sarah, I see you love C!
        Hi Edward.
        Hi Phil.
            Phil, I see you love Python!

Сонымен қатар белгілі бір адамның сауалнамаға қатысқанын не қатыспағанын білу үшін keys() әдісін пайдалануға болады. Бұл жолы Эрин сауалнамаға қатысқанын-қатыспағанын білейік:


        favorite_languages = {
            --snip/код үзіндісі--
            }
        
        if 'erin' not in favorite_languages.keys():
            print("Erin, please take our poll!")

keys() әдісі тек цикл жасап айналып шығу үшін ғана емес: ол шын мәнінде барлық кілттердің тізбегін қайтарады, ал if операторы 'erin' осы тізбекте бар-жоғын тексереді. Ол жоқ болғандықтан, оны сауалнамаға қатысуға шақыратын хабар басып шығарылады:


        Erin, please take our poll!

Сөздік кілттерін белгілі бір ретпен айналып өту

Сөздікті циклмен өту элементтерді енгізілген ретпен қайтарады. Дегенмен, кейде сөздікті басқа ретпен айналдырғыңыз келеді.

Мұны орындаудың бір жолы - кілттер for циклінде қайтарылған уақытта сұрыптау. Кілттердің көшірмесін ретімен алу үшін sorted() функциясын пайдалануға болады:


        favorite_languages = {
            'jen': 'python',
            'sarah': 'c',
            'edward': 'rust',
            'phil': 'python',
            }
        
        for name in sorted(favorite_languages.keys()):
            print(f"{name.title()}, thank you for taking the poll.")

Бұл for амалы басқа for амалдарына ұқсайды, тек dictionary.keys() әдісін sorted() функциясымен орап алғанымызды қоспағанда. Бұл Python-ға сөздіктегі барлық кілттерді алуды және циклды бастамас бұрын оларды сұрыптауды тапсырады. Шығару сауалнамаға қатысқандардың барлығының есімдерін ретпен көрсетеді:


        Edward, thank you for taking the poll.
        Jen, thank you for taking the poll.
        Phil, thank you for taking the poll.
        Sarah, thank you for taking the poll.

Сөздіктегі барлық мәндерді айналым

Егер сізді ең алдымен сөздіктегі мәндер қызықтырса, ешбір кілтсіз мәндер тізбегін қайтару үшін values() әдісін пайдалануға болады. Мысалы, әр тілді таңдаған адамның атын көрсетпей, бағдарламалау тіліндегі сауалнамада таңдалған барлық тілдердің тізімін жай ғана алғымыз келеді делік:


        favorite_languages = {
            'jen': 'python',
            'sarah': 'c',
            'edward': 'rust',
            'phil': 'python',
            }
        
        print("The following languages have been mentioned:")
        for language in favorite_languages.values():
            print(language.title())

Мұндағы for операторы әрбір мәнді сөздіктен алып, оны language айнымалысына тағайындайды. Бұл мәндер басып шығарылғанда, біз барлық таңдалған тілдердің тізімін аламыз:


        The following languages have been mentioned:
        Python
        C
        Rust
        Python

Бұл тәсіл қайталауларды тексермей-ақ сөздіктегі барлық мәндерді шығарады. Бұл мәндердің аз санымен жақсы жұмыс істеуі мүмкін, бірақ респонденттердің көп саны бар сауалнамада бұл өте қайталанатын тізімге әкеледі. Қайталаусыз таңдалған әрбір тілді көру үшін біз жиынтықты (set) пайдалана аламыз. Set/жиын - бұл әрбір элемент ерекше болуы керек жинақ:


        favorite_languages = {
            --snip/код үзіндісі--
            }
        
        print("The following languages have been mentioned:")
        for language in set(favorite_languages.values()):
            print(language.title())

Қайталанатын элементтерді қамтитын мәндер жинағының айналасына set() ораған кезде, Python жинақтағы бірегей элементтерді анықтайды және сол элементтерден жиын құрастырады. Мұнда біз set() әдісін favorite_languages.values() ішіндегі бірегей тілдерді шығару үшін қолданамыз.

Нәтиже - сауалнамаға қатысқан адамдар айтқан тілдердің қайталанбайтын тізімі:


        The following languages have been mentioned:
        Python
        C
        Rust

Python туралы үйренуді жалғастыра отырып, деректеріңізбен дәл қалағаныңызды жасауға көмектесетін тілдің кірістірілген мүмкіндігін жиі табасыз.

Nesting

Кейде тізімде бірнеше сөздіктерді сақтағыңыз келеді, немесе кері жағдай да қажет болуы мүмкін элементтер тізімін сөздіктегі мән ретінде сақтағыңыз келеді. Бұл nesting /кірістіру деп аталады. Сөздіктерді тізімнің ішіне, сөздік ішіне элементтердің тізімін немесе тіпті сөздікті басқа сөздіктің ішіне орналастыруға болады. Кірістіру - бұл қуатты мүмкіндік, оны келесі мысалдар көрсетеді.

Сөздіктер тізімі

alien_0 сөздігі бір бөтен планеталық туралы алуан түрлі ақпаратты қамтиды, бірақ оның екінші бөтен планеталық туралы ақпаратты сақтауға орыны жоқ, тіпті бөтен планеталықтардың экран толтыратын қаптаған саны бар делік. Өзге планеталықтар флотын қалай басқаруға болады? Оның бір жолы - әрбір бөтен планеталық сол бөтен планеталық туралы ақпараттың сөздігі болатын өзге планеталықтардың тізімін жасау. Мысалы, келесі код үш бөтен планеталықтар тізімін жасайды:

aliens.py


        alien_0 = {'color': 'green', 'points': 5}
        alien_1 = {'color': 'yellow', 'points': 10}
        alien_2 = {'color': 'red', 'points': 15}
        
         aliens = [alien_0, alien_1, alien_2]
        
        for alien in aliens:
            print(alien)

Біз алдымен үш сөздік жасаймыз, олардың әрқайсысы жеке-жеке бөтен планеталықтарды білдіреді. Біз осы сөздіктердің әрқайсысын aliens ❶ деп аталатын тізімде сақтаймыз. Соңында біз тізімді айналдырамыз және әрбір бөтен планеталықты басып шығарамыз:


        {'color': 'green', 'points': 5}
        {'color': 'yellow', 'points': 10}
        {'color': 'red', 'points': 15}

Нақтырақ мысалға әрбір бөтен планеталықты автоматты түрде жасайтын коды бар үштен астам өзге планеталықтар жатады. Келесі мысалда біз 30 өзге планеталықтардан тұратын флот құру үшін range() қолданамыз:


        # Make an empty list for storing aliens.
        aliens = []
        
        # Make 30 green aliens.
         for alien_number in range(30):
             new_alien = {'color': 'green', 'points': 5, 'speed': 'slow'}
             aliens.append(new_alien)
        
        # Show the first 5 aliens.
         for alien in aliens[:5]:
            print(alien)
        print("...")
        
        # Show how many aliens have been created.
        print(f"Total number of aliens: {len(aliens)}")

Бұл мысал жасалатын барлық өзге планеталықтарды сақтайтын бос тізімнен басталады. ❶ range() функциясы жәй сандар қатарын қайтарады, бұл Python-ға цикл қанша рет қайталанып орындалатынын айтады. қайталаңыз. Цикл іске қосылған сайын біз жаңа бөтен планеталық ❷ жасаймыз, содан кейін әрбір жаңа бөтен планеталықты ❸ aliens тізіміне қосамыз. Біз алғашқы бес бөтен планеталықты ❹ басып шығару үшін кесінді (slice) қолданамыз және соңында толық ақпаратты жасағанымызды дәлелдеу үшін тізімнің ұзындығын басып шығарамыз. 30 өзге планеталық флот:


        {'color': 'green', 'points': 5, 'speed': 'slow'}
        {'color': 'green', 'points': 5, 'speed': 'slow'}
        {'color': 'green', 'points': 5, 'speed': 'slow'}
        {'color': 'green', 'points': 5, 'speed': 'slow'}
        {'color': 'green', 'points': 5, 'speed': 'slow'}
        ...
        
        Total number of aliens: 30

Бұл бөтен планеталықтардың барлығының сипаттамалары бірдей, бірақ Python әрқайсысын жеке нысан деп санайды, бұл бізге әрбір бөтен планетаны жеке өзгертуге мүмкіндік береді.

Осындай өзге планеталықтар тобымен қалай жұмыс істеуге болады? Ойынның бір аспектісінде кейбір бөтен планеталықтар ойын барысында түсін өзгертіп, жылдамырақ қозғалатынын елестетіп көріңіз. Түстерді өзгерту уақыты келгенде, біз өзге планеталықтардың түсін өзгерту үшін for циклін және if операторын пайдалана аламыз. Мысалы, алғашқы үш бөтен планеталықтардың әрқайсысы 10 ұпайдан тұратын сары, орташа жылдамдықтағы өзге планеталықтарға өзгерту үшін мына әрекетті орындауға болады:


        # Make an empty list for storing aliens.
        aliens = []
        
        # Make 30 green aliens.
        for alien_number in range (30):
            new_alien = {'color': 'green', 'points': 5, 'speed': 'slow'}
            aliens.append(new_alien)
        
        for alien in aliens[:3]:
            if alien['color'] == 'green':
                alien['color'] = 'yellow'
                alien['speed'] = 'medium'
                alien['points'] = 10
        
        # Show the first 5 aliens.
        for alien in aliens[:5]:
            print(alien)
        print("...")

Алғашқы үш бөтен планеталықты өзгерткіміз келетіндіктен, біз тек алғашқы үш өзге планеталықтарды қамтитын бөлікті айналдырамыз. Барлық өзге планеталықтар қазір жасыл, бірақ бұл әрқашан бола бермейді, сондықтан біз тек жасыл өзге планеталықтарды өзгерткенімізге көз жеткізу үшін if амалынан жазамыз. Егер бөтен планеталық жасыл болса, түсін ' Yellow', жылдамдықты 'medium' және ұпай мәнін 10 деп өзгертеміз, келесі шығыста көрсетілгендей:


        {'color': 'yellow', 'points': 10, 'speed': 'medium'}
        {'color': 'yellow', 'points': 10, 'speed': 'medium'}
        {'color': 'yellow', 'points': 10, 'speed': 'medium'}
        {'color': 'green', 'points': 5, 'speed': 'slow'}
        {'color': 'green', 'points': 5, 'speed': 'slow'}
        ...

Бұл циклды әр қайсысы 15 ұпайдан тұратын сары бөтен планеталарды қызылға, жылдам қозғалатындарға айналдыратын elif блогын қосу арқылы кеңейтуге болады. Бүкіл бағдарламаны қайта көрсетпестен, бұл цикл келесідей болады:


        for alien in aliens[0:3]:
            if alien['color'] == 'green':
                alien['color'] = 'yellow'
                alien['speed'] = 'medium'
                alien['points'] = 10
            elif alien['color'] == 'yellow':
                alien['color'] = 'red'
                alien['speed'] = 'fast'
                alien['points'] = 15

Әр сөздікте бір нысан туралы ақпараттың көп түрі болса, тізімде бірнеше сөздіктерді сақтау әдеттегідей. Мысалы, алдыңғы бөлімдердегі user.py файлында жасағандай, веб-сайттағы әрбір пайдаланушы үшін сөздік жасауға болады, және жеке сөздіктерді users деп аталатын тізімде сақтаңыз. Тізімдегі барлық сөздіктер бірдей құрылымға ие болуы керек, осылайша тізімді айналдырып, әрбір сөздік нысанымен бірдей жұмыс жасай аласыз.

Сөздіктегі тізім

Тізімнің ішіне сөздік қоюдың орнына, кейде тізімді сөздік ішіне қою пайдалы. Мысалы, біреу тапсырыс беріп жатқан пиццаны қалай сипаттайтыныңызды қарастырыңыз. Егер сіз тек тізімді қолданатын болсаңыз, онда сіз шынымен сақтай алатын нәрсе - бұл пицца қоспаларының тізімі. Сөздіктің көмегімен қоспалар тізімі сіз сипаттап жатқан пиццаның бір ғана аспектісі болуы мүмкін.

Келесі мысалда әрбір пицца үшін ақпараттың екі түрі сақталады: қыртыстың түрі және қоспалар тізімі. Толтырмалар тізімі 'toppings' кілтімен байланысты мән болып табылады. Тізімдегі элементтерді пайдалану үшін сөздіктегі кез-келген мән сияқты сөздіктің атын және 'toppings' кілтін береміз. Бір мәнді қайтарудың орнына біз толтырулар тізімін аламыз:

pizza.py


        # Store information about a pizza being ordered.
        pizza = {
            'crust': 'thick',
            'toppings': ['mushrooms', 'extra cheese'],
            }
        
        # Summarize the order.
         print(f"You ordered a {pizza['crust']}-crust pizza "
            "with the following toppings:")
        
         for topping in pizza['toppings']:
            print(f"\t{topping}")

Біз тапсырыс берілген пицца туралы ақпаратты қамтитын сөздіктен бастаймыз. Сөздіктегі кілттердің бірі 'crust' және байланысты мән 'thick' жолы болып табылады. Келесі кілт, 'toppings', барлық сұралған толтырғыш-ингредиенттерді сақтайтын мән ретінде тізімге ие. ❶ Пиццаны жасамас (басып шығармас) бұрын тапсырысты қорытындылаймыз. Егер print() шақыруында ұзын жолды үзу қажет болғанда, басып шығарылатын тіркесті үзу үшін сәйкес нүктені таңдап, тіркесті тырнақшамен аяқтаңыз. Келесі сөйлем бөлігін шегіндіріңіз, ашылу тырнақшасын қосыңыз және тіркесті жалғастырыңыз. Python автоматты түрде жақша ішінде тапқан барлық тіркестерді біріктіреді. Қоспаларды басып шығару үшін for циклін ❷ жазамыз. Ингредиенттер тізіміне қол жеткізу үшін біз 'toppings' кілтін қолданамыз, ал Python сөздіктен ингредиенттер тізімін алады.

Келесі шығарылымда біз жасауды жоспарлап отырған пиццаны қорытындылайды:


        You ordered a thick-crust pizza with the following toppings:
            mushrooms 
            extra cheese 

          # Сіз келесі қоспалары бар қалың қыртысы бар пиццаға тапсырыс бердіңіз:
          # саңырауқұлақтар
          # қосымша ірімшік
        

Сөздіктегі бір кілтпен бірнеше мәннің байланысты болғанын қаласаңыз тізімді сөздіктің ішіне кірістіруге болады. Сүйікті бағдарламалау тілдерінің алдыңғы мысалында, егер біз әрбір адамның жауаптарын тізімде сақтайтын болсақ, адамдар бірнеше сүйікті тілдерді таңдай алады. Біз сөздікті айналдырған кезде әрбір адамға қатысты мән бір тіл емес, тілдер тізімі болады. Сөздіктің for циклінің ішінде біз әр адаммен байланыстырылған тілдер тізімін аралау үшін басқа for циклін қолданамыз:

favorite_languages.py


        favorite_languages = {
            'jen': ['python', 'rust'],
            'sarah': ['c'],
            'edward': ['rust', 'go'],
            'phil': ['python', 'haskell'],
            }
        
         for name, languages in favorite_languages.items():
            print(f"\n{name.title()}'s favorite languages are:")
             for language in languages:
                print(f"\t{language.title()}")

favorite_languages ішіндегі әрбір адам есімімен байланысты мән енді тізім болып табылады. Кейбір адамдардың бір сүйікті тілі, ал басқаларының бірнеше таңдаулы тілі бар екенін ескеріңіз. favorite_languages ❶ сөздігін айналдырған кезде сөздіктегі әрбір мәнді сақтау үшін languages айнымалы атауын қолданамыз, өйткені бізде әрбір мән тізім болатынын біліңіз. Негізгі сөздік циклінің ішінде біз әрбір адамның таңдаулы тілдерінің тізімін қарап шығу үшін басқа for циклін ❷ қолданамыз. Енді әр адам қалағанынша сүйікті тілдерді тізімдей алады:


        Jen's favorite languages are:
            Python
            Rust
        
        Sarah's favorite languages are:
            C
        
        Edward's favorite languages are:
            Rust
            Go
        
        Phil's favorite languages are:
            Python
            Haskell

Бұл бағдарламаны одан әрі нақтылау үшін сөздіктің for циклінің басына if операторын қосуға болады, бұл әр адамның бірнеше таңдаулы тілі бар-жоғын білу үшін len(languages) мәніне назар аударуымыз керек. Егер адамда бірнеше сүйікті бағдарламалау тілі болса, нәтиже өзгеріссіз қалады. Егер адамның бір ғана сүйікті тілі болса, оны көрсету үшін сөзді өзгертуге болады. Мысалы, "Сараның сүйікті тілі - C." дей аласыз. (Ағылшын тіліндегі жеке және көп мәндегі сөздердің жазылуына қатысты айтылып отыр: мысалы, car - cars, pen - pens, book - books).

Сөздіктегі сөздік

Сөздікті басқа сөздік ішіне кірістіруге болады, бірақ оны жасаған кезде кодыңыз тез күрделене түсуі мүмкін. Мысалы, веб-сайт үшін әрқайсысының бірегей пайдаланушы аты бар бірнеше пайдаланушы болса, пайдаланушы атын сөздіктегі кілттер ретінде пайдалануға болады. Содан кейін сөздікті пайдаланушы атымен байланысты мән ретінде пайдалану арқылы әрбір пайдаланушы туралы ақпаратты сақтауға болады. Келесі тізімде біз әрбір пайдаланушы туралы үш ақпарат бөлігін сақтаймыз: олардың аты, тегі және орналасқан жері. Біз бұл ақпаратқа пайдаланушы аттары мен әрбір пайдаланушы атына қатысты ақпарат сөздігін айналдыру арқылы қол жеткіземіз:

many_users.py


        users = {
            'aeinstein': {
                'first': 'albert',
                'last': 'einstein',
                'location': 'princeton',
                },
        
            'mcurie': {
                'first': 'marie',
                'last': 'curie',
                'location': 'paris',
                },
        
            }
        
         for username, user_info in users.items():
             print(f"\nUsername: {username}")
             full_name = f"{user_info['first']} {user_info['last']}"
            location = user_info['location']
        
             print(f"\tFull name: {full_name.title()}")
            print(f"\tLocation: {location.title()}")

Біз алдымен екі кілті бар users деп аталатын сөздікті анықтаймыз: әрқайсысы 'aeinstein' және 'mcurie' пайдаланушы аттары үшін бір. Әрбір кілтпен байланысты мән әрбір пайдаланушының атын, тегін және орнын қамтитын сөздік болып табылады. Содан кейін пайдаланушылар сөздігін ❶ арқылы айналдырамыз. Python әр кілтті username айнымалысына тағайындайды және әрбір пайдаланушы атымен байланысты сөздік user_info айнымалысына тағайындалады. Негізгі сөздік цикліне кіргеннен кейін біз ❷ пайдаланушы атын басып шығарамыз.

Одан кейін біз ❸ ішкі сөздігіне қол жеткізе бастаймыз. Пайдаланушы ақпаратының сөздігін қамтитын user_info айнымалысының үш кілті бар: 'бірінші', 'соңғы' және ' орны'. Біз әр пернені әр адам үшін ұқыпты пішімделген толық аты-жөні мен орнын жасау үшін пайдаланамыз, содан кейін әрбір пайдаланушы ❹ туралы білетініміздің қысқаша мазмұнын басып шығарамыз:


        Username: aeinstein
            Full name: Albert Einstein
            Location: Princeton
        
        Username: mcurie
            Full name: Marie Curie
            Location: Paris

Әрбір пайдаланушы сөздігінің құрылымы бірдей екенін ескеріңіз. Python талап етпесе де, бұл құрылым кірістірілген сөздіктермен жұмыс істеуді жеңілдетеді. Әрбір пайдаланушы сөздігінде әртүрлі кілттер болса, for циклінің ішіндегі код күрделірек болар еді.

Қорытынды

Бұл тарауда сөздікке анықтама беруді және сөздікте сақталған ақпаратпен жұмыс істеуді үйрендіңіз. Сіз сөздіктегі жеке элементтерге қалай қол жеткізуге және өзгертуге болатынын және сөздіктегі барлық ақпаратты қалай айналдыру керектігін үйрендіңіз. Сіз сөздіктің кілт-мән жұптарын, оның кілттерін және мәндерін айналдыруды үйрендіңіз. Сондай-ақ бірнеше сөздіктерді тізімге, тізімдерді сөздікке енгізуді және сөздікті сөздік ішіне кірістіруді үйрендіңіз.

Келесі тарауда сіз while циклдары және сіздің бағдарламаларыңызды пайдаланатын адамдардан енгізуді қалай қабылдауға болатынын білесіз. Бұл қызықты тарау болады, өйткені сіз барлық бағдарламаларыңызды интерактивті етуді үйренесіз: олар пайдаланушы енгізуіне жауап бере алады.

User Input және while Loops

ITUniver

7
User Input және while Loops

Бағдарламалардың көпшілігі соңғы пайдаланушының мәселесін шешу үшін жазылған. Мұны істеу үшін әдетте пайдаланушыдан кейбір ақпаратты алу керек. Мысалы, біреудің дауыс беруге жасы жететінін білгісі келетінін айтыңыз. Бұл сұраққа жауап беру үшін бағдарлама жазсаңыз, жауап бермес бұрын пайдаланушының жасын білуіңіз керек. Бағдарлама пайдаланушыдан өз жасын енгізуді немесе input сұрауы керек; Бағдарлама осы енгізуді алғаннан кейін, ол пайдаланушының жасы жеткілікті екенін анықтау үшін оны дауыс беру жасымен салыстыра алады, содан кейін нәтижені хабарлайды.

Бұл тарауда сіз бағдарламаңыз онымен жұмыс істей алатындай пайдаланушы енгізуін қалай қабылдау керектігін үйренесіз. Бағдарламаға атау-есім қажет болғанда, пайдаланушыдан атауды-есімді сұрай аласыз. Бағдарламаға атаулар тізімі қажет болғанда, пайдаланушыдан бірқатар атауларды сұрай аласыз. Ол үшін input() функциясын пайдаланасыз.

Сонымен қатар сіз бағдарламаларды пайдаланушылар қалағанша жұмыс істеп тұруды үйренесіз, осылайша олар қажетінше көп ақпаратты енгізе алады; онда сіздің бағдарламаңыз сол ақпаратпен жұмыс істей алады. Белгілі бір шарттар орындалғанша бағдарламалардың жұмысын жалғастыру үшін Python бағдарламасының while циклін пайдаланасыз.

Пайдаланушы енгізуімен жұмыс істеу мүмкіндігімен және бағдарламаларыңыздың қанша уақыт жұмыс істейтінін басқару мүмкіндігімен сіз толық интерактивті бағдарламалар жаза аласыз.

input() функциясы қалай жұмыс істейді

input() функциясы бағдарламаңызды тоқтатады және пайдаланушының кейбір мәтінді енгізуін күтеді. Python пайдаланушының енгізуін алғаннан кейін, ол сізге жұмыс істеуге ыңғайлы болу үшін енгізілген мәнді айнымалыға тағайындайды.

Мысалы, келесі бағдарлама пайдаланушыдан мәтін енгізуді сұрайды, содан кейін сол хабарламаны пайдаланушыға кері көрсетеді:

parrot.py


        message = input("Tell me something, and I will repeat it back to you: ")
        print(message)

input() функциясы бір аргументті алады: пайдаланушыға көрсеткіміз келетін сұрау/prompt, сондықтан олар қандай ақпарат енгізу керектігін біледі. Бұл мысалда, Python бірінші жолды іске қосқанда, пайдаланушы Маған бірдеңе айтыңыз, және мен оны сізге қайталаймын: шақыруын көреді. Бағдарлама пайдаланушы өз жауабын енгізгенше күтеді және пайдаланушы ENTER пернесін басқаннан кейін жұмысын жалғастырады. Жауап message айнымалысына тағайындалады, содан кейін print(message) енгізуді пайдаланушыға кері көрсетеді:


        Tell me something, and I will repeat it back to you: Hello everyone!
        Hello everyone!

Түсінікті prompt/сұрауларды жазу

input() функциясын пайдаланған сайын, пайдаланушы қандай ақпарат түрін енгізгенін қалайтыныңызды нақты көрсететін түсінікті, орындауға оңай сұрауды/prompt қосу керек. Пайдаланушыға не енгізу керектігін айтатын кез-келген амал жұмыс істеуі керек. Мысалы:

greeter.py


        name = input("Please enter your name: ")
        print(f"\nHello, {name}!")

Сұрауды пайдаланушының жауабынан бөлу және пайдаланушыға олардың мәтінін қай жерде енгізу керектігін түсіндіру үшін сұраулардың соңына бос орын қосыңыз (алдыңғы мысалдағы қос нүктеден кейін). Мысалы:


        Please enter your name: Eric
        Hello, Eric!

Кейде бір жолдан ұзағырақ сұрау жазғыңыз келеді. Мысалы, пайдаланушыға белгілі бір енгізуді не үшін сұрап жатқаныңызды айтқыңыз келуі мүмкін. Сұрауды айнымалыға тағайындауға және сол айнымалы мәнді input() функциясына беруге болады. Бұл сұрауды бірнеше жолдан құруға, содан кейін таза input() операторын жазуға мүмкіндік береді.

greeter.py


        prompt = "If you share your name, we can personalize the messages you see."
        prompt += "\nWhat is your first name? "
        
        name = input(prompt)
        print(f"\nHello, {name}!")

Бұл мысал көп жолды тіркесті құрудың бір әдісін көрсетеді. Бірінші жол хабардың бірінші бөлігін prompt айнымалысына тағайындайды. Екінші жолда += операторы prompt-қа тағайындалған тіркесті алып, жаңа тіркесті соңына қосады.

Сұрау енді екі жолды қамтиды, түсінікті болу үшін сұрақ белгісінен кейін бос орын қалдырылған:


        If you share your name, we can personalize the messages you see.
        What is your first name? Eric
        
        Hello, Eric!

Сандық енгізуді қабылдау үшін int() пайдалану

input() функциясын пайдаланған кезде, Python пайдаланушы енгізген барлық нәрсені тіркес ретінде түсіндіреді. Пайдаланушының жасын сұрайтын келесі аудармашы/interpreter сеансын қарастырыңыз:


        >>> age = input("How old are you? ")
        How old are you? 21
        >>> age
        '21'

Пайдаланушы 21 санын енгізеді, бірақ біз Python-нан age мәнін сұрағанда, ол '21' қайтарады, енгізілген сандық мәннің тіркес көрінісі. Python енгізуді тіркес ретінде түсіндіргенін білеміз, себебі сан енді тырнақшаға алынған. Егер сіз тек кірісті басып шығарғыңыз келсе, бұл жақсы жұмыс істейді. Бірақ енгізуді сан ретінде пайдаланғыңыз келсе, қате пайда болады:


        >>> age = input("How old are you? ")
        How old are you? 21
         >>> age >= 18
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
         TypeError: '>=' not supported between instances of 'str' and 'int'

❶ Сандық салыстыру үшін енгізуді пайдаланған кезде, Python қате шығарады, себебі тіркесті бүтін санмен салыстыру мүмкін емес: age мәніне тағайындалған '21' тіркесін 18 сандық мәнімен салыстыруға болмайды ❷.

Бұл мәселені енгізу жолын сандық мәнге түрлендіретін int() функциясын пайдалану арқылы шеше аламыз. Бұл салыстыруды сәтті орындауға мүмкіндік береді:


        >>> age = input("How old are you? ")
        How old are you? 21
         >>> age = int(age)
        >>> age >= 18
        True

Бұл мысалда, сұрауға 21 енгізген кезде, Python санды тіркес ретінде түсіндіреді, бірақ мән содан кейін ❶ int() арқылы сандық көрініске түрлендіріледі. Енді Python шартты сынақты іске қоса алады: ол age мәні 18-ден үлкен немесе тең екенін көру үшін age (енді 21 сандық мәнді білдіреді) және 18-ді салыстырады. Бұл сынақ True деп бағаланады.

Нақты бағдарламада int() функциясын қалай пайдаланасыз? Адамдардың "американские горки" кіруге жеткілікті ұзын екенін анықтайтын бағдарламаны қарастырыңыз:

rollercoaster.py


        height = input("How tall are you, in inches? ")
        height = int(height)
        
        if height >= 48:
            print("\nYou're tall enough to ride!")
        else:
            print("\nYou'll be able to ride when you're a little older.")

Бағдарлама height параметрін 48-бен салыстыра алады, себебі height = int(height) салыстыру басталғанға дейін кіріс мәнін сандық көрініске түрлендіреді. Енгізілген сан 48-ден үлкен немесе оған тең болса, пайдаланушыға олардың бойы жеткілікті екенін айтамыз:


        How tall are you, in inches? 71
        
        You're tall enough to ride!

Есептер мен салыстырулар үшін сандық енгізуді пайдаланған кезде, алдымен кіріс мәнін сандық көрініске түрлендіруді ұмытпаңыз.

Модуло операторы

Сандық ақпаратпен жұмыс істеуге арналған пайдалы құрал модульдік оператор (%), ол бір санды екінші санға бөліп, қалғанын қайтарады:


        >>> 4 % 3
        1
        >>> 5 % 3
        2
        >>> 6 % 3
        0
        >>> 7 % 3
        1

Модуль операторы бір санның екіншісіне қанша рет сәйкес келетінін айтпайды; ол тек қалған қалдықтың не екенін айтады.

Бір сан басқа санға бөлінсе, қалдық 0 болады, сондықтан модуль операторы әрқашан 0 мәнін қайтарады. Бұл фактіні санның жұп немесе тақ екенін анықтау үшін пайдалануға болады:

even_or_odd.py


        number = input("Enter a number, and I'll tell you if it's even or odd: ")
        number = int(number)
        
        if number % 2 == 0:
            print(f"\nThe number {number} is even.")
        else:
            print(f"\nThe number {number} is odd.")

Жұп сандар әрқашан екіге бөлінеді, сондықтан егер сан мен екінің модулі нөлге тең болса (мұнда if number % 2 == 0 болса) сан жұп болады. Әйтпесе, бұл тақ.


        Enter a number, and I'll tell you if it's even or odd: 42
        
        The number 42 is even.

while циклдерін таныстыру

for циклі жинақталған мәндер тізімін алады және жинақтағы әрбір элемент үшін код блогын бір рет орындап шығады. Керісінше, while циклі белгілі бір шарт true болып тұрған сәтте жұмыс істеп тұрады.

while циклінің жұмысы

Сандар қатарын санау үшін while циклін пайдалануға болады. Мысалы, келесі while циклі 1-ден 5-ке дейін есептеледі:

counting.py


        current_number = 1
        while current_number <= 5:
            print(current_number)
            current_number += 1

Бірінші жолда біз current_number/ағымдық_сан мәнін 1 деп тағайындау арқылы 1-ден санауды бастаймыз. Содан кейін while циклі ағымдық_сан 5-тен кіші немесе оған тең мәні болғанша жұмыс істей беретін етіп орнатылады. Цикл ішіндегі код ағымдық_сан мәнін басып шығарады, содан кейін current_number += 1 арқылы сол мәнге 1 қосады. (+= операторы current_number = current_number + 1 сөзінің стенографиясы болып табылады.)

Python циклды current_number/ағымдық_сан <= 5 шарты дұрыс болғанша қайталайды. 1 саны 5-тен аз болғандықтан, Python 1 басып шығарады, содан кейін ағымдағы санды 2 етіп 1 қосады. 2 саны 5-тен аз болғандықтан, Python 2 басып шығарады және қайтадан 1 қосады, ағымдағы санды 3 етеді және т.с.с current_number мәні 5-тен үлкен болған сәтте цикл жұмысын тоқтатады және бағдарлама аяқталады:


        1
        2
        3
        4
        5

Күнделікті пайдаланатын бағдарламаларда while циклдары болуы мүмкін. Мысалы, ойын ойнауды тоқтатпай жалғастыра беру үшін ойынға while циклы қажет, ал сіз ойыннан шығуды сұраған кезде ол жұмысын тоқтата алады. Бағдарламалар біз тоқтатпай өздігінен жұмысын тоқтатса немесе біз шыққымыз келгенде жұмысын жалғастыра берсе, оларды пайдалану қызық болмас еді, сондықтан бағдарламамызды басқаруға мүмкіндік беретін while циклдері өте пайдалы.

Пайдаланушыға қашан шығу керектігін таңдауға рұқсат беру

Бағдарламаның көп бөлігін while циклінің ішінде жазу арқылы біз parrot.py бағдарламасы пайдаланушы қалағанша жұмыс істеп тұратын ете аламыз. Біз шығу мәнін анықтаймыз, содан кейін пайдаланушы шығу мәнін енгізбегенше бағдарламаның жұмысын жалғастырамыз:

parrot.py


        prompt = "\nTell me something, and I will repeat it back to you:"
        prompt += "\nEnter 'quit' to end the program. "
        
        message = ""
        while message != 'quit':
            message = input(prompt)
            print(message)

Алдымен пайдаланушыға екі опцияны айтатын prompt/шақыруды анықтаймыз: хабарды енгізу немесе шығу мәнін енгізу (бұл жағдайда 'quit'). Содан кейін пайдаланушы енгізген кез-келген мәнді бақылау үшін message айнымалы мәнін орнатамыз. Біз message-ді бос тіркес, "" ретінде анықтаймыз, сондықтан Python-да while жолына бірінші рет жеткенде тексеретін нәрсе бар. Бағдарлама бірінші рет іске қосылғанда және Python while операторына жеткенде, ол message мәнін 'quit' мәнімен салыстыруы керек, бірақ әзірге ешқандай пайдаланушы енгізуі жоқ. Егер Python-да салыстыруға ештеңе болмаса, ол бағдарламаны іске қосуды жалғастыра алмайды. Сондықтан осы мәселені шешу үшін message-ге бастапқы мән беруді қамтамасыз етеміз. Бұл жай ғана бос жол болса да, ол Python үшін мағыналы болады және оған while циклі жұмыс істейтін салыстыруды орындауға мүмкіндік береді. Бұл while циклі message мәні 'quit' болмағанша жұмыс істейді.

Ең басында message мәне бос тіркес болып табылады, Python циклге кіреді,бос тіркес quit-ке тең болмағандықтан, цикл ішіндегі код орындалып бастайды. message = input(prompt) параметрінде Python шақыруды көрсетеді және пайдаланушының input енгізуін күтеді. Пайдаланушы енгізгеннің бәрі message-ға тағайындалады және басып шығарылады; содан кейін Python шартты while операторындағы қайта бағалайды. Пайдаланушы 'quit' сөзін енгізбегенше, шақыру қайтадан көрсетіледі және Python қосымша енгізуді күтеді. Пайдаланушы ақырында 'quit' енгізгенде, Python while циклін орындауды тоқтатады және бағдарлама аяқталады:


        Tell me something, and I will repeat it back to you:
        Enter 'quit' to end the program. Hello everyone!
        Hello everyone!
        
        Tell me something, and I will repeat it back to you:
        Enter 'quit' to end the program. Hello again.
        Hello again.
        
        Tell me something, and I will repeat it back to you:
        Enter 'quit' to end the program. quit
        quit

Бұл бағдарлама жақсы жұмыс істейді, тек 'quit' сөзін ең соңында нақты хабар сияқты басып шығарады. Қарапайым if сынағы оны түзетеді:


        prompt = "\nTell me something, and I will repeat it back to you:"
        prompt += "\nEnter 'quit' to end the program. "
        
        message = ""
        while message != 'quit':
            message = input(prompt)
        
            if message != 'quit':
                print(message)

Енді бағдарлама хабарды көрсетпес бұрын жылдам тексереді және хабарды шығару мәніне сәйкес келмесе ғана басып шығарады:


        Tell me something, and I will repeat it back to you:
        Enter 'quit' to end the program. Hello everyone!
        Hello everyone!
        
        Tell me something, and I will repeat it back to you:
        Enter 'quit' to end the program. Hello again.
        Hello again.
        
        Tell me something, and I will repeat it back to you:
        Enter 'quit' to end the program. quit

Жалаушаны пайдалану / Using a Flag

Алдыңғы мысалда берілген шарт ақиқат болғанда бағдарлама белгілі бір тапсырмаларды орындайтын болды. Бірақ әртүрлі оқиғалар бағдарламаның жұмысын тоқтатуға себеп болатын күрделірек бағдарламалар туралы не деуге болады?

Мысалы, ойында бірнеше түрлі оқиғалар ойынды аяқтауы мүмкін. Ойыншының кемелері таусылғанда, олардың уақыты таусылғанда немесе олар қорғауы керек қалалардың барлығы жойылғанда, ойын аяқталуы керек. Осы оқиғалардың бірі орын алса, оны аяқтау керек. Бағдарламаны тоқтату үшін көптеген ықтимал оқиғалар орын алуы мүмкін болса, осы жағдайлардың барлығын бір уақытта while операторында сынап көру күрделенеді және қиын болады.

Көптеген шарттар дұрыс болған кезде ғана жұмыс істеп тұруы керек бағдарлама үшін бүкіл бағдарлама қосулы немесе қосулы емес екенін анықтайтын бір айнымалы мәнді анықтауға болады. Flag/жалау деп аталатын бұл айнымалы бағдарламаға сигнал ретінде әрекет етеді. Біз өз бағдарламаларымызды жалау True күйіне орнатылған кезде жұмыс істейтіндей етіп жаза аламыз және бірнеше оқиғалардың кез келгені жалаушаның мәнін False мәніне орнатқанда жұмысын тоқтатамыз. Нәтижесінде, біздің жалпы while амалы тек бір шартты тексеруі керек: жалаушаның қазіргі уақытта True екендігін тексеру керек. Содан кейін, барлық басқа сынақтарымыз (жалаушаны False күйіне орнату керек оқиғаның орын алған-алмағанын көру үшін) бағдарламаның қалған бөлігінде ұқыпты түрде ұйымдастырылуы мүмкін.

Алдыңғы бөлімдегі parrot.py кодына жалаушаны қосамыз. Біз active деп атайтын бұл жалауша (бірақ оны кез-келген нәрсе деп атауға болады) бағдарламаның жұмысын жалғастыру керек пе, жоқ па бақылайды:


        prompt = "\nTell me something, and I will repeat it back to you:"
        prompt += "\nEnter 'quit' to end the program. "
        
        active = True
         while active:
            message = input(prompt)
        
            if message == 'quit':
                active = False
            else:
                print(message)

Біз active айнымалы мәнін True мәніне орнаттық, осылайша бағдарлама белсенді күйде басталады. Мұны істеу while операторының өзін қарапайым етеді, себебі while операторының өзінде салыстыру жүргізілмейді; логика бағдарламаның басқа бөліктерінде қарастырылады. active айнымалы мәні True болып қалғанша, цикл ❶ жұмысын жалғастырады.

while циклінің ішіндегі if операторында пайдаланушы өз енгізуін енгізгеннен кейін message мәнін тексереміз. Егер пайдаланушы 'quit' енгізсе, active мәнін False мәніне орнатамыз және while циклі тоқтайды. Егер пайдаланушы 'quit'-тен басқа кез-келген нәрсені енгізсе, біз оның енгізуін хабар ретінде басып шығарамыз.

Бұл бағдарламада біз шартты сынақты тікелей while операторында орналастырған алдыңғы мысалмен бірдей нәтиже бар. Бірақ қазір бізде жалпы бағдарламаның белсенді күйде екенін көрсететін жалауша бар болғандықтан, active тудыруы тиіс оқиғаларға қосымша сынақтарды (мысалы, elif амалдары) қосу оңай болар еді таңдап, False болады. Бұл ойындар сияқты күрделі бағдарламаларда пайдалы, олардың әрқайсысында бағдарлама жұмысын тоқтататын көптеген оқиғалар болуы мүмкін. Осы оқиғалардың кез келгені белсенді жалаушаның False болуына себеп болған кезде, негізгі ойын циклы шығады, Ойын аяқталды хабары көрсетіледі және ойыншыға қайта ойнату үшін опция берілуі мүмкін.

Циклдан шығу үшін break пайдалану

Кез-келген шартты сынақтың нәтижелеріне қарамастан, циклде қалған кодты іске қоспай, while циклінен бірден шығу үшін break операторын пайдаланыңыз. break операторы бағдарламаңыздың ағынын басқарады; оны кодтың қай жолдары орындалатынын және қайсысы орындалмайтынын басқару үшін пайдалана аласыз, сондықтан бағдарлама тек сіз қалаған кодты қалаған кезде орындайды.

Мысалы, пайдаланушыдан барған жерлері туралы сұрайтын бағдарламаны қарастырыңыз. Бұл бағдарламадағы while циклін пайдаланушы 'quit' мәнін енгізген бойда break шақыру арқылы тоқтата аламыз:

cities.py


        prompt = "\nPlease enter the name of a city you have visited:"
        prompt += "\n(Enter 'quit' when you are finished.) "
        
         while True:
            city = input(prompt)
        
            if city == 'quit':
                break
            else:
                print(f"I'd love to go to {city.title()}!")

while True ❶ деп басталатын цикл break/үзіліске жетпесе, амал мәңгі орындалады. Бұл бағдарламадағы цикл пайдаланушыдан 'quit' енгізгенше болған қалалардың атын енгізуді сұрайды. Олар 'quit' енгізген кезде, break операторы іске қосылады, бұл Python-ның циклден шығуына себеп болады:


        Please enter the name of a city you have visited:
        (Enter 'quit' when you are finished.) New York
        I'd love to go to New York!
        
        Please enter the name of a city you have visited:
        (Enter 'quit' when you are finished.) San Francisco
        I'd love to go to San Francisco!
        
        Please enter the name of a city you have visited:
        (Enter 'quit' when you are finished.) quit

Циклде жалғастыруды пайдалану

Қалған кодты орындамай, циклден толығымен шығудың орнына, шартты тесттің нәтижесіне байланысты циклдің басына оралу үшін continue операторын пайдалануға болады. Мысалы, 1-ден 10-ға дейін есептелетін, бірақ сол ауқымдағы тақ сандарды ғана басып шығаратын циклды қарастырайық:

counting.py


        current_number = 0
        while current_number < 10:
             current_number += 1
            if current_number % 2 == 0:
                continue
        
            print(current_number)

Біріншіден, current_number мәнін 0-ге орнатамыз. Ол 10-нан аз болғандықтан, Python while цикліне кіреді. ❶ Циклдің ішіне кіргеннен кейін біз санауды 1-ге арттырамыз, сондықтан current_number 1 болады. Содан кейін if операторы current_number және 2 модулін тексереді. Егер модуль 0 болса (бұл current_number 2-ге бөлінетінін білдіреді), continue амалы Python-ға циклдің қалған бөлігін елемеу және басына оралу керектігін айтады. Ағымдағы сан 2-ге бөлінбесе, циклдің қалған бөлігі орындалады және Python ағымдағы нөмірді басып шығарады:


        1
        3
        5
        7
        9

Шексіз циклдардан аулақ болу

Әр while циклі шексіз айналып тұрып қалмас үшін оның тоқтау шарты болуы міндетті. Мысалы, бұл санау циклі 1-ден 5-ке дейін санау керек:

counting.py


        x = 1
        while x <= 5:
            print(x)
            x += 1

Алайда, x += 1 жолын байқаусызда жазбасаңыз не өткізіп алсаңыз, цикл мәңгі жұмыс істейді:

# This loop runs forever!
        x = 1
        while x <= 5:
            print(x)

Енді x мәні 1 мәнінен басталады, бірақ ешқашан өзгермейді. Нәтижесінде x <= 5 шартты сынағы әрқашан True мәніне баға береді және while циклі мәңгілік орындалады, бұл келесідей үздіксіз 1-лер сериясын басып шығарады:


        1
        1
        1
        1
        --snip/код үзіндісі--

Әрбір бағдарламашы кездейсоқ шексіз while циклін жазады, әсіресе бағдарламаның циклдерінде анық емес шығу шарттары болған кезде. Бағдарламаңыз шексіз циклде тұрып қалса, CTRL-C пернелер тіркесімін басыңыз немесе бағдарламаның шығысын көрсететін терминал терезесін жабыңыз.

Шексіз циклдар жазбау үшін әрбір while циклін сынап көріңіз және цикл күткенде тоқтайтынына көз жеткізіңіз. Пайдаланушы белгілі бір енгізу мәнін енгізген кезде бағдарламаңыздың аяқталуын қаласаңыз, бағдарламаны іске қосыңыз және сол мәнді енгізіңіз. Егер бағдарлама аяқталмаса, бағдарламаңыз циклден шығуға себеп болатын мәнді қалай өңдейтінін мұқият тексеріңіз. Бағдарламаның кем дегенде бір бөлігі цикл шартын False жасай алатынына немесе оны break операторына жеткізе алатынына көз жеткізіңіз.

Тізімдер мен сөздіктерде while циклды пайдалану

Осы уақытқа дейін біз бір уақытта пайдаланушы ақпаратының бір бөлігімен ғана жұмыс істедік. Біз пайдаланушының енгізуін алдық, содан кейін сол енгізілген мәнді немесе оған жауапты басып шығардық. Ал while циклінің келесі жолы айналымында біз басқа енгізу мәнін аламыз және оған жауап береміз. Бірақ пайдаланушылар көп болса және енгізілген ақпарат бөліктері де көп болады, оның бәрін қадағалап отыру үшін біз тізімдер мен сөздіктерді while циклімен пайдалануымыз керек.

for циклі тізімді айналып өту үшін тиімді, бірақ for циклі іске қосылып жүріп жатқанда тізімді өзгертпеу керек, себебі Python тізімдегі элементтерді бақылауда қиындықтарға тап болады. Тізімді айналып оны өңдеу барысында өзгертетін болсаңыз while циклін пайдаланыңыз. Тізімдер мен сөздіктермен while циклдарын пайдалану кейінірек тексеру және есеп беру үшін көптеген деректерді жинауға, сақтауға және ұйымдастыруға мүмкіндік береді.

Элементтерді бір тізімнен екіншісіне жылжыту

Веб-сайттың жаңадан тіркелген, бірақ расталмаған пайдаланушыларының тізімін қарастырыңыз. Бұл пайдаланушыларды тексергеннен кейін оларды расталған пайдаланушылардың бөлек тізіміне қалай жылжытып-қосуға болады? Бір жолы пайдаланушыларды расталмаған пайдаланушылар тізімінен шығарып алу үшін while циклін пайдалану болып табылады, өйткені біз оларды растаймыз, содан кейін оларды расталған пайдаланушылардың бөлек тізіміне қосамыз. Бұл код келесідей болуы мүмкін:

confirmed_users.py


        # Start with users that need to be verified,
        #  and an empty list to hold confirmed users.
         unconfirmed_users = ['alice', 'brian', 'candace']
        confirmed_users = []
        
        # Verify each user until there are no more unconfirmed users.
        #  Move each verified user into the list of confirmed users.
         while unconfirmed_users:
             current_user = unconfirmed_users.pop()
        
            print(f"Verifying user: {current_user.title()}")
             confirmed_users.append(current_user)
        
        # Display all confirmed users.
        print("\nThe following users have been confirmed:")
        for confirmed_user in confirmed_users:
            print(confirmed_user.title())

❶ Біз расталмаған пайдаланушылар тізімінен бастаймыз (Алис, Брайан және Кэндис) және расталған пайдаланушыларды ұстауға арналған бос тізім. while циклі unconfirmed_users тізімі бос емес ❷ болғанша жұмыс істейді. Бұл цикл ішінде pop() әдісі тексерілмеген пайдаланушыларды unconfirmed_users соңынан бір-бірден жояды. ❸. Candace unconfirmed_users тізімінде соңғы болғандықтан, оның аты бірінші болып жойылады, current_user-ға тағайындалады және confirmed_users тізіміне қосылады. ❹. Келесіде Брайан, одан кейін Алиса.

Растау хабарын басып шығару, содан кейін оларды расталған пайдаланушылар тізіміне қосу арқылы әр пайдаланушыны растауды модельдейміз. Расталмаған пайдаланушылар тізімі қысқарған сайын, расталған пайдаланушылар тізімі өседі. Расталмаған пайдаланушылар тізімі бос болғанда, цикл тоқтап, расталған пайдаланушылар тізімі басып шығарылады:


        Verifying user: Candace
        Verifying user: Brian
        Verifying user: Alice
        
        The following users have been confirmed:
        Candace
        Brian
        Alice

Тізімнен арнайы мәндердің барлық даналарын жою

3-тарауда біз тізімнен белгілі бір мәнді жою үшін remove() қолдандық. remove() функциясы жұмыс істеді, себебі бізді қызықтыратын мән тізімде тек бір рет пайда болды. Бірақ тізімнен мәннің барлық даналарын жойғыңыз келсе ше?

Сізде 'cat' мәні бірнеше рет қайталанатын үй жануарларының тізімі бар делік. Бұл мәннің барлық даналарын жою үшін мына жерде көрсетілгендей 'cat' тізімде енді жоқ болғанша while циклін іске қосуға болады:

pets.py


        pets = ['dog', 'cat', 'dog', 'goldfish', 'cat', 'rabbit', 'cat']
        print(pets)
        
        while 'cat' in pets:
            pets.remove('cat')
        
        print(pets)

Біз 'cat'-ның бірнеше данасын қамтитын тізімнен бастаймыз. Тізімді басып шығарғаннан кейін, Python while цикліне кіреді, себебі ол тізімнен кемінде бір рет 'cat' мәнін табады. Цикл ішіне кіргеннен кейін, Python 'cat' бірінші данасын жояды, while жолына оралады, содан кейін 'cat' дегенді тапқан кезде циклды қайта енгізеді. әлі де тізімде. Ол мән тізімде жойылғанша 'cat' әрбір данасын жояды, сол кезде Python циклден шығып, тізімді қайтадан басып шығарады:


        ['dog', 'cat', 'dog', 'goldfish', 'cat', 'rabbit', 'cat']
        ['dog', 'dog', 'goldfish', 'rabbit']

Пайдаланушы енгізуі арқылы сөздікті толтыру

Сіз while циклі арқылы әр өту кезінде қажет болғанша енгізуді сұрай аласыз. Әрбір цикл арқылы қатысушының аты мен жауабын сұрайтын сауалнама бағдарламасын жасайық. Жиналған деректерді сөздікте сақтаймыз, себебі әрбір жауапты белгілі бір пайдаланушымен байланыстырғымыз келеді:

mountain_poll.py


        responses = {}
        # Set a flag to indicate that polling is active.
        polling_active = True
        
        while polling_active:
            # Prompt for the person's name and response.
             name = input("\nWhat is your name? ")
            response = input("Which mountain would you like to climb someday? ")
        
            # Store the response in the dictionary.
             responses[name] = response
        
            # Find out if anyone else is going to take the poll.
             repeat = input("Would you like to let another person respond? (yes/ no) ")
            if repeat == 'no':
                polling_active = False
        
        # Polling is complete. Show the results.
        print("\n--- Poll Results ---")
         for name, response in responses.items():
            print(f"{name} would like to climb {response}.")

Бағдарлама алдымен бос сөздікті (жауаптар) анықтайды және сұраудың белсенді екенін көрсету үшін жалаушаны (polling_active) орнатады. polling_active True болғанша, Python кодты while циклінде іске қосады.

Цикл ішінде пайдаланушыдан өз атын және көтерілгісі келетін тауды ❶ енгізу сұралады. Бұл ақпарат жауаптар сөздігінде ❷ сақталады және пайдаланушыдан сауалнаманы жалғастыру немесе жалғастырмау сұралады ❸. Егер олар yes енгізсе, бағдарлама қайтадан while цикліне кіреді. Егер олар no енгізсе, polling_active жалауы False күйіне орнатылады, while циклі жұмысын тоқтатады және соңғы ❹ код блогы сауалнама нәтижелерін көрсетеді.

Егер сіз осы бағдарламаны іске қосып, үлгі жауаптарды енгізсеңіз, келесідей нәтижені көресіз:


        What is your name? Eric
        Which mountain would you like to climb someday? Denali
        Would you like to let another person respond? (yes/ no) yes
        
        What is your name? Lynn
        Which mountain would you like to climb someday? Devil's Thumb
        Would you like to let another person respond? (yes/ no) no
        
        --- Poll Results ---
        Eric would like to climb Denali.
        Lynn would like to climb Devil's Thumb.

Қорытынды

Бұл тарауда сіз пайдаланушыларға бағдарламаларыңызда өз ақпараттарын беруге мүмкіндік беру үшін input() пайдалану жолын үйрендіңіз. Сіз мәтінмен де, сандық енгізумен де жұмыс істеуді және бағдарламаларды пайдаланушылар қалағанша іске қосу үшін while циклдерін пайдалануды үйрендіңіз. Сіз active жалауын орнату, break операторын және continue амалы арқылы while циклінің ағынын басқарудың бірнеше жолдарын көрдіңіз. Элементтерді бір тізімнен екінші тізімге жылжыту үшін while циклін пайдалануды және тізімнен мәннің барлық даналарын жою жолын үйрендіңіз. Сондай-ақ while циклдерін сөздіктермен қалай пайдалануға болатынын білдіңіз.

8-тарауда функциялар туралы білетін боласыз. Функциялар бағдарламаларды әрқайсысы бір нақты тапсырманы орындайтын шағын бөліктерге бөлуге мүмкіндік береді. Функцияны қалағаныңызша шақыруға болады және функцияларды бөлек файлдарда сақтауға болады. Функцияларды пайдалану арқылы ақауларды жою және жөндеу оңайырақ және көптеген әртүрлі бағдарламаларда қайта пайдалануға болатын тиімдірек код жаза аласыз.

Функциялар

ITUniver

8
Функциялар

Бұл тарауда сіз белгілі бір жұмысты орындауға арналған код блоктары деп аталатын функцияларды жазуды үйренесіз. Функцияда анықталған белгілі бір тапсырманы орындағыңыз келгенде, оған жауапты функцияны шақырасыз. Бұл тапсырманы бағдарламаңызда бірнеше рет орындау қажет болса, бір тапсырманың барлық кодын қайта-қайта терудің қажеті жоқ; сіз жай ғана осы тапсырманы өңдеуге арналған функцияны шақырасыз және шақыру Python-ға функцияның ішіндегі кодты іске қосуды айтады. Функцияларды пайдалану бағдарламаларды жазуды, оқуды, тексеруді және түзетуді жеңілдететінін байқайсыз.

Бұл тарауда сонымен қатар ақпаратты функцияларға берудің әртүрлі тәсілдерін үйренесіз. Негізгі міндеті ақпаратты және деректерді өңдеуге және мәнді немесе мәндер жинағын қайтаруға арналған басқа функцияларды көрсету болып табылатын белгілі бір функцияларды қалай жазу керектігін үйренесіз. Соңында, негізгі бағдарлама файлдарын ұйымдастыруға көмектесу үшін функцияларды модульдер деп аталатын бөлек файлдарда сақтауды үйренесіз.

Функцияны анықтау

Міне, сәлемдесуді басып шығаратын greet_user() атты қарапайым функция:

greeter.py


        def greet_user():
            """Қарапайым сәлемдесуді көрсетіңіз."""
            print("Hello!")
        
        greet_user()

Бұл мысал функцияның ең қарапайым құрылымын көрсетеді. Бірінші жол Python-ға функцияны анықтайтыныңызды хабарлау үшін def кілт сөзін пайдаланады. Бұл функцияның анықтамасы, ол Python-ға функцияның атын және егер бар болса, функция өз жұмысын орындау үшін қандай ақпарат қажет екенін айтады. Жақша осы ақпаратты сақтайды. Бұл жағдайда функцияның атауы greet_user() болады және оның жұмысын орындау үшін ешқандай ақпарат қажет емес, сондықтан оның жақшалары бос (солай болса да, жақша қажет). Соңында анықтама қос нүктемен аяқталады.

def greet_user():-ден кейін келетін кез-келген шегініс жолдар функцияның body/денесін құрайды. Екінші жолдағы мәтін функцияның не істейтінін сипаттайтын docstring деп аталатын түсініктеме болып табылады. Python бағдарламаларыңыздағы функциялар үшін құжаттаманы жасағанда, ол функция анықтамасынан кейін бірден жолды іздейді. Бұл жолдар әдетте үш тырнақшаға алынады, бұл бірнеше жол түсініктемені жазуға мүмкіндік береді.

print("Hello!") жолы - бұл функцияның негізгі денесіндегі/ішіндегі нақты кодтың жалғыз жолы, сондықтан greet_user() бір ғана тапсырмаға ие: print("Hello!").

Бұл функцияны пайдаланғыңыз келсе, оны шақыруыңыз керек. Функцияны шақыру Python-ға функциядағы кодты орындауды айтады. Функцияны шақыру үшін функцияның атын, содан кейін жақшаға кез-келген қажетті ақпаратты жазасыз. Мұнда ешқандай ақпарат қажет емес болғандықтан, функциямызды шақыру greet_user() енгізу сияқты қарапайым. Күтілгендей, ол Hello!: басып шығарады


        Hello!

Функцияға ақпаратты жіберу

Егер greet_user() функциясын сәл өзгертсеңіз, ол пайдаланушыны атымен қарсы алады. Функция мұны істеу үшін def greet_user() функция анықтамасының жақшасына username енгізіңіз. Мұнда username қосу арқылы функцияға сіз көрсеткен кез-келген username мәнін қабылдауға рұқсат бересіз. Функция енді сіз оны шақырған сайын username мәнін беруіңізді күтеді. greet_user() қызметін шақырғанда, оған жақшаның ішіне 'jesse' сияқты есімді беруге болады:


        def greet_user(username):
            """Қарапайым сәлемдесуді көрсетіңіз."""
            print(f"Hello, {username.title()}!")
        
        greet_user('jesse')

greet_user('jesse') енгізу greet_user() шақырады және функцияға print() шақыруын орындау үшін қажетті ақпаратты береді . Функция сіз берген атауды қабылдайды және сол ат үшін сәлемдесуді көрсетеді:


        Hello, Jesse!

Сол сияқты, greet_user('sarah') енгізу greet_user() функциясын шақырады, оған ақпарат ретінде 'sarah' мәнін береді және Hello, Sarah! деп басып шығарады. Сіз greet_user()-ге қалағаныңызша жиі қоңырау шалып, кез-келген есімді ақпарат ретінде берсеңіз болады.

Аргументтер мен параметрлер

Алдыңғы greet_user() функциясында біз greet_user() username айнымалысы үшін мән талап ететіндей етіп анықтадық. Функцияны шақырып, оған ақпаратты (адамның аты-жөнін) бергеннен кейін, ол дұрыс сәлемдесуді басып шығарды.

greet_user() функция анықтамасындағы username айнымалысы параметр деп аталады, параметр функция өзінің жұмысын орындау үшін қажетті ақпарат бөлігі болып табылады. Ал greet_user('jesse') ішіндегі 'jesse' мәні аргумент деп аталады. Argument/аргумент - бұл функция шақыруы орындалатын сәтте функцияға берілетін ақпарат бөлігі. Функцияны шақырған кезде, функция жұмыс істейтін мәнді жақшаның ішіне жазамыз. Бұл жағдайда 'jesse' аргументі greet_user() функциясына беріледі және мән username параметріне тағайындалды.

Аргументтерді беру

Функция анықтамасында бірнеше параметр болуы мүмкін болғандықтан, функция шақыруына бірнеше аргумент қажет болуы мүмкін. Аргументтерді функцияларыңызға бірнеше жолмен беруге болады. Параметрлер жазылған ретпен болуы қажет позициялық аргументтерді пайдалануға болады; кілт сөз аргументтері, мұнда әрбір аргумент айнымалы аты мен мәннен тұрады; мәндердің тізімдері мен сөздіктері. Осылардың әрқайсысын рет-ретімен қарастырайық.

Позициялық аргументтер

Функцияны шақырған кезде, Python функция шақыруындағы әрбір аргументті функция анықтамасындағы параметрмен сәйкестендіруі керек. Мұны істеудің ең қарапайым жолы берілген аргументтердің ретіне негізделген. Осылай сәйкес келетін мәндер позициялық аргументтер деп аталады.

Бұл қалай жұмыс істейтінін көру үшін үй жануарлары туралы ақпаратты көрсететін функцияны қарастырыңыз. Функция бізге әрбір үй жануарының қандай жануар екенін және мұнда көрсетілгендей үй жануарының атын айтады:

pets.py


         def describe_pet(animal_type, pet_name):
            """Үй жануарлары туралы ақпаратты көрсету."""
            print(f"\nI have a {animal_type}.")
            print(f"My {animal_type}'s name is {pet_name.title()}.")
        
         describe_pet('cat', 'harry')

Анықтама бұл функцияға ❶ жануардың түрін және жануардың атауын қажет ететінін көрсетеді. describe_pet() функциясын шақырған кезде, жануар түрін және атауын осы ретпен беруіміз керек. Мысалы, функция шақыруында 'cat' аргументі animal_type параметріне және 'harry' аргументі pet_name параметріне тағайындалады ❷. Функция денесінде бұл екі параметр сипатталатын үй жануары туралы ақпаратты көрсету үшін пайдаланылады.

Шығыс Гарри атты мысықты сипаттайды:


        I have a cat.
        My cat's name is Harry.
Функцияны бірнеше рет шақыру

Функцияны қанша қажет болса, сонша рет шақыруға болады. Екінші, басқа үй жануарын сипаттау үшін describe_pet() функциясын тағы бір рет шақыру қажет:


        def describe_pet(animal_type, pet_name):
            """Үй жануарлары туралы ақпаратты көрсету."""
            print(f"\nI have a {animal_type}.")
            print(f"My {animal_type}'s name is {pet_name.title()}.")
        
        describe_pet('cat', 'harry')
        describe_pet('dog', 'willie')

Осы екінші функция шақыруында біз describe_pet() аргументтерін 'dog' және 'willie' арқылы береміз. Біз пайдаланған аргументтердің алдыңғы жинағы сияқты, Python бағдарламасы animal_type параметрімен 'dog'-ты және pet_name параметрімен 'willie'-ді сәйкес келтіреді. Бұрынғыдай, функция өз жұмысын орындайды, бірақ бұл жолы ол Вилли есімді ит үшін мәндерді басып шығарады. Қазір бізде Гарри атты мысық пен Вилли атты ит бар:


        I have a cat.
        My cat's name is Harry.
        
        I have a dog.
        My dog's name is Willie.

Функцияны бірнеше рет шақыру - өте тиімді жұмыс әдісі. Үй жануарларын сипаттайтын код функцияда бір рет жазылады. Содан кейін, кез-келген уақытта жаңа үй жануарын сипаттағыңыз келсе, сіз жаңа үй жануары туралы ақпаратпен функцияны шақырасыз. Үй жануарларын сипаттайтын код 10-20 жолға дейін кеңейтілсе де, функцияны қайта шақыру арқылы жаңа үй жануарын бір жолда ғана сипаттай аласыз.

Позициялық аргументтердегі реттілік мәселелері

Позициялық аргументтерді пайдаланған кезде функция шақыруындағы аргументтердің ретін араластырсаңыз, күтпеген нәтижелерді алуыңыз мүмкін:


        def describe_pet(animal_type, pet_name):
            """Үй жануарлары туралы ақпаратты көрсету."""
            print(f"\nI have a {animal_type}.")
            print(f"My {animal_type}'s name is {pet_name.title()}.")
        
        describe_pet('harry', 'cat')

Бұл функция шақыруында біз алдымен жануардың атын, екіншіден, жануардың түрін тізімдейміз. 'harry' аргументі осы жолы бірінші тізімде берілгендіктен, бұл мән animal_type параметріне тағайындалады. Сол сияқты, 'cat' pet_name-ға тағайындалады. Қазір бізде «Мысық» атты «гарри» бар:


        I have a harry.
        My harry's name is cat.

Осындай күлкілі нәтижелер алсаңыз, функция шақыруындағы аргументтердің реті функция анықтамасындағы параметрлердің ретіне сәйкес келетініне көз жеткізіңіз.

Кілтсөз аргументтері

Кілт сөз аргументі - функцияға берілетін атау-мән жұбы. Сіз аргументтегі атау мен мәнді тікелей байланыстырасыз, сондықтан аргументті функцияға бергенде, шатасу болмайды (соңында қате нәтиже: Мысық атты гарри болмайды). Кілтсөз аргументтері функция шақыруындағы аргументтерді дұрыс ретке келтіру туралы уайымдаудан босатады және олар функция шақыруындағы әрбір мәннің рөлін түсіндіреді.

describe_pet() шақыру үшін кілтсөз аргументтерін пайдаланып pets.py файлын қайта жазайық:


        def describe_pet(animal_type, pet_name):
            """Үй жануарлары туралы ақпаратты көрсету."""
            print(f"\nI have a {animal_type}.")
            print(f"My {animal_type}'s name is {pet_name.title()}.")
        
        describe_pet(animal_type='cat', pet_name='harry')

describe_pet() функциясы өзгерген жоқ. Бірақ біз функцияны шақырған кезде, біз Python-ға әрбір аргумент қай параметрмен сәйкес келуі керек екенін нақты айтамыз. Python функция шақыруын оқығанда, ол 'cat' аргументін animal_type параметріне және 'harry' аргументін animal_name-ге тағайындауды біледі. Шығару бізде Гарри атты мысық бар екенін дұрыс көрсетеді.

Кілтсөз аргументтерінің реті маңызды емес, өйткені Python әрбір мәннің қайда кетуі керектігін біледі. Келесі екі функция шақырулары баламалы:


        describe_pet(animal_type='cat', pet_name='harry')
        describe_pet(pet_name='harry', animal_type='cat')

Әдепкі мәндер

Функцияны жазу кезінде әрбір параметр үшін әдепкі мәнді/default value анықтауға болады. Функция шақыруында параметр үшін аргумент берілсе, Python аргумент мәнін пайдаланады. Олай болмаса, ол параметрдің әдепкі мәнін пайдаланады. Сонымен, параметр үшін әдепкі мәнді анықтаған кезде, әдетте функция шақыруында жазатын сәйкес аргументті бермей тастап кетсеңіз болады. Әдепкі мәндерді пайдалану функция шақыруларын жеңілдетеді және функцияларды әдетте пайдалану жолдарын нақтылайды.

Мысалы, describe_pet() қызметіне шақырулардың көпшілігі иттерді сипаттау үшін пайдаланылатынын байқасаңыз, animal_type әдепкі мәнін 'dog' етіп орнатуға болады. Енді ит үшін describe_pet() функциясын шақыратын кез-келген қолданушы бұл ақпаратты өткізіп жіберуі мүмкін:


        def describe_pet(pet_name, animal_type='dog'):
            """Үй жануарлары туралы ақпаратты көрсету."""
            print(f"\nI have a {animal_type}.")
            print(f"My {animal_type}'s name is {pet_name.title()}.")
        
        describe_pet(pet_name='willie')

Біз describe_pet() анықтамасын animal_type үшін 'dog' әдепкі мәнді қосу үшін өзгерттік. Енді функция animal_type көрсетілмей шақырылғанда, Python осы параметр үшін 'dog' мәнін пайдалануды біледі:


        I have a dog.
        My dog's name is Willie.

Функция анықтамасындағы параметрлердің жазылу ретін өзгерту керек екендігіне назар аударыңыз. Әдепкі мән жануар түрін аргумент ретінде көрсетуді қажет етпейтіндіктен, функция шақыруында қалған жалғыз аргумент үй жануарының аты болып табылады. Python мұны әлі де позициялық аргумент ретінде түсіндіреді, сондықтан функция тек жануардың атымен шақырылса, бұл аргумент функция анықтамасында тізімделген бірінші параметрге сәйкес келеді. Сондықтан бірінші параметр pet_name болуы керек.

Бұл функцияны қазір пайдаланудың ең қарапайым жолы - функция шақыруында тек иттің атын беру:


        describe_pet('willie')

Бұл функция шақыруы алдыңғы мысалдағыдай нәтижеге ие болады. Берілген жалғыз аргумент - 'willie', сондықтан ол анықтамадағы бірінші параметрмен, pet_name сәйкес келеді. animal_type үшін ешқандай аргумент берілмегендіктен, Python әдепкі 'dog' мәнін пайдаланады.

Иттен басқа жануарды сипаттау үшін келесідей функция шақыруын қолдануға болады:


        describe_pet(pet_name='harry', animal_type='cat')

animal_type үшін айқын аргумент берілгендіктен, Python параметрдің әдепкі мәнін елемейді.

Балама функция шақырулары

Позициялық аргументтер, кілт сөз аргументтері және әдепкі мәндердің барлығы бірге пайдаланылуы мүмкін болғандықтан, функцияны шақырудың бірнеше баламалы тәсілдері жиі болады. Бір әдепкі мән берілген describe_pet() үшін келесі анықтаманы қарастырыңыз:


        def describe_pet(pet_name, animal_type='dog'):

Осы анықтамамен pet_name үшін аргумент әрқашан берілуі керек және бұл мән позициялық немесе кілт сөз пішімін пайдалану арқылы қамтамасыз етілуі мүмкін. Сипатталған жануар ит болмаса, шақыруға animal_type аргументі қосылуы керек және бұл аргументті позициялық немесе кілт сөз пішімін пайдалану арқылы да көрсетуге болады.

Келесі шақырулардың барлығы осы функция үшін жұмыс істейді:


        # A dog named Willie.
        describe_pet('willie')
        describe_pet(pet_name='willie')
        
        # A cat named Harry.
        describe_pet('harry', 'cat')
        describe_pet(pet_name='harry', animal_type='cat')
        describe_pet(animal_type='cat', pet_name='harry')

Бұл функция шақыруларының әрқайсысы алдыңғы мысалдармен бірдей нәтижеге ие болады.

Қандай шақыру стилін пайдаланатыныңыз маңызды емес. Функция шақырулары қалаған нәтижені бергенше, түсінуге оңай мәнерді пайдаланыңыз.

Аргумент қателерін болдырмау

Функцияларды пайдалана бастағанда, сәйкес келмейтін аргументтер туралы қателерге тап болсаңыз, таң қалмаңыз. Сәйкес келмейтін аргументтер функция өз жұмысын орындауға қажет аргументтерден аз немесе көбірек берген кезде пайда болады. Мысалы, describe_pet() параметрін аргументсіз шақыруға тырыссақ, не болады:


        def describe_pet(animal_type, pet_name):
            """Үй жануарлары туралы ақпаратты көрсету."""
            print(f"\nI have a {animal_type}.")
            print(f"My {animal_type}'s name is {pet_name.title()}.")
        
        describe_pet()

Python функция шақыруында кейбір ақпараттың жоқ екенін мойындайды және кері бақылау бізге мынаны айтады:


        Traceback (most recent call last):
           File "pets.py", line 6, in <module>
             describe_pet()
            ^^^^^^^^^^^^^^
         TypeError: describe_pet() missing 2 required positional arguments: 
            'animal_type' and 'pet_name'

Бақылау бізге алдымен мәселенің орнын ❶ көрсетеді, бұл артқа қарап, функция шақыруында бірдеңе дұрыс емес екенін көруге мүмкіндік береді. Одан кейін ❷ көрсететіні қате туындатқан функция шақыру атауы. Соңғысы ❸, кері бақылау қоңырауда екі аргумент жоқ екенін айтады және жетіспейтін аргументтердің атауларын хабарлайды. Бұл функция бөлек файлда болса, сол файлды ашып, функция кодын оқымай-ақ, шақыруды дұрыс қайта жазуымыз мүмкін.

Python біз үшін функцияның кодын оқып, бізге қамтамасыз ету керек аргументтердің атын айтып беретіні үшін пайдалы. Бұл айнымалыларыңыз бен функцияларыңызға түсінікті-сипаттамалық атаулар беруге тағы бір мотивация. Егер солай етсеңіз, Python қате туралы хабарлары сізге және кодыңызды қолдануы мүмкін кез-келген басқа адамға пайдалырақ болады.

Тым көп аргументтер келтірсеңіз, функцияны шақыруды функция анықтамасына дұрыс сәйкестендіруге көмектесетін ұқсас бақылауды алуыңыз керек.

Return Values

Функция әрқашан өз шығысын тікелей көрсетуі міндетті емес. Оның орнына ол кейбір деректерді өңдей алады, содан кейін мәнді немесе мәндер жинағын қайтарады. Функция қайтаратын мән қайтару мәні/return value деп аталады. return операторы функцияның ішінен мән алады және оны функцияны шақырған жолға қайта жібереді. Қайтару мәндері бағдарламаның негізгі жұмысының көп бөлігін функцияларға жылжытуға мүмкіндік береді, бұл бағдарламаның ішкі/body бөлігін жеңілдетеді.

Қарапайым мәнді қайтару

Аты мен тегін қабылдайтын және дұрыс пішімделген толық атын қайтаратын функцияны қарастырайық:

formatted_name.py


        def get_formatted_name(first_name, last_name):
            """Ұқыпты пішімделген толық атауды қайтарыңыз."""
             full_name = f"{first_name} {last_name}"
             return full_name.title()
        
         musician = get_formatted_name('jimi', 'hendrix')
        print(musician)

get_formatted_name() анықтамасы параметр ретінде аты мен фамилиясын қабылдайды. Функция осы екі атауды біріктіреді, олардың арасына бос орын қосады және нәтижені full_name ❶ мәніне тағайындайды. full_name мәні бас әріппен жазылып түрлендіріледі, содан кейін ❷ шақыру жолына қайтарылады.

Мән қайтаратын функцияны шақырған кезде, қайтарылған мән тағайындалатын айнымалыны жазуыңыз керек. Бұл жағдайда ❸ қайтарылған мән musician айнымалы мәніне тағайындалады. Шығару адам атының бөліктерінен тұратын ұқыпты пішімделген толық аты-жөнін көрсетеді:


        Jimi Hendrix

Мұны өзіміз бірден жай ғана жаза алатын болсақ, ұқыпты пішімделген аты-жөнді алу үшін бұл көп жұмыс сияқты көрінуі мүмкін:


        print("Jimi Hendrix")

Алайда көптеген аттар мен фамилияларды бөлек сақтауды қажет ететін үлкен бағдарламамен жұмыс істеуді қарастырған кезде, get_formatted_name() сияқты функциялар өте пайдалы болады. Аты мен фамилиясын бөлек сақтайсыз, содан кейін толық атын көрсеткіңіз келсе, осы функцияны шақырасыз.

Міндетті емес Аргумент жасау

Кейбір жағдайда аргумент беруді міндетті емес етіп код жазу пайдалы, бұл функцияны қолданатын адамдар өздері қаласа ғана қосымша ақпаратты беруді таңдауға мүмкіндік жасайды. Аргументті қосымша-міндетті емес ету үшін әдепкі мәндерді пайдалануға болады.

Мысалы, әкесінің атын өңдеу үшін get_formatted_name() кодын кеңейткіміз келеді делік. Әке атын қосудың бірінші әрекеті келесідей болуы мүмкін:


        def get_formatted_name(first_name, middle_name, last_name):
            """Ұқыпты пішімделген толық атауды қайтарыңыз."""
            full_name = f"{first_name} {middle_name} {last_name}"
            return full_name.title()
        
        musician = get_formatted_name('john', 'lee', 'hooker')
        print(musician)

Бұл функция аты, әкесінің аты және тегі берілгенде жұмыс істейді. Функция аттың барлық үш бөлігін қабылдайды, содан кейін олардан тіркесті құрады. Функция қажет жерде бос орындар қосады және толық аты-жөнін бас әріппен түрлендіреді:


        John Lee Hooker

Бірақ әкесінің аттары әрқашан қажет бола бермейді және егер сіз оны тек аты мен тегімен атағыңыз келсе, бұл функция жазылғандай жұмыс істемейді. Әкесінің атын қосымша-міндетті емес ету үшін middle_name аргументіне бос әдепкі мән бере аламыз және пайдаланушы мән бермесе, аргументті елемеуіміз керек. get_formatted_name() әкесінің аты жазылмағанда жұмыс істеуі үшін middle_name әдепкі мәнін бос жолға орнатып, оны параметрлер тізімінің соңына жылжытамыз:


        def get_formatted_name(first_name, last_name, middle_name=''):
            """Ұқыпты пішімделген толық атауды қайтарыңыз."""
             if middle_name:
                full_name = f"{first_name} {middle_name} {last_name}"
             else:
                full_name = f"{first_name} {last_name}"
            return full_name.title()
        
        musician = get_formatted_name('jimi', 'hendrix')
        print(musician)
        
         musician = get_formatted_name('john', 'hooker', 'lee')
        print(musician)

Бұл мысалда аты-жөні үш мүмкін бөліктен құрастырылған. Әрқашан аты мен тегі болатындықтан, бұл параметрлер функция анықтамасында бірінші болып тізімделеді. Әкесінің аты міндетті емес, сондықтан ол анықтамада соңғы тізімде көрсетіледі және оның әдепкі мәні бос тіркес болып табылады.

Функцияның негізгі бөлігінде біз әкесінің атының берілгенін тексереміз. ❶ Python бос емес тіркестерді True деп түсіндіреді, сондықтан if middle_name шартты сынағының мәнін True деп бағалайды. Егер әкесінің аты берілсе, аты, әкесінің аты және тегі біріктіріліп, толық есім жасалады. Содан кейін бұл толық аты-жөні бас әріппен жазылып өзгертіліп, функцияны шақыру жолына қайтарылады, мұнда ол musician айнымалысына тағайындалады және басып шығарылады. ❷ Егер әкесінің аты берілмесе, бос тіркес if сынағынан өтпейді және else блогы іске қосылады. Толық аты-жөні тек аты мен тегі арқылы жасалады және пішімделген атау musician-ға тағайындалған және басып шығарылатын шақыру жолына қайтарылады.

Бұл функцияны аты-жөні арқылы шақыру оңай. Егер біз әкесінің атын пайдаланатын болсақ, Python позициялық аргументтерді дұрыс сәйкестендіру үшін ❸ әкесінің аты соңғы берілген дәлел екеніне көз жеткізуіміз керек.

Функциямыздың бұл өзгертілген нұсқасы тек аты мен тегі бар адамдар үшін жұмыс істейді және ол әкесінің аты бар адамдар үшін де жұмыс істейді:


        Jimi Hendrix
        John Lee Hooker

Қосымша мәндер функцияларға пайдалану жағдайларының кең ауқымын өңдеуге мүмкіндік береді, сонымен бірге функция шақырулары мүмкіндігінше қарапайым болып қалады.

Сөздікті қайтару

Функция сізге қажет мәннің кез-келген түрін, соның ішінде тізімдер мен сөздіктер сияқты күрделірек деректер құрылымдарын қайтара алады. Мысалы, келесі функция аты-жөн бөліктерін алып, адамды сипаттайтын сөздікті қайтарады:

person.py


        def build_person(first_name, last_name):
            """Адам туралы ақпарат сөздігін қайтару."""
             person = {'first': first_name, 'last': last_name}
             return person
        
        musician = build_person('jimi', 'hendrix')
         print(musician)

build_person() функциясы аты мен тегін алады және бұл мәндерді ❶ person сөздігіне енгізеді. Бұл жерде first_name мәні 'first' кілтімен, ал last_name мәні 'last' кілтімен сақталады. Содан кейін тұлғаны білдіретін бүкіл сөздік ❷ қайтарылады. Қайтару мәні сөздікте сақталған бастапқы екі мәтіндік ақпаратпен бірге басылады ❸:


        {'first': 'jimi', 'last': 'hendrix'}

Бұл функция қарапайым мәтіндік ақпаратты қабылдайды және оны басып шығарудан басқа ақпаратпен жұмыс істеуге мүмкіндік беретін мағыналы деректер құрылымына қосады. 'jimi' және 'hendrix' тіркестері енді аты және тегі ретінде белгіленеді. Бұл функцияны әкесінің аты, жасы, кәсібі немесе адам туралы сақтағыңыз келетін кез-келген басқа ақпарат сияқты қосымша мәндерді қабылдау үшін оңай кеңейтуге болады. Мысалы, келесі өзгеріс адамның жасын да сақтауға мүмкіндік береді:


        def build_person(first_name, last_name, age=None):
            """Адам туралы ақпарат сөздігін қайтару."""
            person = {'first': first_name, 'last': last_name}
            if age:
                person['age'] = age
            return person
        
        musician = build_person('jimi', 'hendrix', age=27)
        print(musician)

Функция анықтамасына жаңа қосымша age параметрін қосамыз және параметрге None арнайы мәнін тағайындаймыз, ол айнымалыға оған арнайы мән тағайындалмаған кезде пайдаланылады. None мәні туралы орын толтырғыш (placeholder) ретінде ойлауға болады. Шартты сынақтарда None False мәніне бағаланады. Егер функция шақыруында age мәні болса, бұл мән сөздікте сақталады. Бұл функция әрқашан адамның атын сақтайды, бірақ оны адам туралы қажет кез-келген басқа ақпаратты сақтау үшін өзгертуге болады.

Функцияны while циклімен пайдалану

Сіз осы уақытқа дейін білген барлық Python құрылымдарымен функцияларды пайдалана аласыз. Мысалы, пайдаланушылармен ресми түрде сәлемдесу үшін get_formatted_name() функциясын while циклімен қолданайық. Адамдардың аты-жөні бойынша сәлемдесудің алғашқы әрекеті:

greeter.py


        def get_formatted_name(first_name, last_name):
            """Ұқыпты пішімделген толық атауды қайтарыңыз."""
            full_name = f"{first_name} {last_name}"
            return full_name.title()
        
        # This is an infinite loop!
        while True:
             print("\nPlease tell me your name:")
            f_name = input("First name: ")
            l_name = input("Last name: ")
        
            formatted_name = get_formatted_name(f_name, l_name)
            print(f"\nHello, {formatted_name}!")

Бұл мысал үшін біз әкесінің атын қамтымайтын get_formatted_name() қарапайым нұсқасын қолданамыз. while циклі пайдаланушыдан өз атын енгізуді сұрайды, біз оның аты мен тегін бөлек ❶ сұраймыз.

Бірақ бұл while циклында бір мәселе бар: біз шығу шартын анықтаған жоқпыз. Енгізулер қатарын сұрағанда шығу шартын қайда қоясыз? Біз пайдаланушының мүмкіндігінше оңай шығуын қалаймыз, сондықтан әрбір шақыру шығудың жолын ұсынуы керек. break операторы кез-келген сұрауда циклден шығудың қарапайым жолын ұсынады:


        def get_formatted_name(first_name, last_name):
            """Ұқыпты пішімделген толық атауды қайтарыңыз."""
            full_name = f"{first_name} {last_name}"
            return full_name.title()
        
        while True:
            print("\nPlease tell me your name:")
            print("(enter 'q' at any time to quit)")
        
            f_name = input("First name: ")
            if f_name == 'q':
                break
        
            l_name = input("Last name: ")
            if l_name == 'q':
                break
        
            formatted_name = get_formatted_name(f_name, l_name)
            print(f"\nHello, {formatted_name}!")

Біз пайдаланушыға шығу жолын хабарлайтын хабарды қосамыз, содан кейін пайдаланушы шығу мәнін кез-келген сұрауда енгізсе, циклден шығамыз. Енді біреу кез-келген атқа q енгізгенше бағдарлама адамдармен амандасуды жалғастырады:


        Please tell me your name:
        (enter 'q' at any time to quit)
        First name: eric
        Last name: matthes
        
        Hello, Eric Matthes!
        
        Please tell me your name:
        (enter 'q' at any time to quit)
        First name: q

Тізімді аргумент ретінде беру

Атаулар, сандар немесе сөздіктер сияқты күрделірек нысандар тізімі болса да, тізімді функцияға беру жиі пайдалы болады. Тізімді функцияға бергенде, функция тізімнің элементтеріне тікелей қатынаса алады. Тізімдермен жұмысты тиімді ету үшін функцияларды қолданайық.

Бізде пайдаланушылардың тізімі бар және олардың әрқайсысына сәлемдемені басып шығарғымыз келеді делік. Келесі мысал тізімдегі әрбір адаммен жеке сәлемдесетін greet_users() деп аталатын функцияға есімдер тізімін жібереді:

greet_users.py


        def greet_users(names):
            """Тізімдегі әрбір пайдаланушыға қарапайым сәлемдесуді басып шығарыңыз."""
            for name in names:
                msg = f"Hello, {name.title()}!"
                print(msg)
        
        usernames = ['hannah', 'ty', 'margot']
        greet_users(usernames)

Біз greet_users() анықтаймыз, сондықтан ол names параметріне тағайындайтын есімдер тізімін күтеді. Функция қабылдайтын тізімді айналдырады және әрбір пайдаланушыға сәлемдесуді басып шығарады. Функцияның сыртында біз usernames пайдаланушылар тізімін анықтаймыз, содан кейін usernames тізімін greet_users() функция шақыруына береміз:


        Hello, Hannah!
        Hello, Ty!
        Hello, Margot!

Бұл біз қалаған нәтиже. Әрбір пайдаланушы жекелендірілген сәлемдесуді көреді және пайдаланушылардың белгілі бір тобымен сәлемдесу үшін функцияны кез-келген уақытта шақыруға болады.

Функциядағы тізімді өзгерту

Тізімді функцияға бергенде, функция тізімді өзгерте алады. Функция ішіндегі тізімге енгізілген кез-келген өзгерістер тұрақты болып табылады, бұл үлкен көлемдегі деректермен жұмыс істегенде де тиімді жұмыс істеуге мүмкіндік береді.

Пайдаланушылар ұсынатын дизайнның 3D басып шығарылған үлгілерін жасайтын компанияны қарастырайық. Басып шығару қажет дизайндар тізімде сақталады және басып шығарылғаннан кейін олар бөлек тізімге жылжытылады. Келесі код мұны функцияларды қолданбай жасайды:

printing_models.py


        # Start with some designs that need to be printed.
        unprinted_designs = ['phone case', 'robot pendant', 'dodecahedron']
        completed_models = []
        
        # Simulate printing each design, until none are left.
        #  Move each design to completed_models after printing.
        while unprinted_designs:
            current_design = unprinted_designs.pop()
            print(f"Printing model: {current_design}")
            completed_models.append(current_design)
        
        # Display all completed models.
        print("\nThe following models have been printed:")
        for completed_model in completed_models:
            print(completed_model)

Бұл бағдарлама басып шығаруды қажет ететін дизайн тізімінен және әрбір дизайн басып шығарылғаннан кейін жылжытылатын completed_models деп аталатын бос тізімнен басталады. unprinted_designs ішінде дизайндар бар болып тұрғанда, while циклі әр дизайнды басып шығарады, одан бұрын тізімнің соңынан дизайнды алып тастайды (pop() әдісімен), дизайнды current_design ішінде сақтайды (append()) және ағымдағы дизайн басып шығарылып жатқаны туралы хабарды көрсетеді. Содан кейін ол дизайнды аяқталған үлгілер тізіміне қосады. Цикл жұмыс істеп болған кезде, басып шығарылған дизайн тізімі көрсетіледі:


        Printing model: dodecahedron
        Printing model: robot pendant
        Printing model: phone case
        
        The following models have been printed:
        dodecahedron
        robot pendant
        phone case

Біз бұл кодты екі функция жазу арқылы қайта ұйымдастыра аламыз, олардың әрқайсысы бір нақты тапсырманы орындайды. Кодтың көпшілігі өзгермейді; біз оны тек мұқият қайта құрылымдаймыз. Бірінші функция дизайнды басып шығарумен айналысады, ал екіншісі жасалған басып шығаруды қорытындылайды:


         def print_models(unprinted_designs, completed_models):
            """
            Simulate printing each design, until none are left.
            Move each design to completed_models after printing.
            """
            while unprinted_designs:
                current_design = unprinted_designs.pop()
                print(f"Printing model: {current_design}")
                completed_models.append(current_design)
        
         def show_completed_models(completed_models):
            """Басып шығарылған барлық үлгілерді көрсету."""
            print("\nThe following models have been printed:")
            for completed_model in completed_models:
                print(completed_model)
        
        unprinted_designs = ['phone case', 'robot pendant', 'dodecahedron']
        completed_models = []
        
        print_models(unprinted_designs, completed_models)
        show_completed_models(completed_models)

Біз print_models() функциясын екі параметрмен анықтаймыз: басып шығару қажет дизайндар тізімі және аяқталған үлгілер тізімі. Осы екі тізімді ескере отырып, функция басып шығарылмаған дизайн тізімін босату және аяқталған үлгілер тізімін толтыру арқылы әрбір дизайнды басып шығаруды имитациялайды. Содан кейін ❷ show_completed_models() функциясын бір параметрмен анықтаймыз: аяқталған үлгілер тізімі. Осы тізімді ескере отырып, show_completed_models() басып шығарылған әрбір үлгінің атын көрсетеді.

Бұл бағдарлама функциялары жоқ нұсқамен бірдей нәтижеге ие, бірақ код әлдеқайда ұйымдастырылған. Жұмыстың көп бөлігін орындайтын код екі бөлек функцияға ауыстырылды, бұл бағдарламаның негізгі бөлігін түсінуді жеңілдетеді. Бағдарламаның негізгі бөлігін қарап, не болып жатқанын қаншалықты оңай қадағалай алатыныңызды байқаңыз:


        unprinted_designs = ['phone case', 'robot pendant', 'dodecahedron']
        completed_models = []
        
        print_models(unprinted_designs, completed_models)
        show_completed_models(completed_models)

Біз басып шығарылмаған дизайн тізімін және аяқталған үлгілерді сақтайтын бос тізімді орнаттық. Содан кейін, біз екі функциямызды бұрыннан анықтағандықтан, бізге тек оларды шақыру және оларға дұрыс аргументтерді беру керек. Біз print_models() шақырамыз және оған қажетті екі тізімді жібереміз; күткендей, print_models() дизайнды басып шығаруды имитациялайды. Содан кейін біз show_completed_models() деп шақырамыз және басып шығарылған үлгілер туралы есеп беруі үшін оған аяқталған үлгілер тізімін береміз. Сипаттамалық функция атаулары басқаларға бұл кодты оқуға және оны түсініктемесіз де түсінуге мүмкіндік береді.

Функциялары жоқ нұсқаға қарағанда бұл бағдарламаны кеңейту және қолдау оңайырақ. Кейінірек қосымша дизайнды басып шығару қажет болса, біз жай ғана print_models() деп қайта шақыра аламыз. Егер басып шығару кодын өзгерту қажет екенін түсінсек, кодты бір рет өзгерте аламыз және біздің өзгертулер функция шақырылған жерде болады. Бұл әдіс бағдарламаның бірнеше жерінде кодты бөлек жаңартуға қарағанда тиімдірек.

Бұл мысал сонымен қатар әрбір функцияның бір нақты тапсырмасы болуы керек деген идеяны көрсетеді. Бірінші функция әрбір дизайнды басып шығарады, ал екіншісі аяқталған үлгілерді көрсетеді. Бұл екі тапсырманы орындау үшін бір функцияны пайдаланғаннан гөрі тиімдірек. Функцияны жазып жатсаңыз және функция тым көп әртүрлі тапсырмаларды орындап жатқанын байқасаңыз, кодты екі функцияға бөліп көріңіз. Күрделі тапсырманы қадамдар қатарына бөлу кезінде пайдалы болуы мүмкін басқа функциядан функцияны әрқашан шақыруға болатынын есте сақтаңыз.

Функцияның тізімді өзгертуіне жол бермеу

Функция тізімді өзгертпеуі керек жағдайлар болады. Мысалы, басып шығарылмаған дизайндар тізімі бар және оларды аяқталған үлгілер тізіміне жылжыту функциясын жаздыңыз делік (алдыңғы мысалдағыдай). Сіз барлық дизайнды басып шығарсаңыз да, өзіңіздің бір қажеттілік үшін басып шығарылмаған дизайндардың түпнұсқа тізімін сақтап қалғыңыз келді делік. Бірақ сіз барлық дизайн атауларын unprinted_designs ішінен жылжытқандықтан, тізім енді бос, және енді сізде бар жалғыз нұсқа бос тізім; түпнұсқасы жоғалып кетті. Бұл жағдайда функцияға түпнұсқаны емес, тізімнің көшірмесін беру арқылы бұл мәселені шешуге болады. Функцияның тізімге жасайтын кез-келген өзгертулері түпнұсқа тізімді өзгеріссіз қалдырып, көшірмеге ғана әсер етеді.

Функцияға тізімнің көшірмесін беру үшін былай жазасыз:


        function_name(list_name[:])

Тік жақшалар мен қос нүкте белгісі [:] функцияға жіберу үшін тізімнің көшірмесін жасайды. Егер printing_models.py ішіндегі басып шығарылмаған дизайндар тізімін босатқымыз келмесе, print_models() функциясын келесідей шақыруға болады:


        print_models(unprinted_designs[:], completed_models)

print_models() функциясы өз жұмысын орындай алады, себебі ол әлі де барлық басып шығарылмаған дизайн атауларын алады. Бірақ бұл жолы ол нақты printed_designs тізімін емес, түпнұсқа басып шығарылмаған дизайндар тізімінің көшірмесін пайдаланады. completed_models тізімі бұрынғыдай басып шығарылған үлгілердің атауларымен толтырылады, бірақ басып шығарылмаған дизайндардың unprinted_designs бастапқы тізіміне функция әсер етпейді.

Тізімнің көшірмесін функцияларыңызға беру арқылы оның мазмұнын сақтай алатын болсаңыз да, көшірмені жіберуге нақты себеп болмаса, түпнұсқа тізімді функцияларға беруіңіз керек. Функцияның бар тізіммен жұмыс істеуі тиімдірек, себебі бұл бөлек көшірме жасау үшін қажет уақыт пен жадты пайдалануды болдырмайды. Бұл әсіресе үлкен тізімдермен жұмыс істегенде дұрыс.

Аргументтердің ерікті санын беру

Кейде функция қанша аргумент қабылдау керек екенін алдын ала білмейсіз. Бақытымызға орай, Python функциясы шақырушы амалдардан аргументтердің ерікті санын қабылдауға мүмкіндік береді.

Мысалы, пицца құрастыратын функцияны қарастырыңыз. Ол бірнеше қоспаны/ингредиентті қабылдауы керек, бірақ адам қанша қоспаны қалайтынын алдын ала біле алмайсыз. Келесі мысалдағы функцияның бір параметрі бар, *toppings, бірақ бұл параметр шақырушы жол неше аргумент берсе соншалықты аргументті қабылдайды:

pizza.py


        def make_pizza(*toppings):
            """Сұралған қоспалар тізімін басып шығарыңыз."""
            print(toppings)
        
        make_pizza('pepperoni')
        make_pizza('mushrooms', 'green peppers', 'extra cheese')

Параметр атауындағы жұлдызша *toppings Python-ға осы функция алатын барлық мәндерді қамтитын toppings деп аталатын кортеж жасау керектігін айтады. Функция денесіндегі print() шақыруы Python бір мәнді функция шақыруын да, үш мәнді шақыруды да өңдей алатынын көрсететін нәтиже береді. Ол әртүрлі шақыруларды бірдей қабылдайды. Функция тек бір мәнді алса да, Python аргументтерді кортежге жинайтынын ескеріңіз:


        ('pepperoni',)
        ('mushrooms', 'green peppers', 'extra cheese')

Енді біз print() шақыруын қоспалар тізімін аралап өтетін және тапсырыс берілген пиццаны сипаттайтын циклмен алмастыра аламыз:


        def make_pizza(*toppings):
            """Біз дайындап жатқан пиццаны қорытындылаңыз."""
            print("\nMaking a pizza with the following toppings:")
            for topping in toppings:
                print(f"- {topping}")
        
        make_pizza('pepperoni')
        make_pizza('mushrooms', 'green peppers', 'extra cheese')

Функция бір мәнді немесе үш мәнді алатынына қарамастан, сәйкес жауап береді:


        Making a pizza with the following toppings:
        - pepperoni
        
        Making a pizza with the following toppings:
        - mushrooms
        - green peppers
        - extra cheese

Бұл синтаксис функция қанша аргумент алғанына қарамастан жұмыс істейді.

Позициялық және ерікті аргументтерді араластыру

Егер функцияның әртүрлі аргумент типтерін қабылдауын қаласаңыз, аргументтердің ерікті санын қабылдайтын параметрді функция анықтамасының соңына жазуыңыз керек. Python алдымен позициялық және кілт сөз аргументтерін сәйкестендіреді, содан кейін соңғы параметрдегі қалған аргументтерді жинайды.

Мысалы, функция пицца өлшемін алуы қажет болса, бұл параметр *toppings параметрінен бұрын келуі керек:


        def make_pizza(size, *toppings):
            """Біз дайындап жатқан пиццаны қорытындылаңыз."""
            print(f"\nMaking a {size}-inch pizza with the following toppings:")
            for topping in toppings:
                print(f"- {topping}")
        
        make_pizza(16, 'pepperoni')
        make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')

Функция анықтамасында Python өзі алатын бірінші мәнді size параметріне тағайындайды. Кейін келетін барлық басқа мәндер toppings кортежінде сақталады. Функция шақыруларында алдымен өлшемге арналған аргумент, содан кейін қажет болғанша көп ингредиенттер саны келеді.

Енді әрбір пиццаның өлшемі мен ингредиенттердің саны бар және әрбір ақпарат тиісті жерде басып шығарылады, алдымен өлшемі, ал кейін ингредиеттер көрсетіледі:


        Making a 16-inch pizza with the following toppings:
        - pepperoni
        
        Making a 12-inch pizza with the following toppings:
        - mushrooms
        - green peppers
        - extra cheese

Кілтсөз аргументтерінің кез-келген санын пайдалану

Кейде сіз аргументтердің кез-келген санын қабылдағыңыз келеді, бірақ функцияға қандай ақпарат жіберілетінін алдын ала білмейсіз. Бұл жағдайда шақыру операторында қанша кілт-мән жұптарын қабылдайтын функцияларды жазуға болады. Бір мысал пайдаланушы профильдерін құруды қамтиды: сіз пайдаланушы туралы ақпарат алатыныңызды білесіз, бірақ қандай ақпарат алатыныңызды білмейсіз. Келесі мысалдағы build_profile() функциясы әрқашан аты мен тегін алады, бірақ ол сонымен қатар кілтсөз аргументтерінің ерікті санын қабылдайды:

user_profile.py


        def build_profile(first, last, **user_info):
            """Пайдаланушы туралы білетініміздің барлығын қамтитын сөздік құрастырыңыз."""
            """Пайдаланушы туралы біз білетін барлық нәрсені қамтитын сөздік жасаңыз."""
             user_info['first_name'] = first
            user_info['last_name'] = last
            return user_info
        
        user_profile = build_profile('albert', 'einstein',
                                     location='princeton',
                                     field='physics')
        print(user_profile)

build_profile() анықтамасы атын және тегін күтеді, содан кейін ол қолданушыға қалағанша атау-мән жұптарын жіберуге мүмкіндік береді. **user_info параметрінің алдындағы қос жұлдызшалар Python-ға функция алатын барлық қосымша атау-мән жұптарын қамтитын user_info деп аталатын сөздікті жасауға мүмкіндік береді. Функция ішінде кез-келген сөздіктегідей user_info ішіндегі кілт-мән жұптарына қол жеткізе аласыз.

build_profile() функциясының шішнде аты мен фамилиясын user_info сөздігіне қосамыз, себебі біз әрқашан пайдаланушыдан осы екі ақпаратты аламыз, ❶ және олар әлі сөздікке орналастырылмаған. Содан кейін user_info сөздігін функцияны шақыру жолына қайтарамыз.

Біз build_profile() функцисын мына мәндерді бере отырып шақырамыз: оның аты 'albert', фамилия 'einstein' және екі кілт-мән жұптары location='princeton' және field='physics'. Қайтарылған profile мәнін user_profile деп тағайындаймыз және user_profile басып шығарамыз:


        {'location': 'princeton', 'field': 'physics',
        'first_name': 'albert', 'last_name': 'einstein'}

Қайтарылған сөздікте пайдаланушының аты-жөні, сондай-ақ бұл жағдайда орналасқан жері мен зерттеу саласы бар. Функция шақыруында қанша қосымша кілт-мән жұбы берілгеніне қарамастан, функция жұмыс істейді.

Өз функцияларыңызды жазған кезде позициялық, кілт сөзді және ерікті мәндерді әртүрлі тәсілдермен араластыруға болады. Барлық осы аргумент түрлері бар екенін білу пайдалы, өйткені сіз басқа адамдардың кодын оқи бастағанда оларды жиі көресіз. Әртүрлі түрлерді дұрыс пайдалану және әр түрді қашан қолдану керектігін білу үшін тәжірибе қажет. Әзірге сіз жасағыңыз келетін жұмысты орындайтын қарапайым кодтау тәсілін пайдалануды ұмытпаңыз. Прогресс барысында сіз ең тиімді әдісті қолдануды үйренесіз.

Функцияларды модульдерде сақтау

Функциялардың бір артықшылығы - олардың негізгі бағдарламадан код блоктарын бөлу тәсілі. Функцияларыңыз үшін түсінікті, функцияны сипаттайтын атауларды пайдаланған кезде, бағдарламаларды орындау оңайырақ болады. Функцияларыңызды модуль деп аталатын бөлек файлда сақтау және содан кейін сол модульді негізгі бағдарламаңызға импорттау арқылы бір қадам алға баса аласыз. import амалы Python-ға модульдегі кодты ағымдағы іске қосылған бағдарлама файлында қолжетімді етуді айтады.

Функцияларды бөлек файлда сақтау бағдарлама кодының мәліметтерін жасыруға және оның жоғары деңгейлі логикасына назар аударуға мүмкіндік береді. Ол сонымен қатар көптеген әртүрлі бағдарламалардағы функцияларды қайта пайдалануға мүмкіндік береді. Функцияларыңызды бөлек файлдарда сақтаған кезде, бүкіл бағдарламаңызды ортақ пайдаланбай-ақ, сол файлдарды басқа бағдарламашылармен ортақ пайдалануға болады. Функцияларды импорттау жолын білу басқа бағдарламашылар жазған функциялар кітапханасын пайдалануға мүмкіндік береді.

Модульді импорттаудың бірнеше жолы бар, мұнда олардың әрқайсысын қысқаша көрсетемін.

Модульді толықтай импорттау

Функцияларды импорттауды бастау үшін алдымен модуль жасау керек. Модуль — бағдарламаңызға импорттағыңыз келетін кодты қамтитын .py-мен аяқталатын файл. make_pizza() функциясын қамтитын модуль жасайық. Бұл модульді жасау үшін біз pizza.py файлынан make_pizza() функциясынан басқасының барлығын жоямыз:

pizza.py


        def make_pizza(size, *toppings):
            """Біз дайындап жатқан пиццаны қорытындылаңыз."""
            print(f"\nMaking a {size}-inch pizza with the following toppings:")
            for topping in toppings:
                print(f"- {topping}")

Енді біз pizza.py сияқты бір каталогта making_pizzas.py деп аталатын бөлек файлды жасаймыз. Бұл файл біз жасаған модульді импорттайды, содан кейін make_pizza() функциясын екі рет шақырады:

making_pizzas.py


        import pizza
        
         pizza.make_pizza(16, 'pepperoni')
        pizza.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')

Python осы файлды оқығанда, import pizza жолы Python-ға pizza.py файлын ашуды және ондағы барлық функцияларды осы бағдарламаға көшіруді айтады. Файлдар арасында көшірілген кодты көрмейсіз, себебі Python кодты бағдарлама іске қосылмай тұрып көшіреді. Сізге тек pizza.py ішінде анықталған кез-келген функция енді making_pizzas.py файл-кодының ішінде қолжетімді болатынын білу қажет.

Импортталған модульден функцияны шақыру үшін, импортталған модульдің атын - pizza, содан кейін функцияның атын - make_pizza(), нүкте арқылы ❶ бөлек енгізіңіз. Бұл код модульді импорттамаған бастапқы бағдарламамен бірдей нәтижені шығарады:


        Making a 16-inch pizza with the following toppings:
        - pepperoni
        
        Making a 12-inch pizza with the following toppings:
        - mushrooms
        - green peppers
        - extra cheese

Импорттаудың бұл бірінші тәсілі, онда сіз жай ғана import деп, содан кейін модуль атауын жазасыз, модульдегі әрбір функцияны бағдарламаңызда қолжетімді етеді. module_name.py деп аталатын модульді толықтай импорттау үшін import амалының осы түрін пайдалансаңыз, модульдегі әрбір функция келесі синтаксис арқылы қолжетімді болады:


        module_name.function_name()

Функцияларды жекелеп импорттау

Сонымен қатар модульден белгілі бір функцияны импорттай аласыз. Міне, осы тәсілдің жалпы синтаксисі:


        from module_name import function_name

Әр функцияның атын үтірмен бөлу арқылы модульден қалағаныңызша көптеген функцияларды импорттай аласыз:


        from module_name import function_0, function_1, function_2

making_pizzas.py мысалы, біз қолданатын функцияны ғана импорттағымыз келсе, келесідей болады:


        from pizza import make_pizza
        
        make_pizza(16, 'pepperoni')
        make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')

Бұл синтаксиспен функцияны шақырған кезде нүкте белгісін пайдаланудың қажеті жоқ. make_pizza() функциясын import операторында анық импорттағандықтан, функцияны пайдаланған кезде оны атымен шақыра аламыз.

Функцияға бүркеншік ат беру үшін пайдалану

Егер импортталатын функцияның аты бағдарламаңыздағы бар атқа қайшы келуі мүмкін болса немесе функция атауы ұзын болса, орнына қысқа, бірегей бүркеншік атын пайдалана аласыз — функцияның лақап атына ұқсас балама атау. Функцияны импорттау кезінде функцияға осы арнайы лақап атын бересіз.

Мұнда біз make_pizza() функциясына mp() бүркеншік атын, make_pizza-ны mp ретінде импорттау арқылы береміз. as кілт сөзі сіз берген бүркеншік атты пайдаланып функцияның атын өзгертеді:


        from pizza import make_pizza as mp
        
        mp(16, 'pepperoni')
        mp(12, 'mushrooms', 'green peppers', 'extra cheese')

Осында көрсетілген import операторы осы бағдарламадағы make_pizza() функциясының атын mp() етіп өзгертеді. Кез-келген уақытта біз make_pizza() функциясын шақырғымыз келсе, оның орнына жай ғана mp() деп жаза аламыз, ал Python кодты make_pizza() ішінде жазылған кодты іске қосады. Осы бағдарлама файлында жазған тағы бір басқа make_pizza() функциясы бар болса, онымен кез-келген шатасу болмайды.

Лақап ат беруге арналған жалпы синтаксис:


        from module_name import function_name as fn

Модульге бүркеншік ат беру үшін пайдалану

Модуль атауына да бүркеншік ат беруге болады. Модульге қысқа бүркеншік ат беру, мысалы, pizza үшін p, модуль функцияларын жылдам шақыруға мүмкіндік береді. p.make_pizza() шақыруы pizza.make_pizza() шақырудан гөрі қысқарақ.:


        import pizza as p
        
        p.make_pizza(16, 'pepperoni')
        p.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')

import операторы жазылу барысында pizza модульіне p бүркеншік аты берілген, бірақ модульдің барлық функциялары бастапқы атауларын сақтайды. p.make_pizza() жазу арқылы функцияларды шақыру pizza.make_pizza() қарағанда қысқа ғана емес, сонымен қатар ол сіздің назарыңызды модуль атына қарағанда функцияларының сипаттамалық атауларына көбірек назар аударуға мүмкіндік береді. Әрбір функцияның не істейтінін анық көрсететін бұл функция атаулары толық модуль атауын пайдаланудан гөрі кодтың оқылуына маңыздырақ.

Бұл тәсілдің жалпы синтаксисі:


        import module_name as mn

Модульдегі барлық функцияларды импорттау

Жұлдызша (*) операторын пайдалану арқылы Python-ға модульдегі барлық функцияны импортта деп айта аласыз:


        from pizza import *
        
        make_pizza(16, 'pepperoni')
        make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')

import амалынандағы жұлдызша Python-ға pizza модулінен әрбір функцияны осы бағдарлама файлына көшіру керектігін айтады. Әрбір функция импортталғандықтан, нүкте белгісін пайдаланбай әр функцияны аты бойынша шақыруға болады. Дегенмен, сіз жазбаған үлкенірек модульдермен жұмыс істегенде бұл тәсілді қолданбағаныңыз жөн: егер модульде жобаңыздағы бар атқа сәйкес функция атауы болса, күтпеген нәтижелерге қол жеткізуге болады. Python бірдей атпен бірнеше функцияларды немесе айнымалы мәндерді көруі мүмкін және барлық функцияларды бөлек импорттаудың орнына ол функцияларды қайта жазады.

Ең жақсы әдіс - қалаған функцияны немесе функцияларды импорттау немесе бүкіл модульді импорттау және нүкте белгісін пайдалану. Бұл оқуға және түсінуге оңай түсінікті кодқа әкеледі. Бұл әдістің мұнда жазылу себебі, басқа адамдар жазған кодта көрсеңіз бірден тани алатын боласыз. Жалпы синтаксисі келесідей жазылады:


        from module_name import *

Функцияларды жазу стилі

Функцияларды сәндеу кезінде кейбір мәліметтерді есте сақтау қажет. Функциялардың сипаттайтын-түсінікті атаулары болуы керек және бұл атауларда кіші әріптер мен астын сызу таңбалары қолданылуы керек. Сипаттама атаулар сізге және басқаларға сіздің кодыңыз не істеуге тырысып жатқанын түсінуге көмектеседі. Модуль атаулары да осы конвенцияларды қолдануы керек.

Әрбір функцияда функцияның не істейтінін қысқаша түсіндіретін түсініктеме болуы керек. Бұл түсініктеме функция анықтамасынан кейін бірден пайда болуы және docstring пішімін пайдалану керек. Жақсы құжатталған функцияда басқа бағдарламашылар функцияны тек құжат жолындағы сипаттаманы оқу арқылы пайдалана алады. Олар кодтың сипатталғандай жұмыс істейтініне сену керек және олар функцияның атын, оған қажет аргументтерді және ол қайтаратын мән түрін білетін болса, оны өз бағдарламаларында пайдалана алуы керек.

Егер параметр үшін әдепкі мәнді көрсетсеңіз, теңдік белгісінің екі жағында бос орындар болмауы керек (жабысып жазылады):

def function_name(parameter_0, parameter_1='default value')

Функция шақыруларында кілт-сөз аргументтері үшінде осындай шартты ереже қолданылуы керек:

function_name(value_0, parameter_1='value')

PEP 8 (https://www.python.org/dev/peps/pep -0008) код жолдарын 79 таңбаға дейін шектеуді ұсынады, осылайша әрбір жол орынды өлшемді өңдегіш терезесінде көрінеді. Параметрлер жиыны функция анықтамасының 79 таңбадан ұзақ болуына себеп болса, анықтау жолындағы жақшаны ашқаннан кейін ENTER пернесін басыңыз. Келесі жолда TAB пернесін екі рет басып, аргументтер тізімін функцияның негізгі бөлігінен бөліңіз, ол тек бір деңгейде шегінеді.

Көптеген редакторлар бірінші жолда орнатқан шегініске сәйкес келу үшін кез-келген қосымша аргумент жолдарын автоматты түрде қатарға қояды:


        def function_name(
                parameter_0, parameter_1, parameter_2,
                parameter_3, parameter_4, parameter_5):
            function body...

Егер бағдарламаңызда немесе модульде бірнеше функция болса, бір функцияның қай жерде аяқталып, келесісі басталатынын көруді жеңілдету үшін әрқайсысын екі бос жолға бөлуге болады.

Барлық import амалдары файлдың басында жазылуы керек. Жалғыз ерекшелік - жалпы бағдарламаны сипаттау үшін файлыңыздың басында түсініктемелерді пайдалансаңыз.

Қорытынды

Бұл тарауда сіз функцияларды қалай жазуды және аргументтерді беруді үйрендіңіз, осылайша функцияларыңыз өз жұмысын орындау үшін қажетті ақпаратқа қол жеткізе алады. Сіз позициялық және кілт сөз аргументтерін пайдалануды, сондай-ақ аргументтердің ерікті санын қалай қабылдауды үйрендіңіз. Сіз шығысты көрсететін функцияларды және мәндерді қайтаратын функцияларды көрдіңіз. Функцияларды тізімдермен, сөздіктермен, if операторларымен және while циклдарымен пайдалануды үйрендіңіз. Сіз сондай-ақ функцияларды модульдер деп аталатын бөлек файлдарда сақтау жолын көрдіңіз, осылайша сіздің бағдарлама файлдарыңыз оңайырақ және түсінуге оңай болады. Соңында, бағдарламаларыңыз әрі қарай жақсы құрылымдалған және сізге және басқаларға оқуға мүмкіндігінше оңай болатындай етіп функцияларды стильдеуді үйрендіңіз.

Бағдарламашы ретінде сіздің мақсаттарыңыздың бірі қалағаныңызды орындайтын қарапайым код жазу болуы керек және функциялар мұны істеуге көмектеседі. Олар код блоктарын жазуға және олардың жұмыс істейтінін білгеннен кейін оларды жалғыз қалдыруға мүмкіндік береді. Функция өз жұмысын дұрыс орындайтынын білсеңіз, оның жұмысын жалғастырып, келесі кодтау тапсырмаңызға көшетініне сене аласыз.

Функциялар кодты бір рет жазуға, содан кейін сол кодты қалағаныңызша қайта пайдалануға мүмкіндік береді. Функцияда кодты іске қосу қажет болғанда, сізге тек бір жолды шақыруды жазу жеткілікті және функция өз жұмысын орындайды. Функция әрекетін өзгерту қажет болғанда, кодтың бір блогын ғана өзгерту керек және өзгерту сол функцияны шақырған жерде күшіне енеді.

Функцияларды пайдалану бағдарламаларды оқуды жеңілдетеді және жақсы функция атаулары бағдарламаның әрбір бөлігінің не істейтінін қорытындылайды. Функция шақыруларының қатарын оқу код блоктарының ұзақ сериясын оқуға қарағанда бағдарламаның не істейтінін тезірек түсінуге мүмкіндік береді.

Функциялар сонымен қатар кодты тексеруді және жөндеуді жеңілдетеді. Бағдарлама жұмысының негізгі бөлігі әрқайсысының белгілі бір жұмысы бар функциялар жиынтығымен орындалса, сіз жазған кодты тексеру және қолдау оңайырақ болады. Әрбір функцияны шақыратын және әрбір функция кезігуі мүмкін барлық жағдайларда жұмыс істейтінін тексеретін бөлек бағдарлама жаза аласыз. Бұл әрекетті орындаған кезде, функциялар оларды шақырған сайын дұрыс жұмыс істейтініне сенімді бола аласыз.

9-бөлімде сіз класстар жазуды үйренесіз. Класстар функциялар мен деректерді икемді және тиімді жолмен пайдалануға болатын бір жинақы пакетке біріктіреді.

Кластар

ITUniver

9
Кластар

Объектіге бағытталған бағдарламалау (OOP) бағдарламалық жабдықты жазудың ең тиімді тәсілдерінің бірі болып табылады. Объектіге бағытталған бағдарламалауда сіз нақты дүниедегі заттар мен жағдайларды көрсететін класстарды жазасыз және осы кластар негізінде нысандарды/object жасайсыз. Классты жазғанда, сіз нысандардың барлығында болуы мүмкін жалпылама әрекетті анықтайсыз.

Класстан жеке нысандарды жасағанда, әрбір нысан автоматты түрде жалпы "қасиетпен" жабдықталады; содан кейін әрбір нысанға өзіңіз қалаған бірегей-жеке қасиеттерді бере аласыз. Нақты әлемдегі жағдайларды объектіге бағытталған бағдарламалау арқылы қаншалықты жақсы модельдеуге болатынына таң қаласыз.

Класстан нысан жасау инстанциялау/instantiation деп аталады және сіз класстың instances/даналары-мен жұмыс жасайсыз. Бұл тарауда сіз класстарды жазасыз және сол класстардың даналарын жасайсыз. Даналарда сақтауға болатын ақпарат түрін көрсетесіз және осы даналармен орындалатын әрекеттерді анықтайсыз. Сіз сондай-ақ бар класстардың функционалдығын кеңейтетін класстарды жазасыз, осылайша ұқсас класстар ортақ функционалдылықты бөлісе алады және аз кодпен көп нәрсені жасай аласыз. Сіз өз класстарыңызды модульдерде сақтайсыз және басқа бағдарламашылар жазған класстарды жеке бағдарлама файлдарыңызға импорттайсыз.

Нысанға-бағытталған бағдарламалауды үйрену шын-әлемді бағдарламашы сияқты көруге көмектеседі. Бұл сізге кодыңызды түсінуге көмектеседі - әр код жолында не болып жатқанын ғана емес, тұтас бағдарламаның артындағы ұғымды көрсетеді. Класстардың артындағы логиканы білу логикалық ойлауға үйретеді, осылайша кез-келген мәселені тиімді шешетін бағдарламалар жаза аласыз.

Класстар сіздің және сіз бірге жұмыс істейтін басқа бағдарламашылардың өмірін жеңілдетеді. Сіз және басқа бағдарламашылар бірдей логикаға негізделген код жазғанда, сіз бір-біріңіздің жұмысын түсіне аласыз. Бағдарламаларыңыз сізбен бірге жұмыс істейтін адамдар үшін мағыналы болады және барлығына көп нәрсеге қол жеткізуге мүмкіндік береді.

Класс жасау және пайдалану

Класстар арқылы кез-келген нәрсені дерлік үлгілеуге болады. Қарапайым класс жазудан бастайық, Dog, ол итті, атап айтқанда бір итті емес, кез-келген итті бейнелейді. Көптеген үй жануарлары туралы не білеміз? Бәрінің де аты, жасы бар. Сондай-ақ, иттердің көпшілігі отырады және айналады. Бұл екі ақпарат (аты мен жасы) және осы екі мінез-құлық (отыру және айналу) біздің Dog классына кіреді, өйткені олар иттердің көпшілігіне тән. Бұл класс Python бағдарламасына итті бейнелейтін нысанды қалай жасау керектігін айтады. Классымыз жазылған соң, біз оны әрқайсысы бір нақты итті білдіретін жеке даналарды жасау үшін пайдаланамыз.

Ит класын жасау

Dog классынан жасалған әрбір данада name және age сақталады және біз иттің әрқайсысына sit() және roll_over() мүмкіндігін береміз:

dog.py


         class Dog:
            """Итті үлгілеудің қарапайым әрекеті."""
        
             def __init__(self, name, age):
                """Аты мен жас атрибуттарын инициализациялау."""
                 self.name = name
                self.age = age
        
             def sit(self):
                """Пәрменге жауап ретінде отырған итке ұқсаңыз."""
                print(f"{self.name} is now sitting.")
        
            def roll_over(self):
                """Пәрменге жауап ретінде айналдыруды имитациялау."""
                print(f"{self.name} rolled over!")

Бұл жерде назар аударатын нәрсе көп, бірақ уайымдамаңыз. Сіз бұл құрылымды осы тарауда көресіз және оған үйренуге көп уақытыңыз болады. Алдымен Dog ❶ деп аталатын классты анықтаймыз. Шартты түрде бас әріппен жазылған атаулар Python тіліндегі класстарға қатысты. Класс анықтамасында жақшалар жоқ, өйткені біз бұл классты нөлден жасап жатырмыз. Содан кейін бұл класстың не істейтінін сипаттайтын құжат тізбегін жазамыз.

__init__() әдісі

Кластың бөлігі болып табылатын функция әдіс/method болып табылады. Функциялар туралы білгеніңіздің бәрі әдістерге де қатысты; әзірге жалғыз практикалық айырмашылық - әдістерді шақыру тәсілі. ❷ __init__() әдісі - Dog класы негізінде жаңа дананы жасаған сайын Python автоматты түрде іске қосатын арнайы әдіс. Бұл әдісте екі бастапқы астын сызу және екі кейінгі астын сызу бар, бұл конвенция Python-ның әдепкі әдіс атауларының сіздің жасаған әдіс атауларымен қайшы келуін болдырмауға көмектеседі. __init__() параметрінің әр жағында екі астыңғы сызықты қолданғаныңызға көз жеткізіңіз. Әр жағынан бір ғана қолдансаңыз, классты пайдаланған кезде әдіс автоматты түрде шақырылмайды, бұл анықтау қиын қателерге әкелуі мүмкін.

Біз __init__() әдісін үш параметрге ие болу үшін анықтаймыз: self, name және age. self параметрі әдіс анықтамасында қажет және ол басқа параметрлерден бұрын бірінші тұруы керек. Оны анықтауға қосу керек, себебі Python бұл әдісті кейін шақырғанда (Dog данасын жасау үшін), әдіс шақыруы self аргументін автоматты түрде шақыруға береді. Данамен байланысты әрбір әдіс шақыруы автоматты түрде self параметрінен өтеді, себебі self данаға сілтеме болып табылады; ол жеке данаға - класстағы атрибуттар мен әдістерге қол жеткізуге мүмкіндік береді. Dog данасын жасаған кезде, Python Dog классынан __init__() әдісін шақырады. Аргументтер ретінде Dog() аты мен жасын береміз; self автоматты түрде беріледі, сондықтан оны берудің қажеті жоқ. Біз Dog классынан дананы жасағымыз келгенде, біз тек соңғы екі параметрге, name және age мәндерін береміз.

__init__() әдісінің ішінде анықталған екі айнымалы мәндердің әрқайсысында self префиксі бар. self префиксі бар кез-келген айнымалы класстағы әрбір әдіске қол жетімді және біз де осы айнымалы мәндерге класстан жасалған кез-келген дана арқылы қол жеткізе аламыз. self.name = name жолы name параметрімен байланысты мәнді алады және оны name айнымалысына тағайындайды, содан кейін ол жасалатын данаға тіркеледі. Дәл осындай процесс self.age = age арқылы орындалады. Осы сияқты даналар арқылы қол жеткізуге болатын айнымалылар атрибуттар деп аталады.

Dog классында анықталған басқа екі әдіс бар: sit() және roll_over() . Біз жазатын бағдарлама бұл әдістерді іске қосу үшін қосымша ақпаратты қажет етпейтіндіктен, біз оларды тек self параметрі ретінде анықтаймыз. Біз кейінірек жасайтын даналар осы әдістерге қол жеткізе алады. Басқаша айтқанда, олар отыра алады және айнала алады. Әзірге sit() және roll_over() көп нәрсе істемейді. Олар жай ғана иттің отырғаны немесе айналып жатқаны туралы хабарлама басып шығарады. Бірақ тұжырымдаманы шынайы жағдайларға дейін кеңейтуге болады: егер бұл класс компьютерлік ойынның бөлігі болса, бұл әдістер анимациялық итті отыруға және айналдыруға арналған кодты қамтиды. Бұл класс робот итті басқару үшін жазылған болса, бұл әдістер робот иттің отыруына және айналуына себеп болатын қозғалыстарды бағыттайды.

Класстан дананы жасау

Классты қарастырғанда, класс дананы қалай жасауға болатыны туралы нұсқаулар жиынтығы ретінде ойлауға болады. Dog классы - Python-ға нақты иттерді көрсететін жеке даналарды қалай жасау керектігін айтатын нұсқаулар жинағы.

Нақты итті көрсететін дананы жасайық:


        
        class Dog:
            """Итті үлгілеудің қарапайым әрекеті."""
        
             def __init__(self, name, age):
                """Аты мен жас атрибуттарын инициализациялау."""
                 self.name = name
                self.age = age
        
             def sit(self):
                """Пәрменге жауап ретінде отырған итке ұқсаңыз."""
                print(f"{self.name} is now sitting.")
        
             def roll_over(self):
                """Пәрменге жауап ретінде айналдыруды имитациялау."""
                print(f"{self.name} rolled over!")
        
        
         my_dog = Dog('Willie', 6)
        
         print(f"My dog's name is {my_dog.name}.")
         print(f"My dog is {my_dog.age} years old.")

Бұл жерде біз қолданып жатқан Dog классы - біз жаңа ғана алдыңғы мысалда жазған класс. Мұнда біз Python-ға аты 'Willie' және жасы 6 ❶ болатын ит жасауды айтамыз. Python осы жолды оқығанда, ол 'Willie' және 6 аргументтерімен Dog ішіндегі __init__() әдісін шақырады. __init__() әдісі осы нақты итті көрсететін дананы жасайды және біз берген мәндерді пайдаланып name және age атрибуттарын орнатады. Содан кейін Python осы итті көрсететін дананы қайтарады. Біз бұл дананы my_dog айнымалысына тағайындаймыз. Бұл жерде атау ережесі пайдалы; әдетте Dog сияқты бас әріппен жазылған атау классқа, ал my_dog сияқты кіші әріппен жазылған атау класстан жасалған жалғыз дананы білдіреді деп болжауға болады.

Атрибуттарға қол жеткізу

Дананың атрибуттарына қол жеткізу үшін нүкте белгісін пайдаланасыз. Мысалы, ❷ my_dog данасының name атрибуты мәніне былай жазу арқылы қол жеткіземіз:

my_dog.name

Нүкте белгісі Python тілінде жиі қолданылады. Бұл синтаксис Python атрибут мәнін қалай табатынын көрсетеді. Мұнда Python my_dog данасын қарастырады, содан кейін my_dog-пен байланысты name атрибутын/атрибутын табады. Бұл Dog классында self.name деп аталатын атрибут. Біз age ❸ атрибутымен жұмыс істеу үшін дәл осындай тәсілді қолданамыз.

Басып шығарылатын нәтиже - my_dog туралы білетін нәрселердің қысқаша мазмұны:


        My dog's name is Willie.
        My dog is 6 years old.
Шақыру әдістері

Біз Dog классынан дананы жасағаннан кейін, Dog ішінде анықталған кез-келген әдісті шақыру үшін нүкте белгісін пайдалана аламыз. Итімізді отырғызып, айналдырайық:


        class Dog:
            --snip/код үзіндісі--
            --алдыңғы код бөліктрі осы жерде бар--
        
        my_dog = Dog('Willie', 6)
        my_dog.sit()
        my_dog.roll_over()

Әдісті шақыру үшін нүктемен бөлінген дананың атын (бұл жағдайда my_dog) және шақырғыңыз келетін әдісті беріңіз. Python my_dog.sit() дегенді оқығанда, Dog классында sit() әдісін іздейді және сол кодты іске қосады. Python my_dog.roll_over() жолын дәл осылай түсіндіреді.

Енді Вилли оған айтқанымызды орындайды:


        Willie is now sitting.
        Willie rolled over!

Бұл синтаксис өте пайдалы. Атрибуттар мен әдістерге name, age, sit() және roll_over() сияқты сәйкес сипаттамалық атаулар берілгенде, біз код блогы не істеу керек екенін оңай шығара аламыз, тіпті бұрын біз ешқашан көрмеген код блогы болса да.

Бірнеше даналарды жасау

Класстан қажетінше көп даналарды жасауға болады. your_dog деп аталатын екінші итті жасайық:


        class Dog:
            --snip/код үзіндісі--
        
        my_dog = Dog('Willie', 6)
        your_dog = Dog('Lucy', 3)
        
        print(f"My dog's name is {my_dog.name}.")
        print(f"My dog is {my_dog.age} years old.")
        my_dog.sit()
        
        print(f"\nYour dog's name is {your_dog.name}.")
        print(f"Your dog is {your_dog.age} years old.")
        your_dog.sit()

Бұл мысалда Вилли есімді ит пен Люси есімді ит жасаймыз. Әрбір ит бірдей әрекеттер жинағын орындай алатын өзіндік атрибуттары бар жеке данасы болып табылады:


        My dog's name is Willie.
        My dog is 6 years old.
        Willie is now sitting.
        
        Your dog's name is Lucy.
        Your dog is 3 years old.
        Lucy is now sitting.

Екінші ит үшін бірдей атау мен жасты қолдансақ та, Python әлі де Dog классынан бөлек дананы жасайды. Әрбір данаға бірегей айнымалы атау берген немесе ол тізімде немесе сөздікте бірегей орынды алатын болса, бір класстан қажетінше көп даналарды жасауға болады.

Класстармен және даналармен жұмыс

Сіз көптеген нақты жағдайларды көрсету үшін класстарды пайдалана аласыз. Классты жазғаннан кейін уақытыңыздың көп бөлігін сол класстан жасалған даналармен жұмыс істеуге жұмсайсыз. Сіз орындағыңыз келетін алғашқы тапсырмалардың бірі - белгілі бір данаға қатысты атрибуттарды өзгерту. Дана атрибуттарын тікелей өзгертуге немесе атрибуттарды белгілі бір жолмен жаңартатын әдістерді жазуға болады.

Автокөлік класы

Көлікті көрсететін жаңа класс жазайық. Біздің класс біз жұмыс істеп жатқан көлік түрі туралы ақпаратты сақтайды және оның осы ақпаратты қорытындылайтын әдісі болады:

car.py


        class Car:
            """Көлікті көрсетудің қарапайым әрекеті."""
        
             def __init__(self, make, model, year):
                """Көлікті сипаттау үшін атрибуттарды инициализациялаңыз."""
                self.make = make
                self.model = model
                self.year = year
        
             def get_descriptive_name(self):
                """Дұрыс пішімделген сипаттама атауын қайтарыңыз."""
                long_name = f"{self.year} {self.make} {self.model}"
                return long_name.title()
        
         my_new_car = Car('audi', 'a4', 2024)
        print(my_new_car.get_descriptive_name())

Car классында біз __init__() әдісін алдымен self параметрімен анықтаймыз, дәл біз Dog классында жасағандай. Біз оған тағы үш параметр береміз: make/жасаушы, model/үлгі және year/жыл, __init__() әдісі осы параметрлерді қабылдайды және оларды осы класстан жасалған даналармен байланыстырылатын атрибуттарға тағайындайды. Жаңа Car данасын жасағанда, данамыз үшін марканы, үлгісін және жылын көрсетуіміз керек.

Біз автомобильдің жылын, жасаушысын және үлгісін автомобильді ұқыпты сипаттайтын бір тіркеске қоятын get_descriptive_name() ❷ деп аталатын әдісті анықтаймыз. Бұл әдіс бізге әрбір атрибуттың мәнін жеке басып шығарудан сақтайды. Бұл әдісте атрибут мәндерімен жұмыс істеу үшін self.make, self.model және self.year қолданамыз. Класстан тыс, класс кодының сыртында біз Car классынан дананы жасаймыз және оны my_new_car ❸ айнымалысына тағайындаймыз. Содан кейін бізде қандай көлік бар екенін көрсету үшін get_descriptive_name() әдісін шақырамыз:

2024 Audi A4

Классты қызықты ету үшін уақыт өте келе өзгеретін төлсипат/атрибут қосамыз. Біз көліктің жалпы жүрген-жолын(пробег) сақтайтын атрибут қосамыз.

Атрибут үшін әдепкі мәнді орнату

Дана жасалғанда, атрибуттарды параметр ретінде жібермей-ақ анықтауға болады. Бұл атрибуттарды __init__() әдісінде анықтауға болады, мұнда оларға әдепкі мән тағайындалады.

Әрқашан 0 мәнінен басталатын odometer_reading деп аталатын атрибутты қосамыз.

Сондай-ақ әрбір көліктің одометрін оқуға көмектесетін read_odometer() әдісін қосамыз:


        class Car:
        
            def __init__(self, make, model, year):
                """Көлікті сипаттау үшін атрибуттарды инициализациялау."""
                self.make = make
                self.model = model
                self.year = year
                 self.odometer_reading = 0
        
            def get_descriptive_name(self):
                --snip/код үзіндісі--
        
             def read_odometer(self):
                """Көліктің жолын көрсететін мәлімдемені басып шығарыңыз."""
                print(f"This car has {self.odometer_reading} miles on it.")
        
        my_new_car = Car('audi', 'a4', 2024)
        print(my_new_car.get_descriptive_name())
        my_new_car.read_odometer()

Бұл жолы Python жаңа дананы жасау үшін __init__() әдісін шақырғанда, алдыңғы мысалдағыдай жасаушы, үлгі және жыл мәндерін атрибуттар ретінде сақтайды. Содан кейін Python odometer_reading деп аталатын жаңа атрибутты жасайды және оның бастапқы мәнін 0 ❶ етіп орнатады. Сондай-ақ бізде read_odometer() ❷ деп аталатын жаңа әдіс бар, ол көліктің жүріп өткен жолын оқуды жеңілдетеді.

Біздің көлігіміз 0 жол жүрісімен басталады:


        2024 Audi A4
        This car has 0 miles on it.

Одометрде дәл 0 миль бар көліктер көп сатылмайды, сондықтан бізге бұл атрибуттың мәнін өзгерту әдісі қажет.

Атрибут мәндерін өзгерту

Атрибуттың мәнін үш жолмен өзгертуге болады: мәнді тікелей дана арқылы өзгертуге, мәнді әдіс арқылы орнатуға немесе әдіс арқылы мәнді арттыруға (оған белгілі бір соманы қосу). Осы тәсілдердің әрқайсысын қарастырайық.

Атрибут мәнін тікелей өзгерту

Атрибуттың мәнін өзгертудің ең қарапайым жолы атрибутқа тікелей данасы арқылы қол жеткізу болып табылады. Мұнда біз одометрдің көрсеткішін тікелей 23-ке орнаттық:


        class Car:
            --snip/код үзіндісі--
        
        my_new_car = Car('audi', 'a4', 2024)
        print(my_new_car.get_descriptive_name())
        
        my_new_car.odometer_reading = 23
        my_new_car.read_odometer()

Біз көліктің odometr_reading атрибутына қол жеткізу және оның мәнін тікелей орнату үшін нүкте белгісін қолданамыз. Бұл жол Python-ға my_new_car данасын алуды, онымен байланысты odometer_reading атрибутын табуды және сол атрибуттың мәнін 23 мәніне орнатуды айтады:


        2024 Audi A4
        This car has 23 miles on it.

Кейде осындай атрибуттарға тікелей қол жеткізгіңіз келеді, бірақ басқа уақытта сіз үшін мәнді жаңартатын әдісті жазғыңыз келеді.

Атрибуттың мәнін әдіс арқылы өзгерту

Сіз үшін белгілі бір атрибуттарды жаңартатын әдістердің болуы пайдалы болуы мүмкін. Атрибутқа тікелей қол жеткізудің орнына, жаңа мәнді жаңартуды ішкі өңдейтін әдіске бересіз.

Міне, update_odometer() деп аталатын әдісті көрсететін мысал:


        class Car:
            --snip/код үзіндісі--
        
            def update_odometer(self, mileage):
                """Одометр көрсеткішін берілген мәнге орнатыңыз."""
                self.odometer_reading = mileage
        
        my_new_car = Car('audi', 'a4', 2024)
        print(my_new_car.get_descriptive_name())
        
         my_new_car.update_odometer(23)
        my_new_car.read_odometer()

Car-ға жалғыз өзгерту update_odometer() қосу болып табылады. Бұл әдіс жүрген жол мәнін алады және оны self.odometer_reading мәніне тағайындайды. my_new_car данасын пайдаланып, update_odometer() әдісін шақырамыз, параметріне 23-ті аргумент ретінде береміз ❶. Бұл одометр көрсеткішін 23-ке орнатады және read_odometer() көрсеткішті басып шығарады:


        2024 Audi A4
        This car has 23 miles on it.

Одометр көрсеткіші өзгертілген сайын қосымша жұмыстарды орындау үшін update_odometer() әдісін кеңейте аламыз. Ешкім одометр көрсеткішін кері қайтаруға әрекет жасамайтынына көз жеткізу үшін аздап логика қосайық:


        class Car:
            --snip/код үзіндісі--
        
            def update_odometer(self, mileage):
                """
                Одометр көрсеткішін берілген мәнге орнатыңыз.
                Егер ол одометрді кері айналдыруға әрекеттенсе, өзгертуді қабылдамаңыз.
                """
                 if mileage >= self.odometer_reading:
                    self.odometer_reading = mileage
                else:
                     print("You can't roll back an odometer!")

Енді update_odometer() атрибутты өзгерту алдында жаңа оқудың мағынасы бар-жоғын тексереді. mileage үшін берілген мән барлық жүріп өткен жол, self.odometer_reading мәнінен үлкен немесе оған тең болса, одометр көрсеткішін жаңа жүріп өткен жол мәніне дейін жаңартуға болады . Жаңа жол жүріс мәні бар мәннен аз болса, одометрді ❷ артқа айналдыру мүмкін еместігі туралы ескерту аласыз.

Атрибуттың мәнін әдіс арқылы арттыру

Кейде мүлдем жаңа мән орнатудың орнына атрибуттың мәнін белгілі бір мөлшерге арттырғыңыз келеді. Біз пайдаланылған көлікті сатып аламыз делік және оны сатып алған уақыт пен оны тіркеген уақыт арасында 100 миль жүрдік. Міне, осы қосымша соманы өткізуге және сол мәнді одометр көрсеткішіне қосуға мүмкіндік беретін әдіс:


        class Car:
            --snip/код үзіндісі--
        
            def update_odometer(self, mileage):
                --snip/код үзіндісі--
        
            def increment_odometer(self, miles):
                """Одометр көрсеткішіне берілген соманы қосыңыз."""
                self.odometer_reading += miles
        
         my_used_car = Car('subaru', 'outback', 2019)
        print(my_used_car.get_descriptive_name())
        
         my_used_car.update_odometer(23_500)
        my_used_car.read_odometer()
        
        my_used_car.increment_odometer(100)
        my_used_car.read_odometer()

Жаңа әдіс increment_odometer() бірнеше мильді алады және бұл мәнді self.odometer_reading мәніне қосады. Алдымен біз пайдаланылған көлікті жасаймыз, my_used_car ❶. update_odometer() функциясына шақыру жасап, 23_500 ❷ арқылы оның одометрін 23500 етіп орнаттық. Соңында, біз increment_odometer() деп атаймыз және оны 100 арқылы өткізіп, көлікті сатып алу мен оны тіркеу арасында жүріп өткен 100 мильді қосамыз:


        2019 Subaru Outback
        This car has 23500 miles on it.
        This car has 23600 miles on it.

Одометрді кері айналдыру үшін бұл функцияны ешкім пайдаланбауы үшін теріс өсімдерді қабылдамау үшін бұл әдісті өзгертуге болады.

Мұрагерлік

Класс жазуды бастағанда әрқашан жаңадан бастау міндетті емес. Егер сіз жазып жатқан класс сіз жазған басқа класстың ары-қарай жетілдіріліп арнайы жасақталған нұсқасы болса, inheritance/мұрагерлікті пайдалана аласыз. Бір класс екіншісінен мұра алған кезде ол бірінші класстың атрибуттары мен әдістерін қабылдайды. Бастапқы класс ата-аналық класс/parent class деп аталады, ал жаңа класс бала/child класс болып табылады. Мұрагер класс өзінің ата-аналық классының атрибуттары мен әдістерінің кез келгенін немесе барлығын иелене алады, бірақ ол өзінің жаңа атрибуттары мен әдістерін анықтауға да мүмкіндігі бар.

Child классына арналған __init__() әдісі

Бұрыннан бар классқа негізделген жаңа классты жазғанда, сіз жиі ата-аналық класстан __init__() әдісін шақырғыңыз келеді. Бұл негізгі __init__() әдісінде анықталған кез-келген атрибуттарды инициализациялайды және оларды child/бала класста қолжетімді етеді.

Мысал ретінде электромобильді үлгі етейік. Электромобиль - бұл көліктің белгілі бір түрі, сондықтан біз жаңа ElectricCar класын біз бұрын жазған Car класына негіздей аламыз. Содан кейін бізге тек электромобильдерге тән атрибуттар мен әрекеттердің кодын жазу керек болады.

Car класы жасайтын барлық нәрсені орындайтын ElectricCar класының қарапайым нұсқасын жасаудан бастайық:

electric_car.py


         class Car:
            """Көлікті көрсетудің қарапайым әрекеті."""
        
            def __init__(self, make, model, year):
                """Initialize attributes to describe a car.""
                self.make = make
                self.model = model
                self.year = year
                self.odometer_reading = 0
        
            def get_descriptive_name(self):
                """Ұқыпты пішімделген сипаттама атауын қайтарыңыз."""
                long_name = f"{self.year} {self.make} {self.model}"
                return long_name.title()
        
            def read_odometer(self):
                """Көліктің жолын көрсететін мәлімдемені басып шығарыңыз."""
                print(f"This car has {self.odometer_reading} miles on it.")
        
            def update_odometer(self, mileage):
                """Одометр көрсеткішін берілген мәнге орнатыңыз."""
                if mileage >= self.odometer_reading:
                    self.odometer_reading = mileage
                else:
                    print("You can't roll back an odometer!")
        
            def increment_odometer(self, miles):
                """Одометр көрсеткішіне берілген соманы қосыңыз."""
                self.odometer_reading += miles
        
         class ElectricCar(Car):
        """Автомобильдің электрлік көліктерге тән аспектілерін көрсету."""
        
             def __init__(self, make, model, year):
                """Ата-аналық сыныптың атрибуттарын инициализациялау."""
                 super().__init__(make, model, year)
        
        
         my_leaf = ElectricCar('nissan', 'leaf', 2024)
        print(my_leaf.get_descriptive_name())

Біз Car ❶ деп бастаймыз. Child/бала классты жасаған кезде, ата-аналық класс ағымдағы файлдың бөлігі болуы керек және файлдағы child/бала класстың алдында пайда болуы керек. Содан кейін біз child/бала классты анықтаймыз, ElectricCar ❷. Негізгі класстың атауы child/бала класстың анықтамасында жақшаға енгізілуі керек. __init__() әдісі Car данасын ❸ жасау үшін қажетті ақпаратты қабылдайды.

super() функциясы ❹ - бұл ата-аналық класстан әдісті шақыруға мүмкіндік беретін арнайы функция. Бұл жол Python-ға __init__() әдісін Car ішінен шақыруды айтады, бұл ElectricCar данасына осы әдісте анықталған барлық атрибуттарды береді. super атауы ата-аналық классты суперкласс және child/бала классты қосалқы класс деп атайтын шарттан шыққан. (Parent class - superclass, child class - subclass)

Біз кәдімгі көлік жасау кезінде беретін ақпарат түрімен электромобиль жасауға тырысу арқылы мұраның дұрыс жұмыс істеп тұрғанын тексереміз. Біз ElectricCar классының данасын жасап, оны my_leaf ❺-ке тағайындаймыз. Бұл жол ElectricCar ішінде анықталған __init__() әдісін шақырады, бұл өз кезегінде Python-ға ата-аналық Car класста анықталған __init__() әдісін шақыруды ұсынады. Біз 'nissan', 'leaf' және 2024 аргументтерін береміз.

ElectricCar класында __init__()-тан басқа, электромобильге тән атрибуттар немесе әдістер әлі жоқ. Әзірге біз тек электромобильдің сәйкес Car сипаттамалары-көрсеткіштері бар екенін тексеріп жатырмыз:

2024 Nissan Leaf

ElectricCar данасы Car данасы сияқты жұмыс істейді, сондықтан енді электромобильдерге тән атрибуттар мен әдістерді анықтауды бастай аламыз.

Бала/child классына арналған атрибуттар мен әдістерді анықтау

Ата-аналық класстан мұраланған child/бала класс болғаннан кейін, child/бала классты ата-аналық класстан ажырату үшін қажетті кез-келген жаңа атрибуттар мен әдістерді қосуға болады.

Электромобильдерге (мысалы, аккумулятор) тән атрибутты және осы атрибут туралы есеп беру әдісін қосамыз. Біз батарея өлшемін сақтаймыз және батареяның сипаттамасын басып шығаратын әдісті жазамыз:


        class Car:
            --snip/код үзіндісі--
        
        class ElectricCar(Car):
            """Автомобильдің электрлік көліктерге тән аспектілерін көрсету."""
        
            def __init__(self, make, model, year):
                """
                Ата-аналық кластың атрибуттарын инициализациялау.
                Содан кейін электромобильге тән атрибуттарды инициализациялаңыз.
                """
              super().__init__(make, model, year)
             self.battery_size = 40
        
             def describe_battery(self):
                """Батарея өлшемін сипаттайтын мәлімдемені басып шығарыңыз."""
                print(f"This car has a {self.battery_size}-kWh battery.")
        
        my_leaf = ElectricCar('nissan', 'leaf', 2024)
        print(my_leaf.get_descriptive_name())
        my_leaf.describe_battery()

Біз self.battery_size жаңа атрибутын қосамыз және оның бастапқы мәнін 40 мәніне орнатамыз ❶ . Бұл атрибут ElectricCar классынан жасалған барлық даналармен байланыстырылады, бірақ Car даналарының ешқайсысымен байланыстырылмайды. Біз сондай-ақ батарея ❷ туралы ақпаратты басып шығаратын describe_battery() деп аталатын әдісті қосамыз. Бұл әдісті шақырғанда, біз нақты электромобильге тән сипаттаманы аламыз:


        2024 Nissan Leaf
        This car has a 40-kWh battery.

ElectricCar класын қаншалықты ерекшелеп-өзгертуге болатынына шек жоқ. Сізге қажетті дәлдік дәрежесіне дейін электромобильді модельдеу үшін қаншама атрибуттар мен әдістерді қосуға болады. Электрлік көлікке тән емес, кез-келген көлікке тиесілі болуы мүмкін атрибут немесе әдіс ElectricCar классының орнына Car классына қосылуы керек. Содан кейін Car классын пайдаланатын кез-келген адамда бұл функция да қолжетімді болады және ElectricCar классында тек электр көліктеріне тән ақпарат пен ерекшелікке арналған код болады.

Ата-ана клас әдістерін қайта анықтау

Енші/child/бала класспен модельдеуге тырысатын нәрсеге сәйкес келмейтін ата-аналық класстың кез-келген әдісін қайта анықтауға болады. Мұны істеу үшін сіз ата-аналық класста қайта анықтағыңыз келетін әдіспен бірдей атаумен child/бала класстағы әдісті анықтайсыз. Python ата-аналық класс әдісін елемейді және тек child/бала класста анықтаған әдіске назар аударады.

Car классында fill_gas_tank() деп аталатын әдіс болды делік. Бұл әдіс толығымен электрлік көлік үшін мағынасыз, сондықтан сіз бұл әдісті жоққа шығарғыңыз келуі мүмкін. Мұны істеудің бір жолы:


        class ElectricCar(Car):
            --snip/код үзіндісі--
        
            def fill_gas_tank(self):
                """Электромобильдерде жанармай құятын цистерналар жоқ."""
                print("This car doesn't have a gas tank!")

Енді біреу электр көлігімен fill_gas_tank() қызметіне қоңырау шалуға әрекеттенсе, Python Car ішіндегі fill_gas_tank() әдісін елемейді және орнына осы кодты іске қосады. Мұрагерлікті пайдаланған кезде, бала класстарына қажет нәрсені сақтап қалуға және ата-аналық класстағы қажет емес нәрселердің барлығын қайта анықтауға болады.

Атрибуттар ретінде даналарды қолдану

Нақты әлемнен бірдеңені кодта модельдеу кезінде классқа көбірек мәліметтер қосып жатқаныңызды байқауыңыз мүмкін. Сізде атрибуттар мен әдістердің өсіп келе жатқан тізімі бар екенін және файлдарыңыз ұзарып бара жатқанын көресіз. Мұндай жағдайларда бір класстың бөлігі бөлек класс ретінде жазылуы мүмкін екенін түсінуіңіз мүмкін. Үлкен классты бірге жұмыс істейтін кішірек класстарға бөлуге болады; бұл тәсіл композиция деп аталады.

Мысалы, ElectricCar классына егжей-тегжейлі қосуды жалғастырсақ, көлік батареясына тән көптеген атрибуттар мен әдістерді қосып жатқанымызды байқаймыз. Бұл жағдайды көргенде, біз тоқтап, сол атрибуттар мен әдістерді Батарея деп аталатын бөлек классқа жылжыта аламыз. Содан кейін біз ElectricCar классында атрибут ретінде Battery данасын пайдалана аламыз:


        class Car:
            --snip/код үзіндісі--
        
        class Battery:
            """Электрокөлік үшін аккумуляторды үлгілеудің қарапайым әрекеті."""
        
             def __init__(self, battery_size=40):
                """Батареяның атрибуттарын инициализациялаңыз."""
                self.battery_size = battery_size
        
             def describe_battery(self):
                """Батарея өлшемін сипаттайтын мәлімдемені басып шығарыңыз."""
                print(f"This car has a {self.battery_size}-kWh battery.")
        
        
        class ElectricCar(Car):
            """Автомобильдің электрлік көліктерге тән аспектілерін көрсету."""
        
            def __init__(self, make, model, year):
                """
                Initialize attributes of the parent class.
                Then initialize attributes specific to an electric car.
                """
                super().__init__(make, model, year)
                 self.battery = Battery()
        
        my_leaf = ElectricCar('nissan', 'leaf', 2024)
        print(my_leaf.get_descriptive_name())
        my_leaf.battery.describe_battery()

Біз Battery деп аталатын жаңа классты анықтаймыз, ол басқа класстан мұрагер емес. __init__() әдісі ❶ self-тен басқа battery_size деген бір параметрге ие. Бұл мән берілмесе, батареяның өлшемін 40 етіп орнататын қосымша параметр. describe_battery() әдісі де осы классқа жылжытылды ❷.

ElectricCar классында біз енді self.battery ❸ деп аталатын атрибутты қосамыз. Бұл жол Python жүйесіне Battery жаңа данасын (әдепкі өлшемі 40, біз мән көрсетпейтіндіктен) жасауды және сол дананы self.battery атрибутына тағайындауды айтады. Бұл __init__() әдісі шақырылған сайын орын алады; енді кез-келген ElectricCar данасы автоматты түрде жасалған Battery данасына ие болады.

Біз электромобиль жасап, оны my_leaf айнымалысына тағайындаймыз. Біз аккумуляторды сипаттағымыз келгенде, көліктің battery атрибуты арқылы жұмыс істеуіміз керек:

my_leaf.battery.describe_battery()

Бұл жол Python-ға my_leaf данасын қарауды, оның battery атрибутын табуды және байланыстырылған describe_battery() әдісін атрибутқа тағайындалған Battery данасынан шақыруды ұсынады.

Шығыс бұрын көргенімізбен бірдей:


        2024 Nissan Leaf
        This car has a 40-kWh battery.

Бұл көп қосымша жұмыс сияқты көрінеді, бірақ енді біз ElectricCar классына кедергі келтірмей, батареяны қалағанымызша егжей-тегжейлі сипаттай аламыз. Battery параметріне батарея көлеміне негізделген көлік ауқымын есептейтін басқа әдісті қосайық:


        class Car:
            --snip/код үзіндісі--
        
        class Battery:
            --snip/код үзіндісі--
        
            def get_range(self):
                """Осы батарея беретін ауқым туралы мәлімдеме басып шығарыңыз."""
                if self.battery_size == 40:
                    range = 150
                elif self.battery_size == 65:
                    range = 225
        
                print(f"This car can go about {range} miles on a full charge.")
        
        class ElectricCar(Car):
            --snip/код үзіндісі--
        
        my_leaf = ElectricCar('nissan', 'leaf', 2024)
        print(my_leaf.get_descriptive_name())
        my_leaf.battery.describe_battery()
         my_leaf.battery.get_range()

Жаңа әдіс get_range() қарапайым талдауды орындайды. Батареяның сыйымдылығы 40 кВт сағ болса, get_range() диапазонды 150 мильге, ал сыйымдылығы 65 кВт/сағ болса, диапазонды 225 мильге орнатады. Содан кейін ол осы мәнді хабарлайды. Бұл әдісті қолданғымыз келгенде, оны көліктің battery атрибуты ❶ арқылы қайтадан шақыруымыз керек.

Шығыс аккумулятор көлеміне байланысты көліктің жүріп өте алатын жолын көрсетеді:


        2024 Nissan Leaf
        This car has a 40-kWh battery.
        This car can go about 150 miles on a full charge.

Нақты әлемдегі нысандарды модельдеу

Электромобильдер сияқты күрделірек заттарды модельдей бастағанда, сіз қызықты сұрақтармен күресетін боласыз. Электрлік көліктің жүріп өте алатын жолы аккумулятордың немесе автомобильдің қасиеті ме? Егер біз тек бір көлікті сипаттайтын болсақ, get_range() әдісінің Battery класымен байланысын сақтау дұрыс болар еді. Бірақ егер біз өндірушінің барлық автомобильдер желісін сипаттайтын болсақ, біз get_range() параметрін ElectricCar класына жылжытқымыз келуі мүмкін. get_range() әдісі диапазонды анықтау алдында әлі де батарея көлемін тексереді, бірақ ол байланыстырылған көлік түріне тән ауқымды хабарлайды. Немесе, біз get_range() әдісінің батареямен байланысын сақтай аламыз, бірақ оған car_model сияқты параметрді бере аламыз. Содан кейін get_range() әдісі батарея өлшемі мен көлік үлгісіне негізделген жүріп өте алатын жолды хабарлайды.

Бұл сізді бағдарламашы ретінде өсуіңіздің қызықты нүктесіне әкеледі. Осындай сұрақтармен күрескен кезде сіз синтаксиске бағытталған деңгейде емес, жоғары логикалық деңгейде ойлайсыз. Сіз Python туралы емес, нақты әлемді кодта қалай көрсету туралы ойлайсыз. Осы нүктеге жеткенде, сіз нақты әлемдегі жағдайларды модельдеудің дұрыс немесе бұрыс тәсілдер жиі жоқ екенін түсінесіз. Кейбір тәсілдер басқаларына қарағанда тиімдірек, бірақ ең тиімді шешімдерді табу үшін тәжірибе қажет. Егер сіздің кодыңыз өзіңіз қалағандай жұмыс істеп тұрса, сіз жақсы жұмыс істеп жатырсыз! Әртүрлі тәсілдер арқылы кластарыңызды бөлшектеп, бірнеше рет қайта жазып жатқаныңызды байқасаңыз, көңіліңізді қалдырмаңыз. Дәл, тиімді код жазуға ұмтылу үшін барлығы осы процестен өтеді.

Класстарды импорттау

Класстарыңызға қосымша функционалдылықты қосқан сайын, мұрагерлікті және композицияны дұрыс пайдалансаңыз да, файлдарыңыз ұзағырақ болуы мүмкін. Python-ның жалпы философиясына сәйкес файлдарыңызды мүмкіндігінше "таза" ұстағыңыз келеді. Көмек көрсету үшін Python класстарды модульдерде сақтауға, содан кейін негізгі бағдарламаңызға қажет класстарды импорттауға мүмкіндік береді.

Бір ғана классты импорттау

Тек қана Car классын қамтитын модуль жасайық. Бұл мәселесін тудырады: бізде осы тарауда car.py деп аталатын файл бар, бірақ бұл модуль car.py деп аталу керек, себебі оның құрамында машинаны сипаттайтын код болады. Бұл атау мәселесін біз бұрын болған car.py файлын ауыстыра отырып, Car классын car.py деп аталатын модульде сақтау арқылы шешеміз. Енді осы модульді пайдаланатын кез-келген бағдарламаға my_car.py сияқты нақтырақ файл атауы қажет болады. Міне, Car класындағы код бар car.py файлы:

car.py


         """Көлікті көрсету үшін пайдалануға болатын класс."""
        
        class Car:
            """Көлікті көрсетудің қарапайым әрекеті."""
        
            def __init__(self, make, model, year):
                """Көлікті сипаттау үшін атрибуттарды инициализациялау."""
                self.make = make
                self.model = model
                self.year = year
                self.odometer_reading = 0
        
            def get_descriptive_name(self):
                """Ұқыпты пішімделген сипаттама атауын қайтарыңыз."""
                long_name = f"{self.year} {self.make} {self.model}"
                return long_name.title()
        
            def read_odometer(self):
                """Көліктің жолын көрсететін мәлімдемені басып шығарыңыз."""
                print(f"This car has {self.odometer_reading} miles on it.")
        
            def update_odometer(self, mileage):
                """
                Set the odometer reading to the given value.
                Reject the change if it attempts to roll the odometer back.
                """
                if mileage >= self.odometer_reading:
                    self.odometer_reading = mileage
                else:
                    print("You can't roll back an odometer!")
        
            def increment_odometer(self, miles):
                """Одометр көрсеткішіне берілген соманы қосыңыз."""
                self.odometer_reading += miles

Осы модульдің мазмұнын қысқаша сипаттайтын модуль деңгейіндегі құжат-жолын/docstring қосамыз ❶. Сіз жасаған әрбір модуль үшін құжат-жолын жазуыңыз керек.

Енді біз my_car.py деп аталатын бөлек файл жасаймыз. Бұл файл Car классын импорттайды, содан кейін сол класстан дананы жасайды:

my_car.py


         from car import Car
        
        my_new_car = Car('audi', 'a4', 2024)
        print(my_new_car.get_descriptive_name())
        
        my_new_car.odometer_reading = 23
        my_new_car.read_odometer()

import операторы ❶ Python-ға car модулін ашуға және Car класын импорттауға команда береді. Енді біз Car класын осы файлда анықталғандай пайдалана аламыз. Шығару біз бұрын көргендей нәтиже береді:


        2024 Audi A4
        This car has 23 miles on it.

Класстарды импорттау - бағдарламалаудың тиімді жолы. Егер бүкіл Car класы қосылған болса, бұл бағдарлама файлының қанша уақытқа созылатынын елестетіңіз. Оның орнына классты модульге жылжытқанда және модульді импорттағанда, сіз бәрібір бірдей функцияларды аласыз, бірақ негізгі бағдарлама файлыңызды таза және оқуға оңай сақтайсыз. Сіз логиканың көп бөлігін бөлек файлдарда сақтайсыз; кластарыңыз өзіңіз қалағандай жұмыс істегеннен кейін, бұл файлдарды жалғыз қалдырып, негізгі бағдарламаңыздың жоғары деңгейлі логикасына назар аударуыңызға болады.

Модульде бірнеше класстарды сақтау

Сіз бір модульде қанша қажет болса, сонша классты сақтай аласыз, дегенмен модульдегі әрбір класс өзара байланысты болуы керек. Battery және ElectricCar класстарының екеуі де автомобильдерді көрсетуге көмектеседі, сондықтан оларды car.py модуліне қосайық.

car.py


        """Газбен және электрмен жүретін көліктерді көрсету үшін қолданылатын кластар жинағы."""
        
        class Car:
            --snip/код үзіндісі--
        
        class Battery:
            """Электрокөлік үшін аккумуляторды үлгілеудің қарапайым әрекеті."""
        
            def __init__(self, battery_size=40):
                """Батареяның атрибуттарын инициализациялаңыз."""
                self.battery_size = battery_size
        
            def describe_battery(self):
                """Батарея өлшемін сипаттайтын мәлімдемені басып шығарыңыз."""
                print(f"This car has a {self.battery_size}-kWh battery.")
        
            def get_range(self):
                """Осы батарея беретін ауқым туралы мәлімдеме басып шығарыңыз."""
                if self.battery_size == 40:
                    range = 150
                elif self.battery_size == 65:
                    range = 225
        
                print(f"This car can go about {range} miles on a full charge.")
        
        class ElectricCar(Car):
            """Электрлік көліктерге тән автокөлік үлгілері аспектілері."""
        
            def __init__(self, make, model, year):
                """
                Initialize attributes of the parent class.
                Then initialize attributes specific to an electric car.
                """
                super().__init__(make, model, year)
                self.battery = Battery()

Енді біз my_electric_car.py деп аталатын жаңа файл жасай аламыз, ElectricCar класын импорттай аламыз және электромобиль жасай аламыз:

my_electric_car.py


        from car import ElectricCar
        
        my_leaf = ElectricCar('nissan', 'leaf', 2024)
        print(my_leaf.get_descriptive_name())
        my_leaf.battery.describe_battery()
        my_leaf.battery.get_range()

Бұл кодта логиканың көп бөлігі модульде жасырылған болса да, біз бұрын көрген нәтижеге ие:


        2024 Nissan Leaf
        This car has a 40-kWh battery.
        This car can go about 150 miles on a full charge.

Модульден бірнеше класстарды импорттау

Бағдарлама файлына қанша қажет болса, сонша классты импорттай аласыз. Егер біз бір файлда кәдімгі автомобильді және электромобильді жасағымыз келсе, екі классты да импорттауымыз керек: Car және ElectricCar:

my_cars.py


         from car import Car, ElectricCar
        
         my_mustang = Car('ford', 'mustang', 2024)
        print(my_mustang.get_descriptive_name())
         my_leaf = ElectricCar('nissan', 'leaf', 2024)
        print(my_leaf.get_descriptive_name())

Әр классты ❶ үтірмен бөлу арқылы модульден бірнеше классты импорттайсыз. Қажетті класстарды импорттағаннан кейін, қажетінше әр класстың даналарын жасай аласыз.

Бұл мысалда біз газбен жұмыс істейтін Ford Mustang ❷, содан кейін электрлік Nissan Leaf ❸ жасаймыз:


        2024 Ford Mustang
        2024 Nissan Leaf

Модульді толықтай импорттау

Сонымен қатар сіз модульді толықтай импорттай аласыз, содан кейін нүкте белгісін пайдаланып қажетті класстарға қол жеткізе аласыз. Бұл тәсіл қарапайым және оңай оқылатын кодты береді. Класс данасын жасайтын әрбір шақыру модуль атауын қамтитындықтан, сізде ағымдағы файлда қолданылған атаулармен атау қайшылықтары болмайды.

Мысалы car модулін толық импорттап, содан кейін кәдімгі көлік пен электромобильді жасау келесідей көрінеді:

my_cars.py


         import car
        
         my_mustang = car.Car('ford', 'mustang', 2024)
        print(my_mustang.get_descriptive_name())
        
         my_leaf = car.ElectricCar('nissan', 'leaf', 2024)
        print(my_leaf.get_descriptive_name())

Алдымен біз бүкіл car модулін ❶ импорттаймыз. Содан кейін біз қажетті класстарға module_name.ClassName синтаксисі арқылы қол жеткіземіз. Біз қайтадан Ford Mustang ❷ және Nissan Leaf ❸ жасаймыз.

Модульден барлық класстарды импорттау

Келесі синтаксисті пайдаланып модульден барлық классты импорттай аласыз:

from module_name import *

Бұл әдіс екі себепке байланысты ұсынылмайды. Біріншіден, файлдың жоғарғы жағындағы import амалдарын оқып, бағдарламаның қай класстарды қолданатынын нақты түсіну пайдалы. Бұл тәсілмен модульде қандай класстарды пайдаланып жатқаныңыз түсініксіз. Бұл тәсіл файлдағы атаулармен шатастыруға да әкелуі мүмкін. Егер сіз бағдарлама файлындағы басқа нәрсемен бірдей атпен классты кездейсоқ импорттасаңыз, диагностикасы қиын қателер жасай аласыз. Бұл жерде көрсетілген себебі, бұл тәсілді қолданбасаңыз да, оны бір сәтте басқа адамдардың кодында көруіңіз мүмкін.

Модульден көптеген класстарды импорттау қажет болса, толық модульді импорттап, module_name.ClassName синтаксисін пайдаланған дұрыс. Сіз файлдың жоғарғы жағында қолданылатын барлық класстарды көрмейсіз, бірақ модульдің бағдарламада қай жерде қолданылатынын анық көресіз. Сондай-ақ модульдегі әрбір классты импорттау кезінде туындауы мүмкін атау қақтығыстарынан аулақ боласыз.

Модульді модульге импорттау

Кейде бір файлдың тым үлкен болып кетпеуі және бір модульде бір-бірімен байланысы жоқ класстардың сақталмауы үшін кластарыңызды бірнеше модульге таратқыңыз келеді. Класстарды бірнеше модульдерде сақтаған кезде, бір модульдегі класс басқа модульдегі классқа тәуелді екенін байқауыңыз мүмкін. Бұл орын алғанда, бірінші модульге қажетті классты импорттауға болады.

Мысалы, Car класын бір модульде, ал ElectricCar және Battery кластарын бөлек модульде сақтайық. Біз бұрын жасалған electric_car.py файлының орнына electric_car.py деп аталатын жаңа модуль жасаймыз және осы файлға тек Battery мен ElectricCar кластарын көшіреміз:

electric_car.py


        """Электромобильдерді көрсету үшін пайдалануға болатын кластар жинағы."""
        
        from car import Car
        
        class Battery:
            --snip/код үзіндісі--
        
        class ElectricCar(Car):
            --snip/код үзіндісі--

ElectricCar классына Car негізгі класы қолжетімді болуы керек, сондықтан модульге Car-ды тікелей импорттаймыз. Бұл код жолын ұмытып кетсек, Python electric_car модулін импорттауға тырысқанда қате шығарады. Сондай-ақ, Car модулін жаңарту керек, сонда ол тек Car классын қамтиды:

car.py


        """Көлікті көрсету үшін пайдалануға болатын класс."""
        
        class Car:
            --snip/код үзіндісі--

Енді біз әр модульден бөлек-бөлек импорттай аламыз және кез-келген көлік түрін жасай аламыз:

my_cars.py

from car import Car
        from electric_car import ElectricCar
        
        my_mustang = Car('ford', 'mustang', 2024)
        print(my_mustang.get_descriptive_name())
        
        my_leaf = ElectricCar('nissan', 'leaf', 2024)
        print(my_leaf.get_descriptive_name())

Біз Car-ды өз модулінен, ал ElectricCar-ды өз модулінен импорттаймыз. Содан кейін біз бір қарапайым көлік пен бір электромобиль жасаймыз. Екі көлік те дұрыс жасалған:


        2024 Ford Mustang
        2024 Nissan Leaf

Лақап аттарды пайдалану

8-тарауда көргеніңіздей, бүркеншік аттар жобаларыңыздың кодын ұйымдастыру үшін модульдерді пайдалану кезінде өте пайдалы болуы мүмкін. Сіз сондай-ақ класстарды импорттау кезінде бүркеншік аттарды пайдалана аласыз.

Мысал ретінде көптеген электромобильдер жасағыңыз келетін бағдарламаны қарастырыңыз. ElectricCar дегенді қайта-қайта теру (және оқу) жалықтыруы мүмкін. Импорттау амалынанда ElectricCar бүркеншік ат беруге болады:

from electric_car import ElectricCar as EC

Енді бұл бүркеншік атты электрлік көлік жасағыңыз келген кезде пайдалануға болады:

my_leaf = EC('nissan', 'leaf', 2024)

Модульге бүркеншік ат беруге де болады. Міне, бүркеншік атпен бүкіл electric_car модулін импорттау жолы:

import electric_car as ec

Енді осы модуль бүркеншік атын толық класс атымен пайдалануға болады:

my_leaf = ec.ElectricCar('nissan', 'leaf', 2024)

Өз жұмыс процесін табу

Көріп отырғаныңыздай, Python сізге үлкен жобада кодты құрылымдау жолының көптеген нұсқаларын береді. Жобаларды ұйымдастырудың ең жақсы жолдарын анықтау, сондай-ақ басқа адамдардың жобаларын түсіну үшін осы мүмкіндіктердің барлығын білу маңызды.

Сіз бастаған кезде код құрылымын қарапайым ұстаңыз. Барлығын бір файлда орындап көріңіз және барлығы жұмыс істегеннен кейін кластарыңызды бөлек модульдерге жылжытыңыз. Модульдер мен файлдардың өзара әрекеттесуі ұнаса, жобаны бастаған кезде класстарды модульдерде сақтап көріңіз. Жұмыс істейтін кодты жазуға мүмкіндік беретін әдісті тауып, сол жерден өтіңіз.

Python стандартты кітапханасы (The Python Standard Library).

Python стандартты кітапханасы әрбір Python орнатуымен қамтылған модульдер жинағы болып табылады. Енді сізде функциялар мен класстардың қалай жұмыс істейтіні туралы негізгі түсінік болған соң, басқа бағдарламашылар жазған модульдерді пайдалана бастай аласыз. Файлыңыздың жоғарғы жағында қарапайым import амалынан қосу арқылы стандартты кітапханадағы кез-келген функцияны немесе классты пайдалануға болады. Көптеген нақты жағдайларды модельдеуге пайдалы болатын random модулін қарастырайық.

Кездейсоқ/Random модульдегі бір қызықты функция randint() болып табылады. Бұл функция екі бүтін аргументті қабылдайды және сол сандар арасында (оның ішінде) кездейсоқ таңдалған бүтін санды қайтарады.

Міне, 1 мен 6 арасындағы кездейсоқ санды жасау жолы:


        >>> from random import randint
        >>> randint(1, 6)
        3

Тағы бір пайдалы функция - choice(). Бұл функция тізімді немесе кортежді қабылдайды және кездейсоқ таңдалған элементті қайтарады:


        >>> from random import choice
        >>> players = ['charles', 'martina', 'michael', 'florence', 'eli']
        >>> first_up = choice(players)
        >>> first_up
        'florence'

Қауіпсіздікке қатысты қосымшаларды жасау кезінде random модулін пайдаланбау керек, бірақ ол көптеген қызықты және ойын жобалар үшін жақсы жұмыс істейді.

Кластарды жазу стилі

Класстарға қатысты бірнеше сәндеу мәселелерін нақтылаған жөн, әсіресе сіздің бағдарламаларыңыз күрделене түскен сайын.

Класс атаулары CamelCase ішінде жазылуы керек. Мұны істеу үшін атаудағы әрбір сөздің бірінші әрпін бас әріппен жазыңыз және астын сызуды пайдаланбаңыз. Дана/instance және модуль атаулары сөздердің арасында астын сызу арқылы кіші әріппен жазылуы керек.

Әр класста класс анықтамасынан кейін бірден құжат-жолы/docstring болуы керек. Құжат тізбегі класс не істейтінінің қысқаша сипаттамасы болуы керек және сіз функцияларда құжат жолдарын жазу үшін пайдаланған пішімдеу конвенцияларын орындауыңыз керек. Әрбір модульде модульдегі класстарды не үшін пайдалануға болатынын сипаттайтын құжат жолы болуы керек.

Кодты ұйымдастыру үшін бос жолдарды пайдалануға болады, бірақ оларды шамадан тыс пайдаланбаңыз. Класс ішінде әдістер арасында бір бос жолды, ал модульде класстарды бөлу үшін екі бос жолды пайдалануға болады.

Стандартты кітапханадан және сіз жазған модульден модульді импорттау қажет болса, алдымен стандартты кітапхана модулі үшін импорттау амалынан орналастырыңыз. Содан кейін сіз жазған модуль үшін бос жолды және импорттау амалынан қосыңыз. Бірнеше импорт амалы бар бағдарламаларда бұл конвенция бағдарламада пайдаланылатын әртүрлі модульдердің қайдан келетінін көруді жеңілдетеді.

Қорытынды

Бұл тарауда сіз өз кластарыңызды жазуды үйрендіңіз. Сіз атрибуттарды пайдаланып класста ақпаратты сақтауды және класстарыңызға қажетті ерекшелік-сипаттама беретін әдістерді жазуды үйрендіңіз. Сіз дәл өзіңіз қалаған атрибуттармен класстарыңыздан даналарды жасайтын __init__() әдістерін жазуды үйрендіңіз. Сіз дананың атрибуттарын тікелей және әдістер арқылы қалай өзгерту керектігін көрдіңіз. Мұрагерлік бір-бірімен байланысты класстарды жасауды жеңілдететінін білдіңіз және әр классты қарапайым ету үшін бір класстың даналарын басқа класста атрибут ретінде пайдалануды үйрендіңіз.

Класстарды модульдерде сақтау және қажет класстарды олар пайдаланылатын файлдарға импорттау жобаларыңызды қалай реттелген сақтай алатынын көрдіңіз. Сіз Python стандартты кітапханасы туралы біле бастадыңыз және random модуліне негізделген мысалды көрдіңіз. Соңында, сіз Python конвенцияларын пайдаланып кластарыңызды стильдеуді үйрендіңіз.

10-тарауда сіз файлдармен жұмыс істеуді үйренесіз, осылайша бағдарламада жасаған жұмысыңызды және қолданушыларға жасауға мүмкіндік берген жұмыстарды сақтай аласыз. Сондай-ақ, сіз қателіктер туындаған кезде жауап беруге көмектесетін арнайы Python классы exceptions/ерекшеліктер туралы біле аласыз.

Файлдар және қателер

ITUniver

10
Файлдар және қателер

Қарапайым, дұрыс ұйымдастырылған кішкентай бағдарламаларды жазу үшін қажет негізгі-бастапқы білімді игергеннен кейін, бағдарламаларыңызды бұрынғыдан да тиімді және қолдануға ыңғайлы ету туралы ойланатын кез келді. Бұл тарауда сіз файлдармен жұмыс істеуді үйренесіз, осылайша бағдарламалар көп деректерді жылдам талдай алады.

Бағдарламалар күтпеген жағдайларға тап болған кезде бұзылып қалмауы үшін қателерді өңдеуді үйренесіз. Сіз Python бағдарламасының жұмыс барысында пайда болатын қателерді басқару үшін жасалатын арнайы нысандар болып табылатын exceptions/ерекшеліктер туралы біле аласыз. Сондай-ақ, бағдарлама жұмысы тоқтаған кезде жоғалып кетпеу үшін пайдаланушы деректерін сақтауға мүмкіндік беретін json ('джейсон) модулі туралы біле аласыз.

Файлдармен жұмыс істеуді және деректерді сақтауды үйрену адамдардың бағдарламаларыңызды қолдануын жеңілдетеді. Пайдаланушылар қандай деректерді енгізу керектігін және оны қашан енгізу керектігін таңдай алады. Адамдар сіздің бағдарламаңызды іске қосып, керекті уақыт жұмыс жасай алады, содан кейін бағдарламаны жауып, кейін қайта қосса тоқтаған жерінен жалғастыра алады. Ерекшеліктерді өңдеуді үйрену файлдар жоқ жағдайларды шешуге және бағдарламаларыңыздың бұзылуына әкелетін басқа мәселелерді шешуге көмектеседі. Бұл байқаусызда жасалған қателерден немесе бағдарламаларды бұзуға жасалған арнайы зиянды әрекеттерден туындайтын нашар деректерге тап болған кезде бағдарламаларыңызды сенімдірек етеді. Осы тарауда үйренетін дағдылардың арқасында сіз бағдарламаларыңызды қолдануға ыңғайлы, қолдануға жарамды және тұрақтырақ етесіз.

Файлдан оқу

Мәтіндік файлдарда деректердің керемет көлемі қолжетімді. Мәтіндік файлдарда ауа райы деректері, жол қозғалысы туралы деректер, әлеуметтік-экономикалық деректер, әдеби шығармалар және т.б. болуы мүмкін. Файлдан оқу әсіресе деректерді талдау (data analysys) қолданбаларында пайдалы, сонымен қатар ол файлда сақталған ақпаратты талдағыңыз немесе өзгерткіңіз келетін кез-келген жағдайға да қатысты. Мысалы, мәтіндік файлдың мазмұнын оқитын және оны браузерде әдемілеп-пішімдеп көрсетуге мүмкіндік беретін бағдарламаны жазуға болады.

Мәтіндік файлдағы ақпаратпен жұмыс істегіңіз келсе, бірінші қадам файлды жадқа оқу болып табылады. Содан кейін файлдың барлық мазмұнымен бірден немесе жеке қатар-қатарымен талдап жұмыс істесеңіз болады.

Файлдың мазмұнын оқу

Бастау үшін бізге бірнеше мәтін жолы бар файл қажет. Біз pi-дің алғашқы 30 ондық бөлшек санынан бастайық, әр жолда 10 бөлшек саны болсын:

pi_digits.txt


          3.1415926535
          8979323846
          2643383279

Келесі мысалдарды өзіңіз де жасап көру үшін осы жолдарды редакторға енгізіп, файлды pi_digits.txt ретінде, осы тараудың бағдарламалары сақталатын каталогта сақтаңыз.

Міне, осы файлды ашатын, оны оқитын және файлдың мазмұнын экранға басып шығаратын бағдарлама:

file_reader.py


        from pathlib import Path
        
         path = Path('pi_digits.txt')
         contents = path.read_text()
        print(contents)

Файлдың мазмұнымен жұмыс істеу үшін Python-ға файлдың жолын айтуымыз керек. Path/жол - жүйедегі файл немесе каталогтың нақты орны. Python сіз немесе бағдарлама пайдаланушылары қай операциялық жүйемен жұмыс істейтініне қарамастан, файлдармен және каталогтармен жұмыс істеуді жеңілдететін pathlib деп аталатын модульді ұсынады. Осы сияқты арнайы функционалдылықты қамтамасыз ететін модуль жиі library/кітапхана деп аталады, сондықтан pathlib деп аталады.

Біз Path классын pathlib ішінен импорттаудан бастаймыз. Файлға нұсқайтын Path нысанымен көп нәрсе жасауға болады. Мысалы, онымен жұмыс жасамас бұрын оның бар-жоғын тексеруге, файлдың мазмұнын оқуға немесе файлға жаңа деректерді жазуға болады. Мұнда біз pi_digits.txt файлын көрсететін Path нысанын жасаймыз, оны path ❶ айнымалысына тағайындаймыз. Бұл .txt файл біз жазып жатқан .py файлымен бір каталогта сақталғандықтан, файлға қатынасу үшін Path-қа тек файл атауы қажет.

Бізде pi_digits.txt-ты ұсынатын Path нысаны болғаннан кейін, файлдың барлық мазмұнын оқу үшін read_text() әдісін қолданамыз. ❷. Файлдың мазмұны бір тіркес ретінде қайтарылады, біз оны contents айнымалысына тағайындаймыз. contents мәнін басып шығарғанда, біз мәтіндік файлдың барлық мазмұнын көреміз:


          3.1415926535
          8979323846
          2643383279
        
        

Бұл шығыс пен түпнұсқа файл арасындағы жалғыз айырмашылық - шығыстың соңындағы қосымша бос жол. Бұл бос жолдың пайда болу себебі read_text() файлдың соңына жеткенде бос тіркесті қайтарады; бұл бос тіркес бос жол ретінде көрсетіледі.

Біз қосымша бос тіркесті rstrip() арқылы contents жолында жоюға болады:


        from pathlib import Path
        
        path = Path('pi_digits.txt')
        contents = path.read_text()
        contents = contents.rstrip()
        print(contents)

2-тараудан Python бағдарламасының rstrip() әдісі тіркестің оң жақтағы бос орын таңбаларын жояды немесе алып тастайтынын еске түсіріңіз. Енді шығыс түпнұсқа файлдың мазмұнына дәл сәйкес келеді:


          3.1415926535
          8979323846
          2643383279

Файлдың мазмұнын оқығанда, read_text() шақырғаннан кейін бірден rstrip() әдісін қолдану арқылы соңғы жаңа жол таңбасын алып тастай аламыз:

contents = path.read_text().rstrip()

Бұл жол Python-ға біз жұмыс істеп жатқан файлдағы read_text() әдісін шақыруды айтады. Содан кейін ол rstrip() әдісін read_text() қайтаратын жолға қолданады. Содан кейін тазартылған жол contents айнымалысына тағайындалады. Бұл тәсіл әдіс тізбегі/method chain деп аталады және оның бағдарламалауда жиі қолданылатынын көресіз.

Салыстырмалы және абсолютті файл жолдары

Сіз Path әдісіне pi_digits.txt сияқты қарапайым файл атауын берген кезде, Python қазір орындалып жатқан файл (яғни .py бағдарлама файлы орындалып жатқан) каталогты іздейді.

Кейде жұмысыңызды қалай ұйымдастырғаныңызға байланысты ашқыңыз келетін файл бағдарлама файлымен бірдей каталогта болмайды. Мысалы, .py бағдарлама файлдарын python_work деп аталатын каталогта сақтауға болады; python_work ішінде бағдарлама файлдарын олар өңдеп жатқан мәтіндік файлдардан ажырату үшін text_files деп аталатын басқа каталог болуы мүмкін. Енді text_files каталогы python_work каталогы ішінде болса да, text_files каталогы ішіндегі файлдың атын Path-қа құр өзін бере салу жұмыс істемейді, өйткені Python тек python_work ішіне қарайды және сонда тоқтайды; ол жалғаспайды және text_files каталогының ішін іздемейді. Python-ды бағдарлама файлы сақталған каталогтан басқа каталогтан файлдарды ашу үшін алу үшін дұрыс жолды көрсету керек.

Бағдарламалауда жолды анықтаудың екі негізгі жолы бар. Салыстырмалы файл жолы Python-ға ағымдағы іске қосылған бағдарлама файлы сақталатын каталогқа қатысты берілген орынды іздеуге нұсқайды. text_files каталогы python_work каталогы ішінде болғандықтан, бізге text_files каталогынан басталып, файл атымен аяқталатын жолды құру керек. Жолды қалай құру керек міне көрсетілген:

path = Path('text_files/filename.txt')

Сонымен қатар орындалып жатқан бағдарламаның қай жерде сақталатынына қарамастан, Python-ға файлдың компьютеріңіздегі нақты қай жерде екенін айта аласыз. Бұл абсолютті файл жолы деп аталады. Егер салыстырмалы жол жұмыс істемесе, абсолютті жолды пайдалануға болады. Мысалы, егер сіз text_files каталогын python_work каталогынан басқа каталогқа қойған болсаңыз, Path-қа мына жолды 'text_files/filename.txt' беру жұмыс істемейді, себебі Python сол орынды тек python_work ішінен іздейді. Python файлы қайда қарайтынын нақтылау үшін абсолютті жолды жазуыңыз керек.

Абсолюттік жолдар әдетте салыстырмалы жолдарға қарағанда ұзағырақ, себебі олар жүйенің түбірлік каталогынан басталады:

path = Path('/home/eric/data_files/text_files/filename.txt')

Абсолютті жолдарды пайдалану арқылы файлдарды жүйедегі кез-келген жерден оқуға болады. Әзірге файлдарды бағдарлама файлдарымен бірдей каталогта немесе бағдарлама файлдарын сақтайтын каталог ішіндегі text_files сияқты каталогта сақтау оңайырақ.

Файл жолдарын оқу

Файлмен жұмыс істегенде, файлдың әрбір жолын жиі тексергіңіз келеді. Сіз файлдағы белгілі бір ақпаратты іздеп жатқан боларсыз немесе файлдағы мәтінді қандай да бір әдіспен өзгерткіңіз келуі мүмкін. Мысалы, ауа райы деректерінің файлын оқып, сол күнгі ауа райының сипаттамасында күн сөзі бар кез-келген жолмен жұмыс істегіңіз келуі мүмкін. Жаңалықтар есебінде <headline> тегі бар кез-келген тіркесті іздеп, сол тіркесті пішімдеудің белгілі бір түрімен қайта жазуға болады.

Ұзын тіркесті жолдар жинағына айналдыру үшін splitlines() әдісін қолдануға болады, содан кейін файлдағы әрбір жолды бір-бірден тексеру үшін for циклін пайдалануға болады:

file_reader.py


        from pathlib import Path
        
        path = Path('pi_digits.txt')
         contents = path.read_text()
        
         lines = contents.splitlines()
        for line in lines:
            print(line)

Бұрынғыдай ❶ файлдың толық мазмұнын оқудан бастаймыз. Егер сіз файлдағы жеке жолдармен жұмыс істеуді жоспарласаңыз, файлды оқу кезінде бос орындарды алып тастаудың қажеті жоқ. splitlines() әдісі файлдағы барлық жолдардың тізімін қайтарады және біз бұл тізімді lines ❷ айнымалысына тағайындаймыз. Содан кейін біз осы жолдарды айналдырып, әрқайсысын басып шығарамыз:


          3.1415926535
          8979323846
          2643383279

Бірде-бір жолды өзгертпегендіктен, нәтиже бастапқы мәтіндік файлға дәл сәйкес келеді.

Файлдың мазмұнымен жұмыс істеу

Файлдың мазмұнын жадта оқығаннан кейін, бұл деректермен қалағаныңызды орындауға болады, сондықтан pi сандарын қысқаша зерттеп көрейік. Алдымен, файлдағы бос орынсыз барлық сандарды қамтитын жалғыз тіркесті құруға тырысамыз:

pi_string.py


        from pathlib import Path
        
        path = Path('pi_digits.txt')
        contents = path.read_text()
        
        lines = contents.splitlines()
        pi_string = ''
         for line in lines:
            pi_string += line
        
        print(pi_string)
        print(len(pi_string))

Біз файлды оқудан және алдыңғы мысалдағыдай тізімдегі цифрлардың әрбір жолын сақтаудан бастаймыз. Содан кейін pi сандарын ұстау үшін pi_string айнымалысын жасаймыз. Сандардың әрбір жолын pi_string-ке ❶ қосатын циклды жазамыз. Біз бұл тіркесті басып шығарамыз, сонымен қатар тіркестің ұзақтығын көрсетеміз:


        3.1415926535  8979323846  2643383279
        36

pi_string айнымалысы әр жолдағы цифрлардың сол жағындағы бос орынды қамтиды, бірақ әр жолда lstrip() арқылы одан құтылуға болады:


        --snip/код үзіндісі--
        for line in lines:
            pi_string += line.lstrip()
        
        print(pi_string)
        print(len(pi_string))

Қазір бізде pi-дың 30 бөлшек санынан тұратын тіркес бар. Тіркестің ұзындығы 32 таңба, себебі ол алдыңғы 3 саны мен ондық нүктені қамтиды:


        3.141592653589793238462643383279
        32

Үлкен файлдар: бір миллион цифр

Осы уақытқа дейін біз тек үш жолды қамтитын мәтіндік файлды талдауға назар аудардық, бірақ бұл мысалдардағы код үлкенірек файлдарда да жұмыс істейді. Егер біз 30-дың орнына pi-ден бөлшек санның 1 000 000 таңбаға дейінгі таңбаны қамтитын мәтіндік файлдан бастасақ, біз осы цифрлардың барлығын қамтитын бір тіркесті жасай аламыз. Бізге оған басқа файлды беруден басқа бағдарламамызды мүлде өзгертудің қажеті жоқ. Біз сондай-ақ алғашқы 50 ондық таңбаны ғана басып шығарамыз, сондықтан терминалда миллион цифрдың басып шығарылуын қарап отырудың қажеті жоқ:

pi_string.py


        from pathlib import Path
        
        path = Path('pi_million_digits.txt')
        contents = path.read_text()
        
        lines = contents.splitlines()
        pi_string = ''
        for line in lines:
            pi_string += line.lstrip()
        
        print(f"{pi_string[:52]}...")
        print(len(pi_string))

Шығыс бізде шын мәнінде pi - 1 000 000 ондық таңбалары бар тіркес бар екенін көрсетеді:


        3.14159265358979323846264338327950288419716939937510...
        1000002

Python-да жұмыс істеуге болатын деректер көлеміне тән шектеулер жоқ; жүйенің жады жетіп жұмыс істей алатындай көп деректермен жұмыс істей аласыз.

Туған күніңіз Pi ішінде бар ма?

"Менің туған күнім pi сандарының кез-келген жерінде кездеседі ме?" - осыны білу маған әрқашан қызықты болды. Біреудің туған күні pi-дің алғашқы миллион цифрының кез-келген жерінде көрінетінін білу үшін жаңа ғана жазған бағдарламаны қолданайық. Біз мұны әрбір туған күнді сандар тізбегі ретінде көрсету және сол тіркестің pi_string ішінде кез-келген жерде пайда болуын көру арқылы жасай аламыз:

pi_birthday.py


        --snip/код үзіндісі--
        for line in lines:
            pi_string += line.strip()
        
        birthday = input("Enter your birthday, in the form mmddyy: ")
        if birthday in pi_string:
            print("Your birthday appears in the first million digits of pi!")
        else:
            print("Your birthday does not appear in the first million digits of pi.")

Біз алдымен пайдаланушының туған күнін сұраймыз, содан кейін бұл тіркестің pi_string ішінде бар-жоғын тексереміз. Қарап көрейік:


        Enter your birthdate, in the form mmddyy: 120372
        Your birthday appears in the first million digits of pi!

Менің туған күнім pi цифрларында көрсетіледі! Файлды оқығаннан кейін оның мазмұнын ойыңызда елестете алатын кез-келген жолмен талдап-сараптай аласыз.

Файлға жазу

Деректерді сақтаудың қарапайым тәсілдерінің бірі оны файлға жазу болып табылады. Файлға мәтін жазғаннан кейін терминалды жапсаңыз да сіз жазған код пен ақпарат сақтаулы болады. Жазған файлыңызде текесріп және оны өзге бағдарламашылар не қолданушылармен бөлісе де аласыз. Сондай-ақ осы мәтінді жадқа қайта оқитын және онымен кейінірек қайта жұмыс істейтін бағдарламаларды жазуға болады.

Бір жол мәтін жазу

Файлдың сақталу жолын анықтағаннан кейін, файлға write_text() әдісі арқылы жаза аласыз. Мұның қалай жұмыс істейтінін көру үшін қарапайым хабарлама жазып, оны экранға басып шығарудың орнына файлға сақтайық:

write_message.py


        from pathlib import Path
        
        path = Path('programming.txt')
        path.write_text("I love programming.")

write_text() әдісі бір аргумент алады: файлға жазғыңыз келетін жол. Бұл бағдарламада терминал шығысы жоқ, бірақ programming.txt файлын ашсаңыз, бір жол мәтінді көресіз:

programming.txt

I love programming.

Бұл файл компьютердегі кез-келген басқа файл сияқты әрекет етеді. Оны ашуға, оған жаңа мәтін жазуға, одан көшіруге, қоюға және т.б. жасауға болады.

Бірнеше мәтін жолын жазу

write_text() әдісі бізге көрсетпей артқы фонда бірнеше әрекеттерді орындайды. path сілтеме жасайтын файл жоқ болса, ол сол файлды жасайды. Сондай-ақ, тіркесті файлға жазғаннан кейін ол файлдың дұрыс жабылғанына көз жеткізеді. Дұрыс жабылмаған файлдар деректердің жоғалуына немесе бүлінуіне әкелуі мүмкін.

Файлға бір жолдан артық жазу үшін файлдың бүкіл мазмұнын қамтитын тіркесті құрастыру керек, содан кейін сол тіркесті аргумент ретінде беріп write_text() әдісін шақыру керек. Енді programming.txt файлына бірнеше жолды жазайық:


        from pathlib import Path
        
        contents = "I love programming.\n"
        contents += "I love creating new games.\n"
        contents += "I also love working with data.\n"
        
        path = Path('programming.txt')
        path.write_text(contents)

Файлдың бүкіл мазмұнын сақтайтын contents деп аталатын айнымалы мәнді анықтаймыз. Келесі жолда осы тіркеске тағы тіркес қосу үшін += операторын қолданамыз. Осы әдісті кез-келген ұзындықтағы тіркесті жасау үшін қажетінше қайталап қолдана беруге болады. Бұл жағдайда әрбір амал өз жолында көрсетілетініне көз жеткізу үшін әр жолдың соңына жаңа жол таңбаларын қосамыз.

Оны іске қосып, programming.txt файлын ашсаңыз, мәтіндік файлда мына тіркес жолдарының әрқайсысын көресіз:


        I love programming.
        I love creating new games.
        I also love working with data.

Сонымен қатар, жазылатын мәтінді өзіңізге қажетті етіп форматтау үшін бос орындарды, tab-ты және бос жолдарды пайдалануға болады. Тіркестің ұзындығында шектеу жоқ және компьютермен жасалған құжаттардың басым көпшілігі осылай жасалады.

Exceptions

Python бағдарламаны орындау кезінде пайда болатын қателерді басқару үшін exceptions/ерекше жағдайлар/ерекшелік деп аталатын арнайы нысандарды пайдаланады. Python-ды әрі қарай не істеу керектігін білмеуге мәжбүрлейтін қате орын алған сайын, ол ерекше жағдай нысанын жасайды. Ерекше жағдайды қарастырып-өңдейтін кодты жазсаңыз, бағдарлама жұмысын жалғастырады. Ерекше жағдайды қарастырып-өңдемесеңіз, бағдарлама тоқтап, кері бақылауды көрсетеді, оған туындаған ерекшелік туралы есеп кіреді.

Ерекшеліктер try-except блоктарымен өңделеді. try-except блогы Python-нан бірдеңе жасауды сұрайды, бірақ ол сонымен қатар Python-ға ерекше жағдай туындаған жағдайда не істеу керектігін айтады. try-except блоктарын пайдаланған кезде, бағдарламалар дұрыс емес болып кетсе де жұмысын жалғастырады. Пайдаланушылар түсінуі қиын қате туралы ақпараттың орнына пайдаланушылар қате туралы ақпаратты беретін сіз жазған түсінікті хабарларды көреді.

ZeroDivisionError ерекше жағдайын өңдеу

Python-да ерекше жағдайды тудыратын қарапайым қатені қарастырайық. Санды нөлге бөлу мүмкін емес екенін білетін шығарсыз, бірақ бәрібір Python-нан мұны істеуді сұрайық:

division_calculator.py

print(5/0)

Python мұны істей алмайды, сондықтан біз traceback(кері-бақылауды) аламыз:


        Traceback (most recent call last):
          File "division_calculator.py", line 1, in <module>
            print(5/0)
                  ~^~
         ZeroDivisionError: division by zero

Бақылауда хабарланған қате, ZeroDivisionError, ❶ exceptions/ерекшелік нысаны болып табылады. Python мұндай нысанды біз сұраған нәрсені орындай алмайтын жағдайға жауап ретінде жасайды. Бұл орын алған кезде, Python бағдарламаны тоқтатады және қандай ерекшелік туындағанын айтады. Біз бұл ақпаратты бағдарламамызды өзгерту үшін пайдалана аламыз. Біз Python-ға мұндай ерекшелік орын алған кезде не істеу керектігін айтамыз; осылайша, егер бұл қайталанса, біз дайын боламыз.

try-except блогын пайдалану

Қате орын алуы мүмкін деп ойласаңыз, көтерілуі мүмкін ерекше жағдайды өңдеу үшін try-except блогын жаза аласыз. Сіз Python-ға қандай да бір кодты іске қосып көруді айтасыз және кодтың нәтижесінде ерекше жағдайдың белгілі бір түрі болса, не істеу керектігін айтасыз.

Міне, ZeroDivisionError ерекшелігін өңдеуге арналған try-except блогы келесідей болады:


        try:
            print(5/0)
        except ZeroDivisionError:
            print("You can't divide by zero!")

Біз print(5/0), қатені тудырған жолды try блогының ішіне орналастырдық. Егер try блогындағы код жұмыс істесе, Python except блогын қарастырмайды. Егер try блогындағы код қатені тудырса, Python қате туындаған try блогына сәйкес келетін except блогын іздейді және сол блоктағы кодты іске қосады.

Бұл мысалда try блогындағы код ZeroDivisionError шығарады, сондықтан Python оған қалай жауап беру керектігін көрсететін exception блогын іздейді. Содан кейін Python осы блокта кодты іске қосады және пайдаланушыға traceback-тың орнына қате туралы түсінікті хабарды көреді:

You can't divide by zero!

Егер try-except блогынан кейін қосымша код болса, бағдарлама жұмысын жалғастырады, өйткені біз Python-ға қатені қалай өңдеу керектігін айттық. Қатені анықтау бағдарламаның жұмысын жалғастыруға мүмкіндік беретін мысалды қарастырайық.

Бағдарламаның бұзылып қалуын болдырмау үшін exceptions пайдалану

Қателерді дұрыс тауып оны өңдей білу, бағдарлама қатеден кейін әлі көп код орындау керек болғанда әсіресе маңызды. Бұл пайдаланушылардан ақпарат енгізуді сұрайтын бағдарламаларда жиі орын алады. Егер бағдарлама жарамсыз енгізуге сәйкес жауап берсе, ол бұзылудың орнына дұрысырақ енгізуді сұрай алады.

Тек бөлуді орындайтын қарапайым калькуляторды жасайық:

division_calculator.py


        print("Give me two numbers, and I'll divide them.")
        print("Enter 'q' to quit.")
        
        while True:
             first_number = input("\nFirst number: ")
            if first_number == 'q':
                break
             second_number = input("Second number: ")
            if second_number == 'q':
                break
             answer = int(first_number) / int(second_number)
            print(answer)

Бұл бағдарлама пайдаланушыдан бірінші_сан ❶ енгізуді және егер пайдаланушы шығу үшін q енгізіп, ENTER басып жібермесе, екінші_сан ❷ енгізуді ұсынады. Содан кейін жауап ❸ алу үшін осы екі санды бөлеміз. Бұл бағдарлама қателерді өңдеу үшін ештеңе жасамайды, сондықтан оны нөлге бөлуді сұрау оның бұзылуына әкеледі:


        Give me two numbers, and I'll divide them.
        Enter 'q' to quit.
        
        First number: 5
        Second number: 0
        Traceback (most recent call last):
          File "division_calculator.py", line 11, in <module>
            answer = int(first_number) / int(second_number)
                     ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
        ZeroDivisionError: division by zero

Бағдарламаның бұзылғаны жаман, бірақ пайдаланушыларға кері бақылауларды көруге мүмкіндік беру де жақсы идея емес. Техникалық емес пайдаланушылар оларды шатастырады және зиянды жағдайда шабуылдаушылар сіз қалағаннан да көп нәрсені үйренеді. Мысалы, олар сіздің бағдарлама файлыңыздың атын біледі және кодыңыздың дұрыс жұмыс істемейтін бөлігін көреді. Тәжірибелі шабуылдаушы кейде бұл ақпаратты кодыңызға қарсы қолданылатын шабуыл түрлерін анықтау үшін пайдалана алады.

else код блогын жазу

Біз try-except блогында қателер тудыруы мүмкін жолды орау арқылы бұл бағдарламаны қатеге төзімді ете аламыз. Қате бөлуді орындайтын жолда орын алады, сондықтан біз осы жерге try-except блогын қоямыз. Бұл мысалда else блогы да бар. try блогының сәтті орындалуына байланысты кез-келген код else блогына кіреді:


          print("Give me two numbers, and I'll divide them.")
          print("Enter 'q' to quit.")
          
          while True:
              first_number = input("\nFirst number: ")
              if first_number == 'q':
                  break
              second_number = input("Second number: ")
              if second_number == 'q':
                  break
             try:
                answer = int(first_number) / int(second_number)
             except ZeroDivisionError:
                print("You can't divide by 0!")
             else:
                print(answer)

Біз Python-нан try блогындағы бөлу операциясын орындауға тырысуын сұраймыз ❶, ол тек қате тудыруы мүмкін кодты қамтиды. try блогындағы кодтың сәтті өтуіне тәуелді болатын кез-келген код else блогына жазылады. Бұл жағдайда бөлу операциясы сәтті болса, нәтижені басып шығару үшін else блогын қолданамыз ❸.

except блогы Python-ға ZeroDivisionError пайда болғанда, ❷ қалай жауап беру керектігін айтады. Егер try блогы нөлге бөлу қатесі себебінен сәтті болмаса, біз пайдаланушыға мұндай қатені болдырмау жолын көрсететін түсінікті хабарды басып шығарамыз. Бағдарлама жұмыс істеуді жалғастырады және пайдаланушы ешқашан кері-бақылауды көрмейді:


        Give me two numbers, and I'll divide them.
        Enter 'q' to quit.
        
        First number: 5
        Second number: 0
        You can't divide by 0!
        
        First number: 5
        Second number: 2
        2.5
        
        First number: q

try блогында болуы керек жалғыз код - бұл ерекше жағдайды тудыруы мүмкін код. Кейде сізде try блогы сәтті болған жағдайда ғана іске қосылуы керек қосымша код болады; бұл код else блогында болады. except блогы Python-ға try блогында кодты іске қосуға әрекеттенген кезде белгілі бір ерекшелік туындаған жағдайда не істеу керектігін айтады.

Қателердің ықтимал көздерін болжау арқылы, олар жарамсыз деректер мен жетіспейтін ресурстарға тап болған кезде де жұмысын жалғастыратын сенімді бағдарламаларды жаза аласыз. Кодыңыз байқаусызда жасалған пайдаланушы қателеріне және зиянды шабуылдарға төзімді болады.

FileNotFoundError ерекше жағдайын өңдеу

Файлдармен жұмыс істеу кезінде жиі туындайтын мәселелердің бірі "жоқ" файлдарды өңдеу болып табылады. Сіз іздеп жатқан файл басқа жерде болуы мүмкін, файл атауы қате жазылуы мүмкін немесе файл мүлде болмауы мүмкін. Осы жағдайлардың барлығын try-except блогымен өңдеуге болады.

Жоқ файлды оқып көрейік. Келесі бағдарлама Алиса ғажайыптар елінде ертегісі жазылған файлдың мазмұнын оқуға тырысады, бірақ мен alice.txt файлын alice.py файлымен бірге бір каталогта сақтамадым:

alice.py


        from pathlib import Path
        
        path = Path('alice.txt')
        contents = path.read_text(encoding='utf-8')

Біз read_text() функциясын бұрын көргеніңізден сәл басқаша қолданып жатқанымызды ескеріңіз. Бұл жердегі encoding аргументі жүйенің әдепкі кодтауы оқылып жатқан файлдың кодтауына сәйкес келмегенде қажет. Оның орын алуы мүмкіндігі егер сіздің оқып жатқан файлыңыз сіздің жүйеңізде жасалмаған болса тіпті мүмкін.

Python жетіспейтін файлды оқи алмайды, сондықтан ол ерекше жағдайды тудырады:


        Traceback (most recent call last):
           File "alice.py", line 4, in <module>
             contents = path.read_text(encoding='utf-8')
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
          File "/.../pathlib.py", line 1056, in read_text
            with self.open(mode='r', encoding=encoding, errors=errors) as f:
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
          File "/.../pathlib.py", line 1042, in open
            return io.open(self, mode, buffering, encoding, errors, newline)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         FileNotFoundError: [Errno 2] No such file or directory: 'alice.txt'

Бұл біз бұрын көргендерге қарағанда ұзағырақ traceback/кері-бақылау, сондықтан күрделі бақылауларды қалай түсінуге болатынын қарастырайық. Көбінесе кері қайтарудың ең соңынан бастаған дұрыс. Соңғы жолда FileNotFoundError ерекше жағдайдың ❸ туындағанын көреміз. Бұл маңызды, себебі ол біз жазатын except блогында қандай ерекшелік түрін пайдалану керектігін айтады.

Енді traceback-тың алғшқы қатарына ❶ қарайтын болсақ, қате alice.py файлындағы 4-жолда орын алғанын көреміз. Келесі жол ❷ қатені тудырған код жолын көрсетеді. Қалған бақылау файлдарды ашуға және оқуға қатысатын кітапханалардың кейбір кодын көрсетеді. Әдетте бұл жолдардың барлығындағы кері бақылауды оқып шығудың немесе түсінудің қажеті жоқ.

Туындаған қатені өңдеу үшін try блогы кері іздеуде ақаулы деп танылған жолдан басталады. Біздің мысалда бұл read_text() әдісін қамтитын жол:


        from pathlib import Path
        
        path = Path('alice.txt')
        try:
            contents = path.read_text(encoding='utf-8')
         except FileNotFoundError:
            print(f"Sorry, the file {path} does not exist.")

Бұл мысалда try блогындағы код FileNotFoundError жасайды, сондықтан біз қатесіне сәйкес келетін except блогын жазамыз. . Содан кейін файл табылмаған кезде Python сол блоктағы кодты іске қосады және нәтиже кері бақылау орнына түсінікті қате туралы хабарды береді:

Sorry, the file alice.txt does not exist.

Файл жоқ болса, бағдарлама басқа ештеңе істей алмайды, сондықтан бұл біз көретін барлық нәтиже. Осы мысалға негізделіп, бірнеше файлмен жұмыс істегенде ерекше жағдайларды өңдеу қалай көмектесетінін көрейік.

Мәтінді талдау, анализдеу

Том том кітап мәтіні жазылған өте үлкен файлдарға дейін талдауға болады. Әдебиеттің көптеген классикалық туындылары қарапайым мәтіндік файлдар ретінде қол жетімді, себебі олар қоғамдық доменде. Бұл бөлімде пайдаланылған мәтіндер Project Gutenberg (https://gutenberg.org/) сайтынан алынған. Гутенберг жобасы жалпыға қолжетімді әдеби шығармалар жинағын қолдайды және бағдарламалау жобаларыңызда әдеби мәтіндермен жұмыс істеуге қызығушылық танытсаңыз, бұл тамаша ресурс.

Келіңіз, Алиса ғажайыптар елінде мәтінін алып, мәтіндегі сөздердің санын санап көрейік. Ол үшін әдепкі бойынша тіркесті кез-келген бос орынды тапқан жерде бөлетін split() тіркес әдісін қолданамыз:


        from pathlib import Path
        
        path = Path('alice.txt')
        try:
            contents = path.read_text(encoding='utf-8')
        except FileNotFoundError:
            print(f"Sorry, the file {path} does not exist.")
        else:
            # Count the approximate number of words in the file:
             words = contents.split()
             num_words = len(words)
            print(f"The file {path} has about {num_words} words.")

Мен alice.txt файлын дұрыс каталогқа жылжыттым, сондықтан try блогы бұл жолы жұмыс істейді. Біз бір ұзын тіркес ретінде Алиса ғажайыптар елінде бүкіл мәтінін қамтитын contents тіркесін аламыз және осы тіркеске split() әдісін қолданып кітаптағы барлық сөздердің тізімін ❶ жасаймыз. Осы тізімде ❷ len() әдісін пайдалану бастапқы мәтіндегі сөздердің санын жақсы жуықтап береді. Соңында біз файлда қанша сөз табылғанын көрсететін амалды басып шығарамыз. Бұл код else блогында орналастырылған, себебі ол тек try блогындағы код сәтті орындалған жағдайда ғана жұмыс істейді.

Шығыс alice.txt ішінде қанша сөз бар екенін көрсетеді:

The file alice.txt has about 29594 words.

Санау нәтижесі түпнұсқа кітаптағы сөздер санынан кішкене ғана жоғары, себебі қосымша ақпаратты осы жерде пайдаланылған мәтіндік файлда баспагер береді, бірақ бұл Алиса ғажайыптар елінде фильмінің ұзақтығына жақсы жуықтау.

Бірнеше файлдармен жұмыс істеу

Талдау үшін көбірек кітаптарды қосамыз, бірақ мұны жасамас бұрын, осы бағдарламаның негізгі бөлігін count_words() деп аталатын функцияға жылжытайық. Бұл бірнеше кітапқа талдау жүргізуді жеңілдетеді:

word_count.py


        from pathlib import Path
        
        def count_words(path):
             """Файлдағы сөздердің шамамен санын санау."""
            try:
                contents = path.read_text(encoding='utf-8')
            except FileNotFoundError:
                print(f"Sorry, the file {path} does not exist.")
            else:
                # Count the approximate number of words in the file:
                words = contents.split()
                num_words = len(words)
                print(f"The file {path} has about {num_words} words.")
        
        path = Path('alice.txt')
        count_words(path)

Бұл кодтың көпшілігі өзгеріссіз. Ол тек шегініспен белгіленді және count_words() функция ішіне жылжытылды. Бағдарламаны өзгерткен кезде түсініктемелерді жаңартып отыру жақсы әдет, сондықтан түсініктеме де құжат жолына өзгертілді және сәл ғана өзгертілді ❶ .

Енді біз талдағымыз келетін кез-келген мәтіндегі сөздерді санау үшін қысқа цикл жаза аламыз. Мұны біз талдағымыз келетін файлдардың атауларын тізімде сақтау арқылы орындаймыз, содан кейін тізімдегі әрбір файл үшін count_words() деп атаймыз. Біз Ғажайыптар әлеміндегі Алиса, Сиддхарта, Моби Дик және Кішкентай әйелдер сөздерін санауға тырысамыз, олардың барлығы қоғамдық доменде қол жетімді. Мен siddhartha.txt файлын word_count.py бар каталогтан әдейі сырт қалдырдым, сондықтан біз бағдарламаның жетіспейтін файлды қаншалықты жақсы өңдейтінін көре аламыз:


        from pathlib import Path
        
        def count_words(filename):
            --snip/код үзіндісі--
        
        filenames = ['alice.txt', 'siddhartha.txt', 'moby_dick.txt', 
                'little_women.txt']
        for filename in filenames:
             path = Path(filename)
            count_words(path)

Файлдардың атаулары қарапайым тіркес ретінде сақталады. Одан кейін әр тіркес count_words() шақыру алдында Path нысанына ❶ түрлендіріледі. Жетіспейтін siddhartha.txt файлы бағдарламаның қалған орындалуына әсер етпейді:


        The file alice.txt has about 29594 words.
        Sorry, the file siddhartha.txt does not exist.
        The file moby_dick.txt has about 215864 words.
        The file little_women.txt has about 189142 words.

Осы мысалдағы try-except блогын пайдалану екі маңызды артықшылық береді. Біз пайдаланушыларымызға кері қайтаруды көруге жол бермейміз және бағдарламаға өзі таба алатын мәтіндерді талдауды жалғастыруға мүмкіндік береміз. Егер siddhartha.txt тудыратын FileNotFoundError қатесін ұстамасақ, пайдаланушы толық кері-бақылауды көреді және Sidhartha-ны талдау әрекетінен кейін бағдарлама жұмысын тоқтатады. Ол ешқашан Моби Дик немесе Кішкентай әйелдер-ді талдамайды.

Қателерді үнсіз-хабарсыз өткізу

Алдыңғы мысалда біз пайдаланушыларға файлдардың біреуі қолжетімсіз екенін хабарлағанбыз. Бірақ туындаған әрбір ерекше-жағдай туралы хабарлау міндетті емес. Кейде бағдарлама ерекше-жағдай орын алған кезде үнсіз бұзылуын және ештеңе болмағандай жалғастыруды қалайсыз. Бағдарламаның үнсіз істен шығуы үшін сіз әдеттегідей try блогын жазасыз, бірақ Python-ға except блогында ешнәрсе жасамау керектігін анық айтасыз. Python-да блокта ештеңе істемеу керектігін айтатын pass амалы бар:


        def count_words(path):
            """Файлдағы сөздердің шамамен санын санау."""
            try:
                --snip/код үзіндісі--
            except FileNotFoundError:
                pass
            else:
                --snip/код үзіндісі--

Бұл код жолдары мен алдыңғысының арасындағы жалғыз айырмашылық - except блогындағы pass амалы. Енді FileNotFoundError туындағанда, except блогындағы код іске қосылады, бірақ ештеңе болмайды. Қайта бақылау жасалмайды және туындаған қатеге жауап ретінде ешқандай нәтиже жоқ. Пайдаланушылар бар әрбір файл үшін сөз санын көреді, бірақ олар файл табылмады деген ақпаратты көрмейді:


        The file alice.txt has about 29594 words.
        The file moby_dick.txt has about 215864 words.
        The file little_women.txt has about 189142 words.

pass операторы да placeholder/толтырғыш ретінде әрекет етеді. Бұл сіздің бағдарламаңызды орындаудың белгілі бір нүктесінде ештеңе жасамауды таңдағаныңызды және кейінірек сол жерде бірдеңе жасағыңыз келуі мүмкін екенін еске салады. Мысалы, бұл бағдарламада біз жетіспейтін файл атауларын missing_files.txt деп аталатын файлға жазуды шешуіміз мүмкін. Біздің пайдаланушылар бұл файлды көрмейді, бірақ біз файлды оқып, кез-келген жетіспейтін мәтіндерді өңдей аламыз.

Қандай қателер туралы хабарлауды шешу

Пайдаланушыларға қате туралы қашан хабарлау керектігін және бағдарламаңыздың үнсіз бұзылып, қатені өткізіп жіберуін қалай білуге болады? Пайдаланушылар қандай мәтіндерді талдау керек екенін білсе, олар кейбір мәтіндердің неге талданбағаны туралы хабарды бағалап, пайдасына жарата алады. Ал қолданушылар не өңделіп жатқанын білсе, бірақ нәтиже қандай болуы керек екенін алдын-ала нақты білмесе, артық ақпарат беру керек емес. Пайдаланушыларға олар іздемейтін ақпаратты беру бағдарламаңыздың ыңғайлылығын төмендетуі мүмкін. Python қателерді өңдеу құрылымдары дұрыс емес жағдайда пайдаланушылармен қаншалықты бөлісуге болатынын нақты бақылауға мүмкіндік береді; қанша ақпарат бөлісетінін өзіңіз шешесіз.

Жақсы жазылған, дұрыс тексерілген код синтаксистік немесе логикалық қателер сияқты ішкі қателерге өте бейім емес. Бірақ сіздің бағдарламаңыз пайдаланушы енгізуі, файлдың болуы немесе желілік қосылымның қолжетімділігі сияқты сыртқы нәрсеге тәуелді болған сайын, ерекше жағдайдың туындау ықтималдылығы бар. Уақыт өте келетін бағдарламалау тәжірибесі бағдарламада ерекше жағдайларды өңдеу блоктарын қай жерде қосу керектігін және пайда болатын қателер туралы пайдаланушыларға қанша есеп беру керектігін білуге көмектеседі.

Деректерді сақтау

Көптеген бағдарламаларыңыз пайдаланушылардан белгілі бір ақпарат түрлерін енгізуді сұрайды. Сіз пайдаланушыларға ойында қалаған опцияларын сақтауға немесе визуализация үшін деректерді беруге рұқсат ете аласыз. Бағдарламаңыздың мақсаты қандай болса да, пайдаланушылар беретін ақпаратты тізімдер мен сөздіктер сияқты деректер құрылымдарында сақтайсыз. Пайдаланушылар бағдарламаны жапқанда, сіз әрқашан олар енгізген ақпаратты сақтағыңыз келеді. Мұны істеудің қарапайым жолы деректеріңізді json('джейсон) модулі арқылы сақтауды қамтиды.

json модулі қарапайым Python деректер құрылымдарын JSON-пішімделген тіркестерге түрлендіруге, содан кейін бағдарлама келесі рет іске қосылғанда сол файлдан деректерді жүктеуге мүмкіндік береді. Сондай-ақ әртүрлі Python бағдарламалары арасында деректерді ортақ пайдалану үшін json пайдалануға болады. Одан да кереметі, JSON деректер пішімі тек Python-ға тән емес, сондықтан сіз JSON пішімінде сақтайтын деректерді көптеген басқа бағдарламалау тілдерінде жұмыс істейтін адамдармен бөлісе аласыз. Бұл пайдалы және портативті пішім және оны үйрену оңай.

json.dumps() және json.loads() пайдалану

Сандар жиынын сақтайтын қысқа бір бөлек бағдарламаны және осы сандарды жадқа қайта оқитын басқа екінші бағдарламаны жазайық. Бірінші бағдарлама сандар жинағын сақтау үшін json.dumps() пайдаланады, ал екінші бағдарлама json.loads() пайдаланады.

json.dumps() функциясы бір аргумент алады: JSON пішіміне түрлендіру керек деректер бөлігі. Функция тіркесті қайтарады, оны кейін деректер файлына жаза аламыз:

number_writer.py


        from pathlib import Path
        import json
        
        numbers = [2, 3, 5, 7, 11, 13]
        
         path = Path('numbers.json')
         contents = json.dumps(numbers)
        path.write_text(contents)

Алдымен json модулін импорттаймыз, содан кейін жұмыс істеу үшін сандар тізімін жасаймыз. Содан кейін ❶ сандар тізімі сақталатын файл атауын таңдаймыз. Файлдағы деректердің JSON пішімінде сақталғанын көрсету үшін .json файл кеңейтімін пайдалану қалыпты жағдай. Содан кейін біз деректердің JSON көрінісін қамтитын тіркесті жасау үшін json.dumps() ❷ функциясын қолданамыз. -мен жұмыс істеп жатырмыз. Бұл тіркесті алғаннан кейін біз оны файлға бұрын қолданған write_text() әдісі арқылы жазамыз.

Бұл бағдарламаның шығысы жоқ, бірақ numbers.json файлын ашып, оны қарайық. Деректер Python сияқты көрінетін пішімде сақталады:

[2, 3, 5, 7, 11, 13]

Енді тізімді жадқа қайта оқу үшін json.loads() қолданатын бөлек бағдарлама жазамыз:

number_reader.py


        from pathlib import Path
        import json
        
         path = Path('numbers.json')
         contents = path.read_text()
         numbers = json.loads(contents)
        
        print(numbers)

Біз өзіміз жаңа жазған файлдан оқуды қамтамасыз етеміз ❶. Деректер файлы тек арнайы пішімдеу бар мәтіндік файл болғандықтан, біз оны read_text() әдісімен ❷ оқи аламыз. . Содан кейін файлдың мазмұнын json.loads() ❸ ішіне жібереміз. Бұл функция JSON-пішімделген тіркесті қабылдайды және Python нысанын (бұл жағдайда тізім) қайтарады, біз оны numbers тағайындаймыз. Соңында біз қалпына келтірілген сандар тізімін басып шығарамыз және оның number_writer.py ішінде жасалған тізіммен бірдей екенін көреміз:

[2, 3, 5, 7, 11, 13]

Бұл екі бағдарлама арасында деректерді ортақ пайдаланудың қарапайым жолы.

Пайдаланушы жасаған деректерді сақтау және оқу

Деректерді json көмегімен сақтау пайдаланушы жасаған деректермен жұмыс істегенде пайдалы, себебі пайдаланушының ақпаратын қандай да бір жолмен сақтамасаңыз, оны бағдарлама жұмысын тоқтатқанда жоғалтасыз. Бағдарламаны бірінші рет іске қосқан кезде пайдаланушыдан оның атын сұрайтын мысалды қарастырайық, содан кейін ол бағдарламаны қайта іске қосқанда оның атын есте сақтаймыз.

Пайдаланушы атын сақтаудан бастайық:

remember_me.py


        from pathlib import Path
        import json
        
         username = input("What is your name? ")
        
         path = Path('username.json')
        contents = json.dumps(username)
        path.write_text(contents)
        
         print(f"We'll remember you when you come back, {username}!")

Біз алдымен ❶ сақтау үшін пайдаланушы атын сұраймыз. Содан кейін біз жаңа ғана жинаған деректерді username.json ❷ деп аталатын файлға жазамыз. Содан кейін біз пайдаланушыға олардың ақпаратын сақтағанымыз туралы хабарды басып шығарамыз ❸:


        What is your name? Eric
        We'll remember you when you come back, Eric!

Енді аты бұрыннан сақталған пайдаланушымен сәлемдесетін жаңа бағдарламаны жазайық:

greet_user.py


        from pathlib import Path
        import json
        
         path = Path('username.json')
        contents = path.read_text()
         username = json.loads(contents)
        
        print(f"Welcome back, {username}!")

Біз ❶ деректер файлының мазмұнын оқимыз, содан кейін қалпына келтірілген файлды тағайындау үшін json.loads() пайдаланыңыз. деректер username ❷ айнымалысына. Пайдаланушы атын қалпына келтіргендіктен, пайдаланушыны жеке сәлемдесу арқылы қарсы аламыз:

Welcome back, Eric!

Осы екі бағдарламаны бір файлға біріктіру керек. Біреу remember_me.py іске қосқанда, мүмкін болса, оның пайдаланушы атын жадтан шығарып алғымыз келеді; болмаса, пайдаланушы атын сұраймыз және оны келесі жолы username.json ішінде сақтаймыз. username.json жоқ болса, тиісті жауап беру үшін біз мұнда try-except блогын жаза аламыз, бірақ оның орнына ыңғайлы файлды қолданамыз. pathlib модулінен алынған әдіс:

remember_me.py


        from pathlib import Path
        import json
        
        path = Path('username.json')
         if path.exists():
            contents = path.read_text()
            username = json.loads(contents)
            print(f"Welcome back, {username}!")
         else:
            username = input("What is your name? ")
            contents = json.dumps(username)
            path.write_text(contents)
            print(f"We'll remember you when you come back, {username}!")

Path нысандарымен қолдануға болатын көптеген пайдалы әдістер бар. exists() әдісі файл немесе каталог бар болса True мәнін, ал жоқ болса False мәнін қайтарады. Мұнда пайдаланушы атының ❶ сақталғанын білу үшін path.exists() пайдаланамыз. Егер username.json бар болса, біз пайдаланушы атын жүктеп, пайдаланушыға жеке сәлемдесуді басып шығарамыз.

Егер username.json файлы жоқ болса ❷, біз пайдаланушы атын сұраймыз және пайдаланушы енгізген мәнді сақтаймыз. Біз сондай-ақ олар қайтып келгенде есте сақтайтын таныс хабарды басып шығарамыз.

Қай блок орындалса да, нәтиже пайдаланушы аты мен сәйкес сәлемдесу болып табылады. Егер бағдарлама бірінші рет іске қосылса, нәтиже мынадай:


        What is your name? Eric
        We'll remember you when you come back, Eric!

Өзге жағдайда:


        Welcome back, Eric!

Бұл бағдарлама кемінде бір рет іске қосылғанын көретін нәтиже. Бұл бөлімдегі деректер тек бір тіркес болса да, бағдарлама JSON пішіміндегі тіркеске түрлендіруге болатын кез-келген деректермен бірдей жұмыс істейді.

Рефакторинг

Көп жағдайда сіз кодыңыз жұмыс істейтін сәтке жетесіз, бірақ кодты белгілі бір тапсырмалары бар функциялар қатарына бөлу арқылы жақсартуға болатынын байқайсыз. Бұл процесс рефакторинг деп аталады. Рефакторинг кодыңызды тазалайды, түсінуді және кеңейтуді-жетілдіруді жеңілдетеді.

Оның логикасының негізгі бөлігін бір немесе бірнеше функцияға жылжыту арқылы remember_me.py файлын қайта өңдей аламыз. remember_me.py фокусы пайдаланушымен сәлемдесу болып табылады, сондықтан барлық бар кодымызды greet_user() деп аталатын функцияға жылжытайық:

remember_me.py


        from pathlib import Path
        import json
        
        def greet_user():
             """Пайдаланушының атымен сәлемдесу."""
            path = Path('username.json')
            if path.exists():
                contents = path.read_text()
                username = json.loads(contents)
                print(f"Welcome back, {username}!")
            else:
                username = input("What is your name? ")
                contents = json.dumps(username)
                path.write_text(contents)
                print(f"We'll remember you when you come back, {username}!")
        
        greet_user()

Біз қазір функцияны пайдаланып жатқандықтан, түсініктемелерді(comments) бағдарламаның қазіргі уақытта жұмыс істеу әдісін көрсететін құжат-жолы(docstrings) ретінде қайта жазамыз ❶. Бұл файл сәл тазарақ, бірақ greet_user() функциясы пайдаланушымен сәлемдесу ғана емес, сонымен қатар ол бар болса, сақталған пайдаланушы атын шығарып алады және жоқ болса, жаңа пайдаланушы атын сұрайды.

Келіңіз, greet_user() рефакторын жасайық, сондықтан ол әртүрлі тапсырмаларды орындамайды. Сақталған пайдаланушы атын шығарып алуға арналған кодты бөлек функцияға жылжытудан бастаймыз:


        from pathlib import Path
        import json
        
        def get_stored_username(path):
             """Қол жетімді болса, сақталған пайдаланушы атын алыңыз."""
            if path.exists():
                contents = path.read_text()
                username = json.loads(contents)
                return username
            else:
                 return None
        
        def greet_user():
            """Пайдаланушының атымен сәлемдесу."""
            path = Path('username.json')
            username = get_stored_username(path)
             if username:
                print(f"Welcome back, {username}!")
            else:
                username = input("What is your name? ")
                contents = json.dumps(username)
                path.write_text(contents)
                print(f"We'll remember you when you come back, {username}!")
        
        greet_user()

Жаңа функция get_stored_username() ❶ құжат-жолында көрсетілгендей анық мақсаты бар. Бұл функция сақталған пайдаланушы атын шығарып алады және егер ол табылса, пайдаланушы атын қайтарады. get_stored_username() әдісіне жіберілген жол жоқ болса, функция None қайтарады ❷. Бұл жақсы тәжірибе: функция не күткен мәнді қайтаруы керек, не None қайтаруы керек. Бұл функцияның қайтарылатын мәнімен қарапайым сынақты орындауға мүмкіндік береді. Пайдаланушы атын шығарып алу әрекеті сәтті болса ❸, біз пайдаланушыға сәлемдесу хабарламасын басып шығарамыз және олай болмаса, біз жаңа пайдаланушы атын енгізуді сұрайтын prompt шығарамыз.

Біз greet_user() ішінен тағы бір код блогын есепке алуымыз керек. Пайдаланушы аты жоқ болса, жаңа пайдаланушы атын сұрайтын кодты осы мақсатқа арналған функцияға жылжытуымыз керек:


        from pathlib import Path
        import json
        
        def get_stored_username(path):
            """Қол жетімді болса, сақталған пайдаланушы атын алыңыз."""
            --snip/код үзіндісі--
        
        def get_new_username(path):
        """Жаңа пайдаланушы атын сұрау."""
            username = input("What is your name? ")
            contents = json.dumps(username)
            path.write_text(contents)
            return username
        
        def greet_user():
            """Пайдаланушының атымен сәлемдесу."""
            path = Path('username.json')
             username = get_stored_username(path)
            if username:
                print(f"Welcome back, {username}!")
            else:
                 username = get_new_username(path)
                print(f"We'll remember you when you come back, {username}!")
        
        greet_user()

remember_me.py бағдарламасының осы соңғы нұсқасындағы әрбір функцияның бір, анық мақсаты бар. Біз greet_user() әдісін шақырамыз және бұл функция сәйкес хабарламаны басып шығарады: ол бұрыннан бар пайдаланушыға қош келдіңіз дейді немесе жаңа пайдаланушыны қарсы алады. Бұрыннан бар қолданушыны қарысы алуды get_stored_username() ❶ әдісіне шақыру жасау арқылы жасайды, бұл әдіс сақталған пайдаланушы атын шығарып алуға ғана жауапты, ол бар болса әрине. Ал кей жағдайда, қажет болса, greet_user() әдісі жауапты get_new_username()❷ шақырады. Жұмысты бұл бөліктерге бөлу қарапайым кодты жазудың маңызды бөлігі болып табылады, оны сақтау және кеңейту оңай болады.

Қорытынды

Бұл тарауда сіз файлдармен жұмыс істеуді үйрендіңіз. Сіз файлдың бүкіл мазмұнын оқуды үйрендіңіз, содан кейін қажет болса, мазмұнды бір-бір жол арқылы өңдеуді үйрендіңіз. Сіз файлға қанша мәтін қажет болса, соншамай мәтінді жазуды үйрендіңіз. Сондай-ақ, сіз ерекше жағдайлар және бағдарламаларыңызда көретін ерекше жағдайларды қалай өңдеу керектігі туралы оқыдыңыз. Соңында сіз Python деректер құрылымдарын сақтауды үйрендіңіз, осылайша пайдаланушылар ұсынатын ақпаратты сақтай аласыз, осылайша олар бағдарламаны іске қосқан сайын қайта бастауды болдырмайды.

11-тарауда кодты тексерудің тиімді жолдарын үйренесіз. Бұл сіз әзірлеген кодтың дұрыс екеніне сенімді болуға көмектеседі және сіз жазған бағдарламаларды құруды жалғастырған кезде пайда болатын қателерді анықтауға көмектеседі.

Кодты тестілеу

ITUniver

11
Кодты тестілеу

Функцияны немесе классты жазғанда, сол код үшін сынақтарды да жаза аласыз. Тестілеу сіздің кодыңыз қабылдауға арналған енгізудің барлық түрлеріне жауап ретінде жұмыс істейтінін дәлелдейді. Тесттерді жазған кезде, сіздің кодыңыз дұрыс жұмыс істейтініне сенімді бола аласыз, уақыт өте сіздің бағдарламаларыңызды көбірек адамдар пайдалана бастайды, олардың барлығының қажеттілігін қанағаттандыратын болады. Сондай-ақ, жаңа код жолдарын қосатын болсаңыз бағдарламаңыздың бұрынғы жұмыс істеуін бұзбайтынына көз жеткізу үшін тесттер көмегімен жаңа кодты сынай аласыз. Әрбір бағдарламашы қателіктер жібереді, сондықтан пайдаланушылар қателіктерге тап болмас бұрын әр бағдарламашы өз кодын жиі тексеріп тұруы керек.

Бұл тарауда сіз pytest арқылы кодты тексеруді үйренесіз. pytest кітапханасы - бұл сізге алғашқы тесттілеу кодтарын жылдам және қарапайым жазуға көмектесетін құралдар жинағы, және уақыт өте бағдарламаңыз-жобаңыз күрделенсе pytest-тің қолдау мүмкіндігі де соншалықты артады. Python әдепкі бойынша pytest қолданбайды, сондықтан сіз сыртқы кітапханаларды орнатуды үйренесіз. Сыртқы кітапханаларды орнатып-білу сізге өзге бағдарламашылар жазған, жақсы жобаланған кодтың көптеген жиынтығын қолжетімді етеді. Бұл кітапханалар сіз жұмыс істеуге болатын жобалардың түрлерін кеңейтеді.

Сіз сынақтар жиынтығын құруды үйренесіз және әрбір енгізілетін мән нәтижесі қалаған шығысқа әкелетінін тексересіз. Сіз өткен сынақтың және өтпеген сынақтың қандай болатынын көресіз және сәтсіз тест кодыңызды жақсартуға қалай көмектесетінін білесіз. Сіз функциялар мен класстарды тексеруді үйренесіз және жоба үшін қанша сынақ жазу керектігін түсіне бастайсыз.

pip көмегімен pytest орнату

Python тілі стандартты кітапханада көптеген функционалдылықты қамтығанымен, Python әзірлеушілері үшінші тарап пакеттеріне де өте тәуелді. Үшінші тарап пакеті - бұл Python негізгі тілінен тыс әзірленген кітапхана. Кейбір танымал үшінші тарап кітапханалары ақырында стандартты кітапханаға қабылданады және осы сәттен бастап Python орнату-қондырғыларының көпшілігіне қосылады. Көбінесе бұл бастапқы қателерді түзетіп болғаннан кейін көп өзгермейтін кітапханаларда болады. Кітапханалардың бұл түрлері жалпы тілмен бірдей қарқынмен дами алады.

Бірақ көптеген бумалар/packages стандартты кітапханадан тыс сақталады, сондықтан оларды тілдің өзінен тәуелсіз уақыт кестесінде әзірлеуге болады. Бұл пакеттер Python-ның өзіне қарағанда жиі жаңартылады. Бұл pytest және біз осы кітаптың екінші жартысында қолданатын кітапханалардың көпшілігіне қатысты. Әрбір үшінші тарап пакетіне көзсіз сенбеу керек, бірақ мұндай пакеттер арқылы көптеген маңызды функционалдық мүмкіндіктер жүзеге асырылатынын білгенде жөн.

pip-ті жаңарту

Python үшінші тарап пакеттерін орнату үшін пайдаланылатын pip деп аталатын құралды қамтиды. pip сыртқы ресурстардан пакеттерді орнатуға көмектесетіндіктен, ол ықтимал қауіпсіздік мәселелерін шешу үшін жиі жаңартылып отырады. Сонымен, біз пипті жаңартудан бастаймыз.

Жаңа терминал терезесін ашыңыз және келесі пәрменді беріңіз:


        $ python -m pip install --upgrade pip
         Requirement already satisfied: pip in /.../python3.11/site-packages (22.0.4)
        --snip/код үзіндісі--
         Successfully installed pip-22.1.2

Осы пәрменнің бірінші бөлігі, python -m pip, Python-ға pip модулін іске қосуды ұсынады. Екінші бөлім, install --upgrade, pip-ке орнатылған буманы жаңартуды ұсынады. Соңғы бөлім pip қай үшінші тарап бумасын жаңарту керектігін көрсетеді. Шығарылым менің ағымдағы pip нұсқасының 22.0.4 ❶ нұсқасы осы жазу кезінде соңғы нұсқамен ауыстырылғанын көрсетеді, 22.1. 2 ❷.

Бұл пәрменді жүйеде орнатылған кез-келген үшінші тарап бумасын жаңарту үшін пайдалануға болады:

$ python -m pip install --upgrade package_name

pytest орнату

Енді бұл pip жаңартылды, біз pytest орната аламыз:


        $ python -m pip install --user pytest
        Collecting pytest
          --snip/код үзіндісі--
        Successfully installed attrs-21.4.0 iniconfig-1.1.1 ...pytest-7.x.x

Біз бұл жолы --upgrade жалауынсыз негізгі pip install пәрменін әлі де қолданамыз. Оның орнына, біз Python-ға осы пакетті тек ағымдағы пайдаланушы үшін орнатуды айтатын --user жалауын қолданамыз. Шығару pytest-тің өзі тәуелді басқа пакеттер қатарымен бірге pytest соңғы нұсқасының сәтті орнатылғанын көрсетеді.

Бұл пәрменді көптеген үшінші тарап пакеттерін орнату үшін пайдалануға болады:

$ python -m pip install --user package_name

Функцияны тестілеу

Тестілеуді үйрену үшін, тест жасайтын код жолдары қажет. Міне, аты мен тегін қабылдайтын және дұрыс пішімделген толық атын қайтаратын қарапайым функция:

name_function.py


        def get_formatted_name(first, last):
          """Ұқыпты пішімделген толық атауды жасаңыз."""
            full_name = f"{first} {last}"
            return full_name.title()

get_formatted_name() функциясы толық аты-жөнін дұрыс пішімдеп жазу үшін аты мен тегінің арасын бос орынмен біріктіреді, содан кейін бас әріппен жазады және толық атауды қайтарады. get_formatted_name() жұмыс істейтінін тексеру үшін осы функцияны пайдаланатын бағдарламаны жасайық. Мына names.py бағдарламасы пайдаланушыларға аты мен тегін енгізуге және дұрыс пішімделген толық атын көруге мүмкіндік береді:

names.py


        from name_function import get_formatted_name
        
        print("Enter 'q' at any time to quit.")
        while True:
            first = input("\nPlease give me a first name: ")
            if first == 'q':
                break
            last = input("Please give me a last name: ")
            if last == 'q':
                break
        
            formatted_name = get_formatted_name(first, last)
            print(f"\tNeatly formatted name: {formatted_name}.")

Бұл бағдарлама name_function.py ішінен get_formatted_name() импорттайды. Пайдаланушы аты-жөнін енгізіп, пішімделген толық аты-жөнін көре алады:


        Enter 'q' at any time to quit.
        
        Please give me a first name: janis
        Please give me a last name: joplin
               Neatly formatted name: Janis Joplin.
        
        Please give me a first name: bob
        Please give me a last name: dylan
                Neatly formatted name: Bob Dylan.
        
        Please give me a first name: q

Осы жасалған аты-жөннің дұрыс пішімделгенін көреміз. Бірақ біз get_formatted_name() параметрін өзгерткіміз келеді делік, осылайша ол әкесінің атын да өңдей алатын етейік. Сонымен қатар тек аты мен тегін берген жағдайда да кодымыздың бұзылмай жұмыс жасайтынына көз жеткізейік. Біз кодымызды тексеру үшін names.py файлын іске қосып, get_formatted_name() функциясын өзгерткен сайын Janis Joplin сияқты есімді енгізу арқылы тексере аламыз, бірақ бұл жалықтырып-зеріктіретін жұмысқа айналады. Бақытымызға орай, pytest функция шығысын тексеруді автоматтандырудың тиімді әдісін ұсынады. Егер get_formatted_name() функциясын сынауды автоматтандыратын болсақ, біз сынақ ретінде жазған есімдердің түрлері берілгенде функция жұмыс істейтініне әрқашан сенімді бола аламыз.

Unit tests және Test cases/сынақ жағдайлары

Бағдарламалық құралды тестілеудің алуан түрлі тәсілдері бар. Тесттің ең қарапайым түрлерінің бірі - Unit tests. Unit tests/бірлік сынағы функция әрекетінің бір нақты аспектісінің дұрыстығын тексереді. Test cases/сынақ жағдайы - бұл функцияның сіз күткен жағдайлардың толық ауқымында өз әрекетін дұрыс орындауы тиіс екенін дәлелдейтін бірлік сынақтарының жинағы.

Жақсы сынақ жағдайы функция қабылдай алатын кірістің барлық ықтимал түрлерін қарастырады және осы жағдайлардың әрқайсысын көрсететін сынақтарды қамтиды. Full coverage/толық қамтылуы бар сынақ жағдайы функцияны пайдаланудың барлық ықтимал жолдарын қамтитын бірлік сынақтарының толық ауқымын қамтиды. Үлкен жобада толық қамтуға қол жеткізу қорқынышты болуы мүмкін. Көбінесе кодыңыздың маңызды әрекеттері үшін сынақтар жазып, содан кейін жоба өте кең, көп қолданыла бастағанда ғана толық қамтуды мақсат етуге болады.

Өту сынағы

pytest көмегімен өзіңіздің бірінші Unit сынағын жазу өте оңай. Біз жалғыз тесттілеу функциясын жазамыз. Сынақ функциясы біз сынап жатқан функцияны шақырады және біз қайтарылған мән туралы қорытынды-тұжырым жасаймыз. Біздің қорытынды-тұжырым дұрыс болса, сынақтан өтеді; егер қорытынды-тұжырым дұрыс болмаса, сынақ сәтсіз болады.

Міне, get_formatted_name() функциясының бірінші сынағы:

test_name_function.py


        from name_function import get_formatted_name
        
         def test_first_last_name():
            """"Джанис Джоплин" сияқты атаулар жұмыс істей ме?"""
             formatted_name = get_formatted_name('janis', 'joplin')
             assert formatted_name == 'Janis Joplin'

Сынақты іске қоспас бұрын, осы функцияны толығырақ қарастырайық. Сынақ файлының атауы маңызды; ол test_ деп басталуы керек. Біз pytest-тен біз жазған сынақтарды орындауды сұраған кезде, ол test_ деп басталатын кез-келген файлды іздейді және сол файлда тапқан барлық сынақтарды орындайды.

Сынақ файлында біз алдымен тексергіміз келетін функцияны импорттаймыз: get_formatted_name(). Содан кейін сынақ функциясын анықтаймыз: бұл жағдайда test_first_last_name() ❶. Бұл арнайы себеппен біз қолданып жүрген функциядан ұзағырақ атау. Біріншіден, сынақ функциялары test сөзінен басталып, астын сызу керек. test_ деп басталатын кез-келген функция pytest арқылы ашылады және тестілеу процесінің бөлігі ретінде іске қосылады.

Сонымен қатар сынақ атаулары әдеттегі функция атауына қарағанда ұзағырақ және сипаттамалы болуы керек. Сіз ешқашан функцияны өзіңіз шақырмайсыз; pytest функцияны тауып, оны сіз үшін іске қосады. Сынақ функциясының атаулары сынақ есебінде функция атауын көрсеңіз, қандай әрекет тексеріліп жатқанын жақсы түсіну үшін жеткілікті ұзын болуы керек.

Келесі, біз сынап жатқан функцияны ❷ шақырамыз. Мұнда біз names.py іске қосқан кезде пайдаланғанымыздай, 'janis' және 'joplin' аргументтерімен get_formatted_name() функциясын шақырамыз. Бұл функцияның қайтару мәнін formatted_name мәніне тағайындаймыз.

Соңында, ❸ қорытынды-тұжырым/assertion жасаймыз. assertion/қорытынды-тұжырым - бұл шартқа қойылатын талап. Мұнда біз formatted_name мәні 'Janis Joplin' болуы керек деп талап қоямыз.

Сынақты іске қосу

Егер test_name_function.py файлын тікелей іске қоссаңыз, ешқандай нәтиже алмайсыз, өйткені біз ешқашан сынақ функциясын шақырмағанбыз. Оның орнына, сынақ файлын pytest біз үшін іске қосып беруі керек.

Ол үшін терминал терезесін ашып, сынақ файлы бар каталогқа өтіңіз. VS Code редакторын пайдаланып жатсаңыз, сынақ файлы бар каталогты ашып, VS Code редактор терезесіне ендірілген терминалды пайдалануға болады. Терминал терезесінде pytest пәрменін енгізіңіз. Сіз мынаны көруіңіз керек:


        $ pytest
        ========================= test session starts =========================
         platform darwin -- Python 3.x.x, pytest-7.x.x, pluggy-1.x.x
         rootdir: /.../python_work/chapter_11
         collected 1 item
        
         test_name_function.py .                                          [100%]
        ========================== 1 passed in 0.00s ==========================

Осы нәтижені түсінуге тырысайық. Ең алдымен, біз ❶ сынақ орындалатын жүйе туралы кейбір ақпаратты көреміз. Мен мұны macOS жүйесінде сынап жатырмын, сондықтан сіз мұндағыдан аздап өзге нәтиже көруіңіз мүмкін. Ең бастысы, сынақты іске қосу үшін Python, pytest және басқа пакеттердің қандай нұсқалары қолданылып жатқанын көре аламыз.

Одан кейін, ❷ сынақ қай каталог ішінен орындалатын көреміз: менің жағдайда, python_work/chapter_11. pytest ❸ іске қосу үшін бір сынақ файлын тапқанын және ❹ орындалып жатқан сынақ файлы қайсы екенін көре аламыз. Файл атауынан кейінгі жалғыз нүкте бір-сынақ өткенін айтады, ал 100% барлық сынақтардың орындалғанын көрсетеді. Үлкен жобада жүздеген немесе мыңдаған сынақтар болуы мүмкін, ал нүктелер мен пайыздық орындалу көрсеткіші сынақтың жалпы барысын бақылауға көмектесуі мүмкін.

Соңғы жол бір сынақтан өткенін және сынақты орындауға 0,01 секундтан аз уақыт кеткенін айтады.

Бұл шығыс-нәтиже функцияны өзгертпейінше, get_formatted_name() функциясы әрқашан аты мен тегі бар есімдер үшін жұмыс істейтінін көрсетеді. get_formatted_name() өзгерткенде, біз бұл сынақты қайта іске қоса аламыз. Егер сынақтан өтсе, функция Джанис Джоплин сияқты есім үшін әлі де жұмыс істейтінін білеміз.

Сәтсіз сынақ

Сәтсіз сынақ қандай болады? get_formatted_name() функциясын өзгертейік, осылайша ол әкесінің атын өңдей алады, бірақ Джанис Джоплин сияқты аты мен тегі ғана берілген есімдер осы функцияны бұзатындай етіп жасайық.

Міне, get_formatted_name() функциясының әкесінің аты аргументін қажет ететін жаңа нұсқасы:

name_function.py


        def get_formatted_name(first, middle, last):
            """Ұқыпты пішімделген толық атауды жасаңыз."""
            full_name = f"{first} {middle} {last}"
            return full_name.title()

Бұл нұсқа әкесінің аты-жөнін берген адамдар үшін жұмыс істеуі керек, бірақ біз оны сынаған кезде аты-жөнін ғана берген адамдар үшін функцияны бұзғанымызды көреміз.

Бұл жолы pytest іске қосу келесі нәтижені береді:


        $ pytest
        ========================= test session starts =========================
        --snip/код үзіндісі--
         test_name_function.py F                                          [100%]
         ============================== FAILURES ===============================
         ________________________ test_first_last_name _________________________
            def test_first_last_name():
                """"Джанис Джоплин" сияқты атаулар жұмыс істей ме?"""
         >       formatted_name = get_formatted_name('janis', 'joplin')
         E       TypeError: get_formatted_name() missing 1 required positional
                    argument: 'last'
        
        test_name_function.py:5: TypeError
        ======================= short test summary info =======================
        FAILED test_name_function.py::test_first_last_name - TypeError:
            get_formatted_name() missing 1 required positional argument: 'last'
        ========================== 1 failed in 0.04s ==========================

Бұл жерде көптеген ақпарат бар, өйткені сынақ сәтсіз болған кезде сізге көп нәрсе қажет болуы мүмкін. Шығарылымдағы ескертпенің бірінші элементі бір сынақтың сәтсіз аяқталғанын көрсететін жалғыз F ❶ болып табылады. Одан кейін біз FAILURES ❷-ге назар аударатын бөлімді көреміз, себебі сәтсіз сынақтар әдетте назар аудару керек ең маңызды нәрсе болып табылады. Әрі қарай, ❸ орындалмаған сынақ функциясы test_first_last_name() екенін көреміз. ❹ бұрыштық жақша сынақтың сәтсіз аяқталуына себеп болған код жолын көрсетеді. ❺ келесі код жолындағы E қатеге себеп болған нақты қатені көрсетеді: TypeError туындады, себебі қажетті позициялық аргумент last жоқ болғандықтан. Ең маңызды ақпарат соңында қысқарақ қорытындыда қайталанады, сондықтан көптеген сынақтарды орындаған кезде, қандай сынақтардың және неліктен сәтсіз болғанын жылдам түсіне аласыз.

Сәтсіз сынаққа жауап беру

Сынақ сәтсіз болғанда не істейсіз? Сіз дұрыс шарттарды тексеріп жатырсыз деп есептесеңіз, сынақтан өту функцияның дұрыс жұмыс істеп тұрғанын білдіреді және сәтсіз сынақ сіз жазған жаңа кодта қате бар екенін білдіреді. Сондықтан сынақ сәтсіз болғанда, сынақты өзгертпеңіз. Егер олай жасасаңыз, сынақтарыңыз өтуі мүмкін, бірақ дұрыс-сынақ сияқты функцияңызды шақыратын кез-келген код кенеттен жұмысын тоқтатады. Оның орнына сынақтың сәтсіз болуына әкелетін кодты түзетіңіз. Функцияға жаңа ғана енгізген өзгерістерді қарап шығыңыз және сол өзгерістердің қалаған әрекетті қалай бұзғанын анықтаңыз.

Бұл жағдайда get_formatted_name() тек екі параметрді қажет ететін: аты мен тегі. Енді ол аты, әкесінің аты және тегі қажет. Бұл міндетті әкесінің аты параметрін қосу get_formatted_name() бастапқы әрекетін бұзды. Мұнда ең жақсы нұсқа - әкесінің атын міндетті емес қосымша ету. Біз жасағаннан кейін, Janis Joplin сияқты аттарға арналған тестіміз қайтадан өтуі керек және біз әкесінің аты-жөнін де қабылдай алатын боламыз. Әкесінің аты міндетті емес болуы үшін get_formatted_name() өзгертейік, содан кейін сынақ жағдайын қайта іске қосыңыз. Ол өтсе, біз функцияның әке атын дұрыс өңдейтініне көз жеткізуге көшеміз.

Әкесінің атын міндетті емес ету үшін middle параметрін функция анықтамасындағы параметрлер тізімінің соңына жылжытамыз және оған бос әдепкі мән береміз. Біз сондай-ақ әкесінің атының берілген-берілмегеніне байланысты толық атын дұрыс құрайтын if шартты амалын қосамыз:

name_function.py


        def get_formatted_name(first, last, middle=''):
            """Ұқыпты пішімделген толық атауды жасаңыз."""
            if middle:
                full_name = f"{first} {middle} {last}"
            else:
                full_name = f"{first} {last}"
            return full_name.title()

get_formatted_name() қолданбасының осы жаңа нұсқасында әкесінің аты міндетті емес. Егер функцияға әкесінің аты берілсе, толық атауда аты, әкесінің аты және тегі болады. Әйтпесе, толық аты тек аты мен тегінен тұрады. Енді функция атаулардың екі түрі үшін де жұмыс істеуі керек. Функцияның әлі де Janis Joplin сияқты атаулар үшін жұмыс істейтінін білу үшін сынақты қайта іске қосамыз:


        $ pytest
        ========================= test session starts =========================
        --snip/код үзіндісі--
        test_name_function.py .                                       [100%]
        ========================== 1 passed in 0.00s ==========================

Сынақ енді өтеді. Бұл өте жақсы; бұл функция Janis Joplin сияқты атаулар үшін функцияны қолмен сынамай-ақ қайта жұмыс істейтінін білдіреді. Функциямызды түзету оңайырақ болды, себебі сәтсіз сынақ жаңа кодтың бұрын дұрыс жұмыс істеп тұрған кодты қалай бұзғанын анықтауға көмектесті.

Жаңа сынақтарды қосу

Енді біз get_formatted_name() параметрінің қарапайым атаулар үшін жұмыс істейтінін білетіндіктен, әкесінің аты бар адамдар үшін екінші сынақты жазайық. Мұны test_name_function.py файлына басқа сынақ функциясын қосу арқылы жасаймыз:

test_name_function.py


        from name_function import get_formatted_name
        
        def test_first_last_name():
            --snip/код үзіндісі--
        
        def test_first_last_middle_name():
            """Вольфганг Амадей Моцарт" сияқты атаулар жұмыс істей ме?"""
             formatted_name = get_formatted_name(
                'wolfgang', 'mozart', 'amadeus')
             assert formatted_name == 'Wolfgang Amadeus Mozart'

Бұл жаңа функцияны test_first_last_middle_name() деп атаймыз. Функция атауы test_ деп басталуы керек, сондықтан pytest іске қосылғанда функция автоматты түрде іске қосылады. get_formatted_name() параметрінің қандай әрекетін тексеріп жатқанымызды анықтау үшін функцияны атаймыз. Нәтижесінде, сынақ сәтсіз аяқталса, қандай атауларға әсер ететінін бірден білеміз.

Функцияны тексеру үшін ❶ аты, соңғы және әкесінің атымен get_formatted_name() деп атаймыз, содан кейін біз ❷ қайтарылған толық аттың біз күткен толық атқа (бірінші, орта және соңғы) сәйкес келетінін растаймыз. pytest қайта іске қосылғанда, екі сынақ та өтеді:


        $ pytest
        ========================= test session starts =========================
        --snip/код үзіндісі--
        collected 2 items
        
         test_name_function.py ..                                         [100%]
        ========================== 2 passed in 0.01s ==========================

Екі нүкте ❶ екі сынақтан өткенін көрсетеді, бұл шығарылымның соңғы жолынан да анық. Бұл тамаша! Функция әлі де Янис Джоплин сияқты атаулар үшін жұмыс істейтінін білеміз және оның Вольфганг Амадей Моцарт сияқты атаулар үшін де жұмыс істейтініне сенімді бола аламыз.

Классты тестілеу

Осы тараудың бірінші бөлігінде сіз бір функция үшін сынақтар жаздыңыз. Енді сіз классқа тест жазасыз. Сіз көптеген жеке бағдарламаларыңызда кластарды пайдаланасыз, сондықтан кластарыңыздың дұрыс жұмыс істейтінін дәлелдеу пайдалы. Жұмыс істеп жатқан классқа қатысты өтетін дұрыс сынақтар жазған болсаңыз, классқа енгізген жақсартулар-өзгертулер оның ағымдағы әрекетін кездейсоқ бұзбайтынына сенімді бола аласыз.

Қорытынды тұжырымдардың әртүрлілігі

Осы уақытқа дейін сіз қорытынды тұжырымның бір түрін ғана көрдіңіз: тіркестің белгілі бір мәні болу керек деген талап. Тест жазу кезінде шартты амал ретінде көрсетуге болатын болса, сәйкесінше кез-келген талап қоюға болады. Егер шарт күтілгендей True болса, бағдарламаның сол бөлігінің әрекеті, нәтижесі туралы болжамыңыз расталады; қателер жоқ екеніне сенімді бола аласыз. Егер сіз True деп болжаған шарт шын мәнінде False болса, сынақ сәтсіз аяқталады және сіз шешетін мәселе бар екенін білесіз. 11-1-кесте бастапқы сынақтарыңызға қосуға болатын ең пайдалы тұжырым түрлерінің кейбірін көрсетеді.

11-1-кесте: Тесттерде жиі қолданылатын тұжырым/assertion амалдары

Assertion(Тұжырым) Claim(Талап)
assert a == b Assert that two values are equal.
assert a != b Екі мәннің тең емес екенін растаңыз
assert a a True мәніне бағаланатынын растаңыз.
assert not a a False мәніне бағаланатынын растаңыз.
assert element in list Элемент тізімде бар екенін растаңыз.
assert element not in list Элемент тізімде жоқ екенін растаңыз.

Бұл тек бірнеше мысал; шартты амал ретінде өрнектелетін кез-келген нәрсені сынаққа қосуға болады.

Тестілеуге арналған класс

Кластты тестілеу функцияны тексеруге ұқсас, себебі жұмыстың көп бөлігі класстағы әдістердің әрекетін тексеруді қамтиды. Дегенмен, бірнеше айырмашылықтар бар, сондықтан тестілеу үшін класс жазайық. Анонимді сауалнамаларды басқаруға көмектесетін классты қарастырыңыз:

survey.py

class AnonymousSurvey:
            """Сауалнама сұрағына жасырын жауаптарды жинаңыз."""
        
             def __init__(self, question):
                """Сұрақты сақтаңыз және жауаптарды сақтауға дайындалыңыз."""
                self.question = question
                self.responses = []
        
             def show_question(self):
                """Сауалнама сұрағын көрсет."""
                print(self.question)
        
             def store_response(self, new_response):
                """Сауалнамаға бір жауапты сақтаңыз."""
                self.responses.append(new_response)
        
             def show_results(self):
                """Барлық берілген жауаптарды көрсетіңіз."""
                print("Survey results:")
                for response in self.responses:
                    print(f"- {response}")

Бұл класс ❶ берген сауалнама сұрағымен басталады және жауаптарды сақтау үшін бос тізімді қамтиды. Класста ❷ сауалнама сұрағын басып шығару, және ❹ тізімінде сақталған барлық жауаптарды басып шығарыңыз. Осы класстан дананы жасау үшін сізге тек сұрақ қою керек. Белгілі бір сауалнаманы білдіретін дананы алғаннан кейін, сауалнама сұрағын show_question() арқылы көрсетесіз, жауапты store_response() көмегімен сақтайсыз және нәтижелерді show_results арқылы көрсетесіз. ().

AnonymousSurvey классы жұмыс істейтінін көрсету үшін классты пайдаланатын бағдарламаны жазайық:

language_survey.py

from survey import AnonymousSurvey
        
        # Define a question, and make a survey.
        question = "What language did you first learn to speak?"
        language_survey = AnonymousSurvey(question)
        
        # Show the question, and store responses to the question.
        language_survey.show_question()
        print("Enter 'q' at any time to quit.\n")
        while True:
            response = input("Language: ")
            if response == 'q':
                break
            language_survey.store_response(response)
        
        # Show the survey results.
        print("\nThank you to everyone who participated in the survey!")
        language_survey.show_results()

Бұл бағдарлама сұрақты анықтайды ("Алғаш рет қай тілде сөйлеуді үйрендіңіз?") және сол сұрақпен AnonymousSurvey нысанын жасайды. Бағдарлама сұрақты көрсету үшін show_question() шақырады, содан кейін жауаптарды сұрайды. Әрбір жауап алынған кезде сақталады. Барлық жауаптар енгізілген кезде (шығу үшін пайдаланушы q енгізеді), show_results() сауалнама нәтижелерін басып шығарады:

What language did you first learn to speak?
        Enter 'q' at any time to quit.
        
        Language: English
        Language: Spanish
        Language: English
        Language: Mandarin
        Language: q
        
        Thank you to everyone who participated in the survey!
        Survey results:
        - English
        - Spanish
        - English
        - Mandarin

Бұл класс қарапайым анонимді сауалнама үшін жұмыс істейді, бірақ біз AnonymousSurvey және оның құрамындағы сауалнама модулін жақсартқымыз келеді делік. Біз әрбір пайдаланушыға бірнеше жауап енгізуге рұқсат бере аламыз, біз тек бірегей жауаптарды тізімдеу әдісін жаза аламыз және әр жауаптың қанша рет берілгені туралы есеп бере аламыз немесе тіпті анонимді сауалнамаларды басқару үшін басқа класс жаза аламыз.

Мұндай өзгерістерді енгізу AnonymousSurvey класының ағымдағы әрекетіне әсер ету қаупі бар. Мысалы, әр пайдаланушыға бірнеше жауаптар енгізуге рұқсат беруге тырысқанда, біз бір жауаптарды өңдеу әдісін кездейсоқ өзгертуіміз мүмкін. Бұл модульді әзірлеу кезінде бар мінез-құлықты бұзбау үшін біз классқа тесттер жаза аламыз.

AnonymousSurvey классын сынау

Келіңіз, AnonymousSurvey әрекетінің бір аспектісін тексеретін сынақ жазайық. Сауалнама сұрағына бір жауап дұрыс сақталғанын тексеру үшін сынақ жазамыз:

test_survey.py

from survey import AnonymousSurvey
        
         def test_store_single_response():
            """Бір жауаптың дұрыс сақталғанын тексеріңіз."""
            question = "What language did you first learn to speak?"
             language_survey = AnonymousSurvey(question)
            language_survey.store_response('English')
             assert 'English' in language_survey.responses

Біз тексергіміз келетін классты импорттаудан бастаймыз, AnonymousSurvey. Бірінші сынақ функциясы сауалнама сұрағына жауапты сақтаған кезде жауап сауалнаманың жауаптар тізімінде аяқталатынын тексереді. Бұл функция үшін жақсы сипаттамалық атау test_store_single_response() ❶ болып табылады. Бұл сынақ сәтсіз аяқталса, сауалнамаға бір жауапты сақтауда ақау бар екенін сынақ қорытындысындағы функция атауынан білеміз.

Кластың әрекетін тексеру үшін класстың данасын жасау керек. "Алғаш рет қай тілде сөйлеуді үйрендіңіз?" деген сұрақпен language_survey ❷ деп аталатын дананы жасаймыз. store_response() әдісін қолданып, Ағылшынша деген жалғыз жауапты сақтаймыз. Содан кейін Ағылшын тілінің language_survey.responses ❸ тізімінде екенін растау арқылы жауаптың дұрыс сақталғанын тексереміз. .

Әдепкі бойынша, pytest пәрменін аргументсіз орындау pytest ағымдағы каталогта ашатын барлық сынақтарды іске қосады. Бір файлдағы сынақтарға назар аудару үшін іске қосқыңыз келетін сынақ файлының атын беріңіз. Мұнда біз AnonymousSurvey үшін жазған бір ғана сынақты орындаймыз:

$ pytest test_survey.py
        ========================= test session starts =========================
        --snip/код үзіндісі--
        test_survey.py .                                                 [100%]
        ========================== 1 passed in 0.01s ==========================

Бұл жақсы бастама, бірақ сауалнама бірнеше жауап берген жағдайда ғана пайдалы болады. Үш жауапты дұрыс сақтауға болатынын тексерейік. Ол үшін TestAnonymousSurvey-ге басқа әдісті қосамыз:

from survey import AnonymousSurvey
        
        def test_store_single_response():
            --snip/код үзіндісі--
        
        def test_store_three_responses():
            """Үш жеке жауап дұрыс сақталғанын тексеріңіз."""
            question = "What language did you first learn to speak?"
            language_survey = AnonymousSurvey(question)
             responses = ['English', 'Spanish', 'Mandarin']
            for response in responses:
                language_survey.store_response(response)
        
             for response in responses:
                assert response in language_survey.responses

Жаңа функцияны test_store_three_responses() деп атаймыз. Сауалнама нысанын дәл test_store_single_response() ішіндегі жасағандай жасаймыз. Біз үш түрлі жауаптан тұратын тізімді ❶ анықтаймыз, содан кейін осы жауаптардың әрқайсысы үшін store_response() деп атаймыз. Жауаптар сақталғаннан кейін, біз басқа цикл жазамыз және әрбір жауап енді language_survey.responses ❷ ішінде екенін бекітеміз.

Сынақ файлын қайта іске қосқанда, екі сынақ (бір жауап және үш жауап үшін) өтеді:

$ pytest test_survey.py
        ========================= test session starts =========================
        --snip/код үзіндісі--
        test_survey.py ..                                                [100%]
        ========================== 2 passed in 0.01s ==========================

Бұл тамаша жұмыс істейді. Дегенмен, бұл сынақтар аздап қайталанады, сондықтан оларды тиімдірек ету үшін pytest басқа мүмкіндігін қолданамыз.

Арматураларды пайдалану

test_survey.py ішінде біз әрбір сынақ функциясында AnonymousSurvey жаңа данасын жасадық. Бұл біз жұмыс істеп жатқан қысқа мысалда жақсы, бірақ ондаған немесе жүздеген сынақтары бар нақты жобада бұл қиындық тудыруы мүмкін.

Тестілеу кезінде арнатура сынақ ортасын орнатуға көмектеседі. Көбінесе бұл бірнеше сынақ пайдаланатын ресурс жасауды білдіреді. @pytest.fixture декораторымен функция жазу арқылы pytest ішінде арматураны жасаймыз. декоратор – функция анықтамасының алдында орналасқан директива; Python бұл директиваны функция кодының әрекетін өзгерту үшін оны іске қоспас бұрын оған қолданады. Бұл күрделі болып көрінсе, алаңдамаңыз; үшінші тарап пакеттеріндегі декораторларды өз бетіңізше жазуды үйренбес бұрын пайдалана бастай аласыз.

Келіңіз, test_survey.py ішіндегі екі сынақ функцияларында да пайдалануға болатын жалғыз сауалнама данасын жасау үшін арматураны қолданайық:

import pytest
        from survey import AnonymousSurvey
        
         @pytest.fixture
         def language_survey():
            """Барлық сынақ функцияларына қолжетімді сауалнама."""
            question = "What language did you first learn to speak?"
            language_survey = AnonymousSurvey(question)
            return language_survey
        
         def test_store_single_response(language_survey):
            """Бір жауаптың дұрыс сақталғанын тексеріңіз."""
             language_survey.store_response('English')
            assert 'English' in language_survey.responses
        
         def test_store_three_responses(language_survey):
            """Үш жеке жауап дұрыс сақталғанын тексеріңіз."""
            responses = ['English', 'Spanish', 'Mandarin']
            for response in responses:
                 language_survey.store_response(response)
        
            for response in responses:
                assert response in language_survey.responses

Біз қазір pytest импорттауымыз керек, себебі біз pytest ішінде анықталған декораторды пайдаланып жатырмыз. @pytest.fixture декораторын ❶ жаңа language_survey() функциясына қолданамыз. ❷. Бұл функция AnonymousSurvey нысанын құрастырады және жаңа сауалнаманы қайтарады.

Екі сынақ функциясының анықтамалары өзгергеніне назар аударыңыз ❸ ❺; әрбір сынақ функциясының енді language_survey деп аталатын параметрі бар. Сынақ функциясындағы параметр функция атауымен @pytest.fixture декораторымен сәйкес келгенде, арматура автоматты түрде іске қосылады және қайтарылатын мән сынақ функциясына беріледі. Бұл мысалда language_survey() функциясы test_store_single_response() және test_store_three_responses() данасымен қамтамасыз етеді. .

Сынақ функцияларының ешқайсысында да жаңа код жоқ, бірақ әр функциядан екі Тіркестің жойылғанын ескеріңіз ❹ : сұрақты анықтайтын жол және AnonymousSurvey нысанын жасаған жол.

Сынақ файлын қайта іске қосқанда, екі сынақ әлі де өтеді. Бұл сынақтар әр адам үшін бірнеше жауаптарды өңдеу үшін AnonymousSurvey кеңейту әрекеті кезінде әсіресе пайдалы болады. Бірнеше жауапты қабылдау үшін кодты өзгерткеннен кейін, осы сынақтарды іске қосып, бір жауапты немесе жеке жауаптар сериясын сақтау мүмкіндігіне әсер етпегеніңізге көз жеткізіңіз.

Жоғарыдағы құрылым күрделі болып көрінетіні сөзсіз; онда сіз осы уақытқа дейін көрген ең дерексіз кодтардың кейбірі бар. Арматураларды бірден пайдаланудың қажеті жоқ; Тесттерді мүлдем жазбағанша, қайталанатын коды көп сынақтарды жазған дұрыс. Қайталау кедергі болатын жеткілікті сынақтарды жазған кезде, қайталаумен күресудің жақсы бекітілген әдісі бар екенін біліңіз. Сондай-ақ, осы сияқты қарапайым мысалдардағы қондырғылар кодты орындауды қысқартпайды немесе оңайлатпайды. Бірақ көптеген сынақтары бар жобаларда немесе бірнеше сынақтарда пайдаланылатын ресурсты құру үшін көп жолдар қажет болатын жағдайларда арматуралар сынақ кодыңызды күрт жақсарта алады.

Құрылғыны жазғыңыз келсе, бірнеше сынақ функциялары пайдаланатын ресурсты жасайтын функцияны жазыңыз. Жаңа функцияға @pytest.fixture декораторын қосыңыз және осы ресурсты пайдаланатын әрбір сынақ функциясына параметр ретінде осы функцияның атын қосыңыз. Осы сәттен бастап сынақтарыңыз қысқа болады және жазу және қолдау оңайырақ болады.

Қорытынды

Бұл тарауда сіз pytest модуліндегі құралдарды пайдаланып, функциялар мен класстарға тест жазуды үйрендіңіз. Функцияларыңыз бен класстарыңыз көрсетуі керек нақты әрекеттерді тексеретін сынақ функцияларын жазуды үйрендіңіз. Сынақ файлындағы бірнеше сынақ функцияларында пайдалануға болатын ресурстарды тиімді жасау үшін арматураларды қалай пайдалануға болатынын көрдіңіз.

Тестілеу – көптеген жаңа бағдарламашылар біле бермейтін маңызды тақырып. Жаңа бағдарламашы ретінде сынап көретін барлық қарапайым жобаларға тест жазудың қажеті жоқ. Бірақ сіз айтарлықтай даму күш-жігерін қамтитын жобалармен жұмыс істей бастағанда, функцияларыңыз бен класстарыңыздың сыни мінез-құлқын сынауыңыз керек. Жобаңыздағы жаңа жұмыс жұмыс істейтін бөліктерді бұзбайтынына сенімді боласыз және бұл сізге кодты жақсартуға еркіндік береді. Егер сіз бұрыннан бар функционалдылықты байқаусызда бұзсаңыз, мәселені бірден біле аласыз, осылайша мәселені оңай шеше аласыз. Сіз орындаған сәтсіз сынаққа жауап беру бақытсыз пайдаланушының қате туралы есебіне жауап беруден әлдеқайда оңай.

Бастапқы сынақтарды қоссаңыз, басқа бағдарламашылар сіздің жобаларыңызды көбірек құрметтейді. Олар сіздің кодыңызбен тәжірибе жасауды ыңғайлы сезінеді және сізбен жобаларда жұмыс істеуге дайын болады. Басқа бағдарламашылар жұмыс істеп жатқан жобаға үлес қосқыңыз келсе, кодыңыздың бар сынақтардан өткенін көрсетуіңіз керек және әдетте жобаға енгізген кез-келген жаңа мінез-құлық үшін сынақтар жазуыңыз күтіледі.

Кодыңызды сынау процесімен танысу үшін сынақтармен ойнаңыз. Функцияларыңыз бен класстарыңыздың ең маңызды мінез-құлықтары үшін сынақтар жазыңыз, бірақ нақты себебіңіз болмаса, бастапқы жобаларда толық қамтуды мақсат етпеңіз.

Оқ ататын кеме

ITUniver

12
Оқ ататын кеме

Келіңіз, Бөтен планеталықтардың шабуылы деп аталатын ойын жасайық! Біз графиканы, анимацияны және тіпті дыбысты басқаратын, күрделі ойындарды құруды жеңілдететін қызықты, көңілді, қуатты Python модульдерінің жинағы Pygame-ді қолданамыз. Pygame экранға кескіндер салу, графика, қозғалыс сияқты тапсырмаларды автоматтандырады, және сіз ойын динамикасының жоғары деңгейлі логикасына барлық назарыңызды аудара аласыз.

Бұл тарауда сіз Pygame орнатасыз, содан кейін ойыншының енгізуіне жауап ретінде оңға және солға қозғалатын және оқ ататын зымырандық кеме жасайсыз. Келесі екі тарауда сіз атып-жою үшін өзге планеталықтар флотын жасайсыз, содан кейін пайдалануға болатын кемелер санына шектеу қою және табло қосу арқылы ойынды жетілдіруді жалғастырасыз.

Осы ойынды құрастыру кезінде сіз бірнеше файлды қамтитын үлкен жобаларды басқаруды үйренесіз. Біз жобаны ұйымдастыру және кодты тиімді ету үшін көптеген кодтарды қайта өңдеп, файл мазмұнын басқарамыз.

Ойын жасау - тіл үйрену кезінде көңіл көтерудің тамаша тәсілі. Өзіңіз жазған ойынды ойнау өте керемет сезім және қарапайым ойын жазу сізге кәсіпқойлардың ойындарды қалай жасайтыны туралы көп нәрсені үйретеді. Осы тараумен жұмыс істеу барысында әрбір код блогының жалпы ойынға қалай үлес қосатынын анықтау үшін кодты енгізіңіз және іске қосыңыз. Ойындарыңыздағы өзара әрекеттесуді жақсарту жолын жақсырақ түсіну үшін әртүрлі мәндер мен параметрлермен тәжірибе жасаңыз.

Жобаңызды жоспарлау

Үлкен жобаны құрып жатқанда, кодты жазуды бастамас бұрын жоспарды дайындау маңызды. Жоспарлау сіздің ой-көңіліңізді, назарыңызды жинақы етеді және жобаны аяқтау ықтималдығын арттырады.

Жалпы ойынның сипаттамасын жазайық. Төмендегі сипаттама Бөтен планеталықтардың шабуылының барлық мәліметтерін қамтымаса да, ол ойынды қалай бастау керектігі туралы нақты түсінік береді:

Alien Invasion ойынында ойыншы экранның төменгі ортасында пайда болатын зымырандық кемені басқарады. Ойыншы нұсқау пернелерін пайдаланып кемені оңға және солға жылжыта алады және бос орын пернесін пайдаланып оқ ата алады. Ойын басталған кезде, өзге планеталықтар флоты аспанды толтырып, экранның бойымен және төмен қарай жылжиды. Ойыншы өзге планеталықтарды атып, жояды. Егер ойыншы барлық өзге планеталықтарды жойса, алдыңғы флотқа қарағанда жылдамырақ қозғалатын жаңа флот пайда болады. кез-келген бөтен планеталық ойыншының кемесіне соқтығысса немесе экранның төменгі жағына жетсе, ойыншы кемеден айырылады. Ойыншы үш кемені жоғалтса, ойын аяқталады.

Бірінші әзірлеу кезеңінде ойыншы нұсқау пернелерін басқанда оңға және солға жылжи алатын кемені және бос орын пернесін басқан кезде оқтарды ататын кеме жасаймыз. Бұл әрекетті жасап болғаннан кейін біз өзге планеталықтарды жасап, ойынды нақтылай аламыз.

Pygame орнату

Кодтауды бастамас бұрын Pygame орнатыңыз. Біз мұны 11-тарауда pytest орнатқандай орындаймыз: pip көмегімен. 11-тарауды өткізіп алсаңыз, немесе еске түсіру қажет болса pip көмегімен pytest орнату бөлімін қараңыз.

Pygame-ді орнату үшін терминал шақыруында келесі пәрменді енгізіңіз:

$ python -m pip install --user pygame

Бағдарламаларды іске қосу немесе терминал сеансын бастау үшін python пәрменінен басқа пәрменді пайдалансаңыз, мысалы, python3, python орнына сол пәрменді пайдаланып жатқаныңызға көз жеткізіңіз.

Ойын жобасын бастау

Бос Pygame терезесін жасау арқылы ойын құруды бастаймыз. Кейінірек біз осы терезеде кеме және өзге планеталықтар сияқты ойын элементтерін саламыз. Сондай-ақ, біз ойынымыз пайдаланушының енгізуіне жауап беретін етеміз, фон түсін орнатамыз, кеме кескінін жүктейміз.

Pygame терезесін жасау және пайдаланушы енгізуіне жауап беру

Ойынды көрсету үшін класс жасау арқылы біз бос Pygame терезесін жасаймыз. Мәтіндік редакторда жаңа файл жасаңыз және оны alien_invasion.py ретінде сақтаңыз; содан кейін келесіні енгізіңіз:

alien_invasion.py


        import sys
        
        import pygame
        
        class AlienInvasion:
            """Ойын элементтерін және олардың әрекетін..."""
            """...басқаруға арналған жалпы сынып."""
        
            def __init__(self):
                """Ойынды инициализациялаңыз және ойын ресурстарын жасаңыз."""
                 pygame.init()
        
                 self.screen = pygame.display.set_mode((1200, 800))
                pygame.display.set_caption("Alien Invasion")
        
            def run_game(self):
                """Ойынның негізгі циклін бастау."""
                 while True:
                    # Watch for keyboard and mouse events.
                    # Пернетақта мен тінтуір өзгерістерін қадағалау.
                     for event in pygame.event.get():
                         if event.type == pygame.QUIT:
                            sys.exit()
        
                    # Make the most recently drawn screen visible.
                    # Ең соңғы салынған экранды көрсетіңіз.
                     pygame.display.flip()
        
        if __name__ == '__main__':
            # Make a game instance, and run the game.
            ai = AlienInvasion()
            ai.run_game()

Біріншіден, sys және pygame модульдерін импорттаймыз. pygame модулінде ойын жасауға қажетті функциялар бар. Ойыншы шыққанда ойыннан шығу үшін sys модуліндегі құралдарды қолданамыз.

Alien Invasion AlienInvasion деп аталатын класс ретінде басталады. __init__() әдісінде pygame.init() функциясы Pygame дұрыс жұмыс істеуі үшін қажет фондық параметрлерді инициализациялайды . Содан кейін біз ❷ дисплей терезесін жасау үшін pygame.display.set_mode() әдісін шақырамыз, осы дисплейге ойынның барлық графикалық элементтерін саламыз. Мұндағы (1200, 800) аргументі ойын терезесінің өлшемдерін анықтайтын кортеж болып табылады, оның ені 1200 пиксель және биіктігі 800 пиксель болады. (Бұл мәндерді дисплей өлшеміне байланысты реттеуге болады.) Біз бұл дисплей терезесін self.screen атрибутына тағайындаймыз, сондықтан ол класстағы барлық әдістерде қолжетімді болады.

Біз self.screen-ға тағайындаған нысан беті деп аталады. Pygame ішіндегі бет/surface ойын элементін көрсетуге болатын экранның бөлігі болып табылады. Ойынның әрбір элементі, мысалы бөтен планеталық немесе кеме, өзіндік бетте болады. display.set_mode() арқылы қайтарылған бет бүкіл ойын терезесін білдіреді. Ойынның анимациялық циклін іске қосқанда, бұл бет цикл арқылы әр өтуде қайта сызылып-салынады, сондықтан оны пайдаланушы енгізуі арқылы енгізілген кез-келген өзгерістермен жаңартуға болады.

Ойын run_game() әдісімен басқарылады. Бұл әдіс үздіксіз жұмыс істейтін while ❸ циклін қамтиды. while циклінде экран жаңартуларын басқаратын оқиғалар циклі мен код бар. Оқиға/event — пайдаланушының ойын ойнау кезінде пернені басу немесе тінтуірді жылжыту сияқты әрекеті. Бағдарламамыздың оқиғаларға жауап беруі үшін оқиғаларды тыңдау үшін оқиға циклін жазамыз және орын алған оқиғалар түріне байланысты тиісті тапсырмаларды орындаймыз. ❹ for циклі while циклінің ішінде кірістірілген оқиға циклі болып табылады.

Pygame анықтайтын оқиғаларға қол жеткізу үшін pygame.event.get() функциясын қолданамыз. Бұл функция осы функция соңғы рет шақырылғаннан бері орын алған оқиғалардың тізімін қайтарады. Кез-келген пернетақта немесе тінтуір оқиғасы осы for циклінің іске қосылуына себеп болады. Цикл ішінде біз нақты оқиғаларды анықтау және оларға жауап беру үшін if амалдарының қатарын жазамыз. Мысалы, ойыншы ойын терезесінің жабу түймесін басқанда, pygame.QUIT оқиғасы көрінеді және біз ойынынан шығу үшін sys.exit() әдісін шақырамыз ❺.

pygame.display.flip() ❻ әдісіне шақыру жасау Pygame-ге соңғы салынған экранды көрсетуді ұсынады. Бұл жағдайда ол жай ғана while циклі арқылы әрбір өтуде бос экранды сызып, ескі экранды өшіреді, осылайша тек жаңа экран көрінеді. Ойын элементтерін жылжытқанда, pygame.display.flip() ойын элементтерінің жаңа орындарын көрсету және ескілерін жасыру үшін дисплейді үнемі жаңартып, бірқалыпты қозғалыс елесін жасайды.

Файлдың соңында біз ойынның данасын жасаймыз, содан кейін run_game() шақырамыз. Біз run_game() файлын тікелей шақырғанда ғана іске қосылатын if блогына орналастырамыз. Осы alien_invasion.py файлын іске қосқан кезде бос Pygame терезесін көресіз.

Кадр жиілігін басқару

Ойынымыз жақсы жұмыс істеу үшін оның жалдамдығы-frame rate барлық жүйелерде бердей орындалуы керек. Бірнеше жүйеде жұмыс істей алатын ойынның кадр жиілігін басқару күрделі мәселе, бірақ Pygame бұл мақсатқа жетудің салыстырмалы түрде қарапайым әдісін ұсынады. Біз сағат жасаймыз және бағдарлама негізгі цикл арқылы әр өткенде сағат бір жылжуын қамтамасыз етеміз. Егер цикл біз анықтаған жылдамдықтан тез өңделіп кетсе, Pygame ойын тұрақты жылдамдықпен жұмыс істеуі үшін үзіліс уақытын есептеп, керекті үзілісті жасайды.

Сағатты __init__() әдісімен анықтаймыз:

alien_invasion.py


            def __init__(self):
                """Ойынды инициализациялаңыз және ойын ресурстарын жасаңыз."""
                pygame.init()
                self.clock = pygame.time.Clock()
                --snip/код үзіндісі--

pygame инициализациясынан кейін pygame.time модулінен Clock класының данасын жасаймыз. Содан кейін run_game() ішіндегі while циклінің соңында сағат белгісін қоямыз:


            def run_game(self):
                """Ойынның негізгі циклін бастау."""
                while True:
                    --snip/код үзіндісі--
                    pygame.display.flip()
                    self.clock.tick(60)

tick() әдісі бір аргумент алады: ойынға арналған кадр жиілігі/frame rate. Мұнда біз 60 мәнін пайдаланып жатырмыз, сондықтан Pygame циклды секундына дәл 60 рет орындау үшін барын салады.

Фон түсін орнату

Pygame әдепкі бойынша қара экран жасайды, бірақ бұл қызықсыз. Басқа фон түсін орнатайық. Мұны __init__() әдісінің соңында орындаймыз.

alien_invasion.py


            def __init__(self):
                --snip/код үзіндісі--
                pygame.display.set_caption("Alien Invasion")
        
                # Set the background color.
                 self.bg_color = (230, 230, 230)
        
            def run_game(self):
                --snip/код үзіндісі--
                    for event in pygame.event.get():
                        if event.type == pygame.QUIT:
                            sys.exit()
        
                    # Redraw the screen during each pass through the loop.
                     self.screen.fill(self.bg_color)
        
                    # Make the most recently drawn screen visible.
                    pygame.display.flip()
                    self.clock.tick(60)

Pygame-дегі түстер RGB түстері ретінде көрсетілген: қызыл, жасыл және көктің араласуы. Әрбір түс мәні 0 мен 255 аралығында болуы мүмкін. Түс мәні (255, 0, 0) қызыл, (0, 255, 0) жасыл және (0, 0, 255) көк. 16 миллион түске дейін жасау үшін әртүрлі RGB мәндерін араластыруға болады. Түс мәні (230, 230, 230) қызыл, көк және жасыл түстерді бірдей мөлшерде араластырады, бұл ашық сұр фондық түс береді. Біз бұл түсті self.bg_color ❶ түріне тағайындаймыз.

Біз бетке әсер ететін fill() ❷ әдісі арқылы экранды фон түсімен толтырамыз, және бұл әдіс бір ғана аргумент қабылдайды: түс.

Баптау/Settings классын жасау

Ойынға жаңа функцияларды қосқан сайын сәйкесінше біз әдетте жаңа баптауларды жасаймыз. Баптауларды бүкіл код ішіне араластырып қосудың орнына, осы мәндердің барлығын бір жерде сақтау үшін Settings деп аталатын классты қамтитын settings деп аталатын модуль жазайық. Бұл тәсіл бізге жеке баптауға қол жеткізу керек болған кез-келген сәтте бір ғана settings нысанымен жұмыс істеуге мүмкіндік береді. Бұл сонымен қатар жобамыз өсіп келе жатқанда ойынның сыртқы түрі мен әрекетін өзгертуді жеңілдетеді. Ойынды өзгерту үшін жоба ішіндегі әртүрлі баптауларды іздеудің орнына, біз қазір жасайтын settings.py ішіндегі сәйкес мәндерді өзгерте саламыз.

alien_invasion каталогыңызда settings.py атты жаңа файл жасаңыз және осы бастапқы Settings классын қосыңыз:

settings.py


        class Settings:
            """Alien Invasion ойынына қажетті барлық баптауларды сақтауға арналған класс."""
        
            def __init__(self):
                """Ойын параметрлерін инициализациялау."""
                # Screen settings
                self.screen_width = 1200
                self.screen_height = 800
                self.bg_color = (230, 230, 230)

Жобада Settings данасын жасау және оны баптауларымызға кіруге пайдалану үшін alien_invasion.py файлын келесідей өзгерту керек:

alien_invasion.py


        --snip/код үзіндісі--
        import pygame
        
        from settings import Settings
        
        class AlienInvasion:
            """Ойын элементтері мен әрекетін басқаруға арналған жалпы клас."""
        
            def __init__(self):
                """Ойынды инициализациялаңыз және ойын ресурстарын жасаңыз."""
                pygame.init()
                self.clock = pygame.time.Clock()
                 self.settings = Settings()
        
                 self.screen = pygame.display.set_mode(
                    (self.settings.screen_width, self.settings.screen_height))
                pygame.display.set_caption("Alien Invasion")
        
            def run_game(self):
                    --snip/код үзіндісі--
                    # Redraw the screen during each pass through the loop.
                     self.screen.fill(self.settings.bg_color)
        
                    # Make the most recently drawn screen visible.
                    pygame.display.flip()
                    self.clock.tick(60)
        --snip/код үзіндісі--

Біз Settings негізгі бағдарлама файлына импорттаймыз. Содан кейін Settings данасын жасаймыз және оны self.settings ❶ параметріне тағайындаймыз, pygame.init() әдісін шақырғаннан кейін. Ойын ❷ экранын жасағанда, біз self.settings-тің screen_width және screen_height атрибуттарын қолданамыз, содан кейін біз экранды түспен бояу кезінше фон түсіне қол жеткізу үшін тағы да ❸ self.settings-ті қолданамыз.

Енді alien_invasion.py қолданбасын іске қосқан кезде сіз әлі ешбір өзгерістерді көрмейсіз, себебі біз бұрыннан қолданып жүрген параметрлерді басқа жерге көшірдік. Енді экранға жаңа элементтер қосуға дайынбыз.

Кеме кескінін қосу

Кемені ойынымызға қосайық. Ойыншының кемесін экранға салу үшін біз кескінді жүктейміз, содан кейін суретті салу үшін Pygame blit() әдісін қолданамыз.

Ойындарыңыз үшін өнер туындысын таңдағанда, лицензиялауға назар аударыңыз. Бастаудың ең қауіпсіз және ең арзан жолы - https://opengameart.org сияқты веб-сайттан пайдалануға және өзгертуге болатын еркін лицензияланған графиканы пайдалану.

Ойыныңызда кескін файлының кез-келген түрін дерлік пайдалана аласыз, бірақ нүктелік кескінді (.bmp) пайдаланған кезде бұл оңайырақ, себебі Pygame растрлық (bitmaps) кескіндерді әдепкі бойынша жүктейді. Pygame қолданбасын басқа файл түрлерін пайдалану үшін конфигурациялауға болады, бірақ кейбір файл түрлері компьютерде орнатылуы керек белгілі бір кескін кітапханаларын талап етеді. Сіз табатын кескіндердің көпшілігі .jpg немесе .png пішімінде, бірақ оларды Photoshop, GIMP және Paint сияқты құралдарды пайдаланып нүктелік кескіндерге (bitmaps) түрлендіруге болады.

Таңдалған суреттегі фон түсіне ерекше назар аударыңыз. Кескін өңдегішін пайдаланып, кез-келген фон түсімен ауыстыруға болатын мөлдір немесе біркелкі түс фоны бар файлды табуға тырысыңыз. Кескіннің өң түсі ойыныңыздың өң түсіне сәйкес келсе, ойындарыңыз жақсы көрінеді. Немесе ойынның фонын кескіннің фонымен сәйкестендіруге болады.

Alien Invasion үшін ship.bmp файлын пайдалана аласыз (12-сурет -1), ол осы кітаптың https://ehmatthes.github.io/pcc_3e сайтындағы ресурстарында қолжетімді. Файлдың өң түсі осы жобада қолданып жатқан параметрлерге сәйкес келеді. Негізгі alien_invasion жоба каталогының ішінде images деп аталатын каталогты жасаңыз. ship.bmp файлын images каталогына сақтаңыз.

12-1-сурет: Alien Invasion-ға арналған кеме

Кеме классын жасау

Кеме үшін суретті таңдағаннан кейін оны экранда көрсету керек. Біздің кемені пайдалану үшін біз Ship классын қамтитын жаңа ship модулін жасаймыз. Бұл класс ойыншы кемесінің әрекетінің көп бөлігін басқарады:

ship.py


        import pygame
        
        class Ship:
            """Кемені басқаруға арналған клас"""
        
            def __init__(self, ai_game):
                """Кемені инициализациялаңыз және оның бастапқы орнын орнатыңыз."""
                 self.screen = ai_game.screen
                 self.screen_rect = ai_game.screen.get_rect()
        
                # Кеме кескінін жүктеңіз және оның тіктөртбұрышын алыңыз
                 self.image = pygame.image.load('images/ship.bmp')
                self.rect = self.image.get_rect()
        
                # Әрбір жаңа кемені экранның төменгі ортасынан бастаңыз.
                 self.rect.midbottom = self.screen_rect.midbottom
        
             def blitme(self):
                """Кемені қазіргі орнында сызыңыз."""
                self.screen.blit(self.image, self.rect)

Pygame тиімді, себебі ол барлық ойын элементтерін тіктөртбұрыштар(rects) сияқты өңдеуге мүмкіндік береді, тіпті олардың пішіні тіктөртбұрыштар сияқты болмаса да. Элементті тіктөртбұрыш ретінде қарастыру тиімді, себебі тіктөртбұрыштар қарапайым геометриялық фигуралар. Pygame екі ойын элементінің соқтығысқан-соқтығыспағанын анықтау қажет болғанда, мысалы, ол әрбір нысанды тіктөртбұрыш ретінде қарастырса, мұны жылдамырақ жасай алады. Осы тәсілдің жеткілікті жақсы жұмыс істеуіне байланысты ойыншылар біздің ойын элементтерінің нақты пішінімен жұмыс жасап жоқ екенімізді байқамайды. Бұл класста кеме мен экранды төртбұрыштар ретінде қарастырамыз.

Классты анықтамас бұрын pygame модулін импорттаймыз. Ship класының __init__() әдісі екі параметрді қабылдайды: self сілтемесі және AlienInvasion класының ағымдағы данасына сілтеме. Бұл Ship қолданбасына AlienInvasion ішінде анықталған барлық ойын ресурстарын қолжетімді етеді. Содан кейін экранды Ship ❶ атрибутына тағайындаймыз, осылайша біз оған осы кластағы барлық әдістерде оңай қол жеткізе аламыз. Біз экранның rect атрибутына get_rect() әдісі арқылы қол жеткіземіз және оны self.screen_rect ❷ -ге тағайындаймыз. Бұл бізге кемені экранда дұрыс орынға қоюға мүмкіндік береді.

Кескінді жүктеу үшін pygame.image.load() ❸ әдісін шақырамыз және оған кеменің суреті сақталған каталог орнын береміз. Бұл функция кемені көрсететін бетті/surface қайтарады, оны біз self.image-ге тағайындаймыз. Кескін жүктелген кезде, біз кеме бетінің rect атрибутына қол жеткізу үшін get_rect() шақырамыз, осылайша оны кейін кемені орналастыру үшін пайдалана аламыз.

Сіз rect нысанымен жұмыс істегенде, осы нысанды терезеде орналастыру-жылжыту үшін жоғарғы, төменгі, сол және оң жақ ұштарының, сондай-ақ орта нүктесінің x- және y- координаталарын пайдалана аласыз. rect-тің ағымдағы орнын орнату үшін осы мәндердің кез-келгенін жазып-орнатуға болады. Ойын элементін ортаға қойатын болсаңыз, rect атрибуттарының center, centerx немесе centery атрибуттарымен жұмыс істеңіз. Экранның шетінде жұмыс істегенде, top/жоғарғы, bottom/төменгі, left/сол немесе right/оң жақ атрибуттарымен жұмыс жасаңыз. Сондай ақ, осы қасиеттерді біріктіретін midbottom, midtop, midleft және midright сияқты атрибуттар да бар. rect көлденең немесе тік орналасуын реттеп жатқанда, сіз жай ғана x және y атрибуттарын пайдалана аласыз, мұндай x- және y-оның жоғарғы сол жақ бұрышының координаталары. Бұл атрибуттар ойын әзірлеушілері бұрын қолмен жасайтын есептеулерді орындаудан құтқарады және сіз оларды жиі пайдаланасыз.

Кемені экранның төменгі ортасына орналастырамыз. Ол үшін self.rect.midbottom ❹ мәні экранның rect нысанының midbottom атрибутына сәйкес болсын. Pygame осы rect атрибуттарын кеме кескінін терезенің қақ ортасында және экранның төменгі жағымен қатарлас етіп орналастыру үшін пайдаланады.

Соңында, біз ❺ bltime әдісін анықтаймыз, ол self.rect арқылы көрсетілген позицияда кескінді экранға салады.

Кемені экранға салу

Енді alien_invasion.py файлын жаңартайық, сонда ол кеме жасайды және кеменің blitme() әдісін шақырады:

alien_invasion.py


        --snip/код үзіндісі--
        from settings import Settings
        from ship import Ship
        
        class AlienInvasion:
            """Ойын активтері мен мінез-құлқын басқаруға арналған жалпы сынып."""
        
            def __init__(self):
                --snip/код үзіндісі--
                pygame.display.set_caption("Alien Invasion")
        
                 self.ship = Ship(self)
        
            def run_game(self):
                    --snip/код үзіндісі--
                    # Redraw the screen during each pass through the loop.
                    self.screen.fill(self.settings.bg_color)
                     self.ship.blitme()
        
                    # Make the most recently drawn screen visible.
                    pygame.display.flip()
                    self.clock.tick(60)
        --snip/код үзіндісі--

Біз Ship импорттаймыз, содан кейін экран жасалғаннан кейін Ship данасын жасаймыз ❶. Ship() шақыру бір аргументті қажет етеді: AlienInvasion данасы. Мұндағы self аргументі AlienInvasion ағымдағы данасына сілтеме жасайды. Бұл Ship-ке ойын ресурстарын қолжетімді ететін параметр, screen объектісі сияқты. Біз бұл Ship данасын self.ship-ке тағайындаймыз.

Фонды біркелкі түске бояп-толтырғаннан кейін, біз ship.blitme() әдісін шақыру арқылы экранда кеменің суретін саламыз, осылайша кеме фон қабатының үсінде пайда болады .

alien_invasion.py қолданбасын қазір іске қосқан кезде, төменде көрсетілгендей зымыран кемесі орналасқан бос ойын экранын көресіз.12-2-сурет.

12-2-сурет: Бөтен планеталықтардың шабуылы, экранның төменгі ортасында кеме бар

Refactoring: The _check_events() and _update_screen() Methods

Үлкен жобаларда қосымша код қоспас бұрын жазған кодты жиі қайта өңдейсіз. Рефакторинг сіз жазған кодтың құрылымын жеңілдетеді және оның үстінен құруды жеңілдетеді. Бұл бөлімде біз ұзарып бара жатқан run_game() әдісін екі көмекші әдіске бөлеміз. Helper method/Көмекші әдіс класс ішінде жұмыс істейді, бірақ класстан тыс кодпен пайдалануға арналмаған. Python тілінде бір астын сызумен басталатын әдіс - көмекші әдіс екенін білдіреді.

_check_events() әдісі

Оқиғаларды басқаратын кодты _check_events() деп аталатын бөлек әдіске жылжытамыз. Бұл run_game()-ді жеңілдетеді және оқиғаларды басқару циклін оқшаулайды. Оқиғалар циклін оқшаулау экранды жаңарту сияқты оқиғаларды ойынның басқа аспектілерінен бөлек басқаруға мүмкіндік береді.

Міне, жаңа _check_events() әдісі бар AlienInvasion классы, ол тек run_game() ішіндегі кодқа әсер етеді:

alien_invasion.py


            def run_game(self):
                """Ойынның негізгі циклін бастау."""
                while True:
                     self._check_events()
        
                    # Redraw the screen during each pass through the loop.
                    --snip/код үзіндісі--
        
             def _check_events(self):
                """Пернелерді басу және тінтуір оқиғаларына жауап беру."""
                for event in pygame.event.get():
                    if event.type == pygame.QUIT:
                        sys.exit()

Біз жаңа _check_events() әдісін ❷ жасаймыз және "ойыншы терезені жабу нүктесін басты ма" соны тексеретін код жолдарын осы әдіске жылжытамыз.

Кластың ішінен әдісті шақыру үшін ❶ self айнымалысы және әдіс атауын нүкте белгісі арқылы пайдаланыңыз. Әдісті run_game() ішіндегі while циклінің ішінен шақырамыз.

_update_screen() әдісі

run_game() нұсқасын одан әрі жеңілдету үшін экранды жаңарту кодын _update_screen() деп аталатын бөлек әдіске жылжытамыз:

alien_invasion.py


            def run_game(self):
                """Ойынның негізгі циклін бастау."""
                while True:
                    self._check_events()
                    self._update_screen()
                    self.clock.tick(60)
        
            def _check_events(self):
                --snip/код үзіндісі--
        
            def _update_screen(self):
            """Экрандағы кескіндерді жаңартыңыз және жаңа экранға өтіңіз."""
                self.screen.fill(self.settings.bg_color)
                self.ship.blitme()
        
                pygame.display.flip()

Біз фон мен кемені салатын кодты және экранды айналдыратын кодты _update_screen() көмекші әдісіне жылжыттық. Енді run_game() ішіндегі негізгі циклдің денесі әлдеқайда қарапайым. Циклдың әр өтуінде жаңа оқиғалардың болған-болмағанын қадағалайтынымызды, экранды жаңартып жатқанымызды және сағаттың тикат етіп өтіп жатқанын түсіну оңай.

Егер сіз бірнеше ойын жасап қойған болсаңыз, кодты осындай әдістерге бөлуден бастаған боларсыз. Бірақ мұндай жобамен ешқашан айналыспаған болсаңыз, бастапқыда кодты қалай құрылымдау керектігін білмеуіңіз мүмкін. Бұл тәсіл сізге нақты код жазу процесі туралы түсінік береді: сіз кодты мүмкіндігінше қарапайым жаза бастайсыз, содан кейін жобаңыз күрделене түскен сайын оны қайта өңдейсіз.

Енді біз жаңа код жолдарын қосуды жеңілдету үшін рефакторинг жасап болған соң, біз ойынның динамикалық аспектілерімен жұмыс істей аламыз!

Кемені "ұшырып-басқару"

Одан кейін біз ойыншыға кемені оңға және солға жылжыту мүмкіндігін береміз. Ойыншы оң немесе сол жақ көрсеткі пернесін басқанда жауап беретін кодты жазамыз. Біз алдымен оңға қарай қозғалысқа назар аударамыз, содан кейін солға қарай қозғалысты басқару үшін бірдей принциптерді қолданамыз. Бұл кодты қосқанда, экрандағы кескіндердің қозғалысын басқаруды және пайдаланушы енгізуіне жауап беруді үйренесіз.

Пернені басуға жауап беру

Ойыншы пернені басқанда, сол пернені басу Pygame жүйесінде оқиға ретінде тіркеледі. Әрбір оқиға pygame.event.get() әдісі арқылы алынады. Біз _check_events() әдісімізде ойында қандай оқиғаларды тексергіміз келетінін көрсетуіміз керек. Әрбір пернені басу KEYDOWN оқиғасы ретінде тіркеледі.

Pygame KEYDOWN оқиғасын анықтаған кезде, басылған перне белгілі бір әрекетті тудыратын перне екенін тексеруіміз керек. Мысалы, егер ойыншы оң жақ көрсеткі пернесін басса, кемені оңға жылжыту үшін кеменің rect.x мәнін арттырғымыз келеді:

alien_invasion.py


            def _check_events(self):
                """Пернелерді басу және тінтуір оқиғаларына жауап беру."""
                for event in pygame.event.get():
                    if event.type == pygame.QUIT:
                        sys.exit()
                     elif event.type == pygame.KEYDOWN:
                         if event.key == pygame.K_RIGHT:
                            # Move the ship to the right.
                             self.ship.rect.x += 1

_check_events() функция ішіндегі оқиғалар цикліне (event loop) ❶ elif блогын қосамыз, ол Pygame KEYDOWN оқиғасын анықтағанда сол әрекетке кері әрекетпен жауап береді. Басылған перне, event.key, оң жақ көрсеткі ❷ ме, соны тексереміз. Оң жақ көрсеткі перне pygame.K_RIGHT арқылы көрсетіледі. Оң жақ көрсеткі пернесі басылған болса, self.ship.rect.x мәнін 1-ге ❸ арттыру арқылы кемені оңға жылжытамыз.

Қазір alien_invasion.py іске қосылғанда, оң жақ көрсеткі пернесін басқан сайын кеме оңға бір пиксельге жылжуы керек. Бұл бастама, және кемені басқарудың тиімді жолы емес. Үздіксіз қозғалысқа рұқсат беру арқылы бұл басқаруды жақсартайық.

Үздіксіз қозғалысқа рұқсат ету

Ойыншы оң жақ көрсеткі пернесін басып тұрғанда, ойыншы пернені босатып-жібермегенше кеменің оң жақ бағытта қозғалуын қалаймыз. Ойынның pygame.KEYUP оқиғасын анықтауын қамтамасыз етеміз, осылайша оң жақ көрсеткі перненің қашан босатылғанын білеміз; содан кейін үздіксіз қозғалысты жүзеге асыру үшін KEYDOWN және KEYUP оқиғаларын moving_right деп аталатын жалаушамен бірге қолданамыз.

moving_right жалауы False болғанда, кеме қозғалыссыз болады. Ойыншы оң жақ көрсеткі пернесін басқанда, жалаушаны True күйіне орнатамыз, ал ойыншы пернені босатқанда, жалаушаны қайтадан False күйіне орнатамыз.

Ship классы кеменің барлық атрибуттарын басқарады, сондықтан біз оған moving_right жалауының күйін тексеру үшін moving_right деп аталатын атрибутты және update() әдісін береміз. update() әдісі жалауша True күйіне орнатылған болса, кеменің орнын өзгертеді. Біз бұл әдісті кеменің орнын жаңарту үшін while циклі арқылы әр өткенде бір рет шақырамыз.

Ship класындағы код өзгертулері манандай:

ship.py


        class Ship:
            """Кемені басқаруға арналған сынып."""
        
            def __init__(self, ai_game):
                --snip/код үзіндісі--
                # Start each new ship at the bottom center of the screen.
                self.rect.midbottom = self.screen_rect.midbottom
        
                # Movement flag; start with a ship that's not moving.
                 self.moving_right = False
        
             def update(self):
                """Қозғалыс жалауы негізінде кеменің орнын жаңарту."""
                if self.moving_right:
                    self.rect.x += 1
        
            def blitme(self):
                --snip/код үзіндісі--

Біз self.moving_right атрибутын __init__() әдісіне қосамыз және оны бастапқыда False мәніне орнатамыз ❶. Одан кейін жалау True болса, кемені оңға жылжытатын update() қосамыз ❷. update() әдісі класстан тыс шақырылады, сондықтан ол көмекші әдіс болып саналмайды.

Енді біз _check_events() параметрін өзгертуіміз керек, осылайша moving_right оң жақ көрсеткі пернесін басқанда True және перне босатылған кезде False мәніне орнатылады:

alien_invasion.py


            def _check_events(self):
                """Пернелерді басу және тінтуір оқиғаларына жауап беру."""
                for event in pygame.event.get():
                    --snip/код үзіндісі--
                    elif event.type == pygame.KEYDOWN:
                        if event.key == pygame.K_RIGHT:
                             self.ship.moving_right = True
                     elif event.type == pygame.KEYUP:
                        if event.key == pygame.K_RIGHT:
                            self.ship.moving_right = False

Бұл жерде біз ойыншы оң жақ көрсеткі пернесін басқан кезде ойынның қалай жауап беретінін өзгертеміз: кеменің орнын пиксельдеп тікелей өзгертудің орнына, біз жәй ғана ❶ moving_right мәнін True-ге өзгерте салдық. Содан кейін біз KEYUP оқиғаларына ❷ жауап беретін жаңа elif блогын қосамыз. Ойыншы оң жақ көрсеткі пернесін (K_RIGHT) босатқанда, біз moving_right параметрін False күйіне орнатамыз.

Келесі, run_game() ішіндегі while циклін өзгертеміз, осылайша ол цикл арқылы әрбір өтуде кеменің update() әдісін шақырады:

alien_invasion.py


             def run_game(self):
                """Ойынның негізгі циклін бастау."""
                while True:
                    self._check_events()
                    self.ship.update()
                    self._update_screen()
                    self.clock.tick(60)

Кеменің орны пернетақта оқиғаларын тексергеннен кейін және экранды жаңарту алдында жаңартылады. Бұл ойыншының енгізуіне жауап ретінде кеменің орнын жаңартуға мүмкіндік береді және кемені экранға салу кезінде жаңартылған орынның қолданылуын қамтамасыз етеді.

alien_invasion.py файлын іске қосып, оң жақ көрсеткі пернесін басып тұрғанда, сіз кілтті босатқанша кеме үздіксіз оңға қарай жылжуы керек.

Солға және оңға жылжыту

Енді кеме үздіксіз оңға қарай жылжи алатындықтан, солға қозғалыс қосу оңай. Тағы да, біз Ship классын және _check_events() әдісін өзгертеміз. Мұнда __init__() және update() үшін Ship ішіндегі тиісті өзгерістер берілген:

ship.py


            def __init__(self, ai_game):
                --snip/код үзіндісі--
                # Movement flags; start with a ship that's not moving.
                self.moving_right = False
                self.moving_left = False
        
            def update(self):
                """Қозғалыс жалаулары негізінде кеменің орнын жаңарту."""
                if self.moving_right:
                    self.rect.x += 1
                if self.moving_left:
                    self.rect.x -= 1

__init__() ішінде біз self.moving_left жалауын қосамыз. update() жүйесінде кеменің rect.xelif қолдансақ, оң жақ көрсеткі перне әрқашан басымдыққа ие болады. Екі if блогын пайдалану, ойыншы бағытты өзгерткен кезде екі пернені де бір сәт басып тұруы мүмкін болғанда, қозғалыстарды дәлірек етеді.

Біз _check_events() файлына екі толықтыру енгізуіміз керек:

alien_invasion.py


            def _check_events(self):
                """Пернелерді басу және тінтуір оқиғаларына жауап беру."""
                for event in pygame.event.get():
                    --snip/код үзіндісі--
                    elif event.type == pygame.KEYDOWN:
                        if event.key == pygame.K_RIGHT:
                            self.ship.moving_right = True
                        elif event.key == pygame.K_LEFT:
                            self.ship.moving_left = True
        
                    elif event.type == pygame.KEYUP:
                        if event.key == pygame.K_RIGHT:
                            self.ship.moving_right = False
                        elif event.key == pygame.K_LEFT:
                            self.ship.moving_left = False

Егер K_LEFT пернесі үшін KEYDOWN оқиғасы орын алса, moving_left мәнін True мәніне орнатамыз. K_LEFT пернесі үшін KEYUP оқиғасы орын алса, moving_left мәнін False мәніне орнатамыз. Мұнда біз elif блоктарын пайдалана аламыз, себебі әрбір оқиға тек бір кілтке қосылған. Ойнатқыш екі пернені бірден басса, екі бөлек оқиға анықталады.

Қазір alien_invasion.py іске қосылғанда, кемені үздіксіз оңға және солға жылжыту мүмкіндігіңіз болуы керек. Екі пернені басып тұрсаңыз, кеме қозғалысын тоқтатуы керек.

Кейін кеменің қозғалысын одан әрі нақтылайтын боламыз. Кеменің жылдамдығын реттеп, экранның шетіне жеткенде жоғалып кетпес үшін оның қаншалықты қозғала алатынын шектейік.

Кеме жылдамдығын реттеу

Қазір кеме while циклі арқылы цикл сайын бір пиксельді жылжытады, бірақ біз Settings классына ship_speed атрибутын қосу арқылы кеме жылдамдығын жақсырақ басқара аламыз. Біз бұл атрибутты цикл арқылы әрбір өтуде кемені қаншалықты жылжыту керектігін анықтау үшін қолданамыз. Міне, settings.py ішіндегі жаңа атрибут:

settings.py


        class Settings:
            """Жат планеталық шабуылға арналған барлық параметрлерді сақтауға арналған сынып."""
        
            def __init__(self):
                --snip/код үзіндісі--
        
                # Ship settings
                self.ship_speed = 1.5

Біз ship_speed бастапқы мәнін 1,5 етіп орнаттық. Кеме қазір қозғалғанда, оның орны цикл арқылы әр өту кезінде 1,5 пикселге (1 пиксельге емес) өзгертіледі.

Ойынның қарқын-жылдамдығын кейінірек арттырған кезде кеме жылдамдығын жақсырақ басқаруға мүмкіндік беру үшін жылдамдық параметрі үшін біз қазір бөлшек сан қолданамыз. Дегенмен, x сияқты rect атрибуттары тек бүтін мәндерді сақтайды, сондықтан Ship-ке кейбір өзгертулер енгізу керек:

ship.py


        class Ship:
            """Кемені басқаруға арналған сынып."""
        
            def __init__(self, ai_game):
                """Кемені инициализациялаңыз және оның бастапқы орнын орнатыңыз."""
                self.screen = ai_game.screen
                 self.settings = ai_game.settings
                --snip/код үзіндісі--
        
                # Start each new ship at the bottom center of the screen.
                self.rect.midbottom = self.screen_rect.midbottom
        
                # Store a float for the ship's exact horizontal position.
                 self.x = float(self.rect.x)
        
                # Movement flags; start with a ship that's not moving.
                self.moving_right = False
                self.moving_left = False
        
            def update(self):
                """Қозғалыс жалаулары негізінде кеменің орнын жаңарту."""
                # Update the ship's x value, not the rect.
                if self.moving_right:
                     self.x += self.settings.ship_speed
                if self.moving_left:
                    self.x -= self.settings.ship_speed
        
                # Update rect object from self.x.
                 self.rect.x = self.x
        
            def blitme(self):
                --snip/код үзіндісі--

Біз Ship үшін settings атрибутын жасаймыз, сондықтан оны update() -да пайдалана аламыз. Біз кеменің орнын пикселдің бөліктері бойынша реттеп жатқандықтан, позицияны оған тағайындалған қалқымалы мәнге ие айнымалыға тағайындауымыз керек. rect атрибутын орнату үшін float пайдалана аласыз, бірақ rect сол мәннің бүтін бөлігін ғана сақтайды. Кеменің орнын дәл қадағалау үшін біз жаңа self.x ❷ анықтаймыз. self.rect.x мәнін қалқымалы мәнге түрлендіру және бұл мәнді self.x мәніне тағайындау үшін float() функциясын қолданамыз.

Енді update() ішіндегі кеме орнын өзгерткен кезде, self.x мәні settings.ship_speed ішінде сақталған сомаға реттеледі.❸. self.x жаңартылғаннан кейін, кеме орнын басқаратын self.rect.x жаңарту үшін жаңа мәнді пайдаланамыз.❹. self.x файлының бүтін бөлігі ғана self.rect.x-ге тағайындалады, бірақ бұл кемені көрсету үшін жақсы.

Енді біз ship_speed мәнін өзгерте аламыз және 1-ден жоғары кез-келген мән кемені жылдамырақ жылжытады. Бұл кеменің бөгде планеталықтарды атып түсіру үшін жеткілікті жылдам әрекет етуіне көмектеседі және ойыншы геймплей барысында алға жылжып жатқанда ойын қарқынын өзгертуге мүмкіндік береді.

Кеменің ауқымын шектеу

Кодтың қазіргі жағдайында көрсеткі пернені тым ұзақ басып тұрсаңыз, кеме экранның екі шетінен де жоғалып кетеді. Кеме экранның шетіне жеткенде қозғалысын тоқтататындай етіп түзетейік. Біз мұны update() әдісін Ship ішінде өзгерту арқылы жасаймыз:

ship.py


            def update(self):
                """Қозғалыс жалаулары негізінде кеменің орнын жаңарту."""
                # Update the ship's x value, not the rect.
                 if self.moving_right and self.rect.right < self.screen_rect.right:
                    self.x += self.settings.ship_speed
                 if self.moving_left and self.rect.left > 0:
                    self.x -= self.settings.ship_speed
        
                # Update rect object from self.x.
                self.rect.x = self.x

Бұл код self.x мәнін өзгертпес бұрын кеменің орнын тексереді. self.rect.right коды кеменің rect оң жақ жиегінің x- координатын қайтарады. Бұл мән self.screen_rect.right қайтарған мәннен аз болса, кеме экранның оң жақ шетіне жеткен жоқ ❶. Сол жақ жиекке де солай болады: егер rect сол жағының мәні 0-ден үлкен болса, кеме экранның сол жақ жиегіне жетпеген . Бұл self.x мәнін реттемес бұрын кеменің осы шектерде болуын қамтамасыз етеді.

Қазір alien_invasion.py іске қосылғанда, кеме экранның кез-келген шетінде қозғалуды тоқтатуы керек. Бұл өте керемет; біз тек if амалынане шартты сынақты қостық, бірақ кеме экранның екі шетіндегі қабырғаға немесе күш өрісіне соғылғандай әсер қалдырады!

_check_events() қайта өңдеу

Ойынның дамуын жалғастырған сайын _check_events() әдісі ұзарады, сондықтан _check_events() әдісін екі бөлек әдіске бөлейік: біреуі KEYDOWN оқиғаларын өңдейді және екіншісі KEYUP оқиғаларын өңдейді:

alien_invasion.py


            def _check_events(self):
                """Пернелерді басу және тінтуір оқиғаларына жауап беру."""
                for event in pygame.event.get():
                    if event.type == pygame.QUIT:
                        sys.exit()
                    elif event.type == pygame.KEYDOWN:
                        self._check_keydown_events(event)
                    elif event.type == pygame.KEYUP:
                        self._check_keyup_events(event)
        
            def _check_keydown_events(self, event):
                """Пернелерді басуға жауап беру."""
                if event.key == pygame.K_RIGHT:
                    self.ship.moving_right = True
                elif event.key == pygame.K_LEFT:
                    self.ship.moving_left = True
        
            def _check_keyup_events(self, event):
                """Негізгі шығарылымдарға жауап беру."""
                if event.key == pygame.K_RIGHT:
                    self.ship.moving_right = False
                elif event.key == pygame.K_LEFT:
                    self.ship.moving_left = False

Біз екі жаңа көмекші әдіс жасаймыз: _check_keydown_events() және _check_keyup_events(). Әрқайсысына self параметрі және event параметрі қажет. Бұл екі әдістің денесі _check_events() ішінен көшірілді және біз ескі кодты жаңа әдістерге шақырулармен ауыстырдық. _check_events() әдісі енді осы таза код құрылымымен оңайырақ, бұл ойыншы енгізуіне әрі қарай жауаптарды әзірлеуді жеңілдетеді.

Шығу үшін Q пернесін басу

Енді біз пернелерді басуға тиімді жауап беріп жатқандықтан, ойыннан шығудың басқа жолын қоса аламыз. Жаңа мүмкіндікті сынаған сайын ойынды аяқтау үшін ойын терезесінің жоғарғы жағындағы X түймесін басу жалықтырады, сондықтан ойыншы Q түймесін басқанда ойынды аяқтау үшін пернелер тіркесімін қосамыз:

alien_invasion.py


            def _check_keydown_events(self, event):
                --snip/код үзіндісі--
                elif event.key == pygame.K_LEFT:
                    self.ship.moving_left = True
                elif event.key == pygame.K_q:
                    sys.exit()

_check_keydown_events() ішінде біз ойыншы Q пернесін басқанда ойынды аяқтайтын жаңа блок қосамыз. Енді тестілеу кезінде, жабу үшін жүгіргіні пайдаланудың орнына ойынды жабу үшін Q түймесін басуға болады. терезе.

Ойынды толық экран режимінде іске қосу

Pygame-де толық экран режимі бар, ол ойынды кәдімгі терезеде іске қосқаннан гөрі ұнауы мүмкін. Кейбір ойындар толық экран режимінде жақсырақ көрінеді, ал кейбір жүйелерде ойын толық экран режимінде жақсырақ жұмыс істеуі мүмкін.

Ойынды толық экран режимінде іске қосу үшін __init__() ішінде келесі өзгерістерді жасаңыз:

alien_invasion.py


            def __init__(self):
                """Ойынды инициализациялаңыз және ойын ресурстарын жасаңыз."""
                pygame.init()
                self.settings = Settings()
        
                 self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
                 self.settings.screen_width = self.screen.get_rect().width
                self.settings.screen_height = self.screen.get_rect().height
                pygame.display.set_caption("Alien Invasion")

Экран бетін құру кезінде біз (0, 0) өлшемін және pygame.FULLSCREEN параметрін береміз.❶. Бұл Pygame-ге экранды толтыратын терезе өлшемін анықтауды ұсынады. Біз экранның ені мен биіктігін алдын ала білмегендіктен, экран жасалғаннан кейін бұл параметрлерді жаңартамыз.❷.Біз settings нысанын жаңарту үшін экранның rect атрибуттарының width және height атрибуттарын қолданамыз.

Егер ойынның толық экран режимінде қалай көрінетіні немесе әрекеті ұнаса, осы параметрлерді сақтаңыз. Егер сізге ойын өз терезесінде ұнаса, ойынға арнайы экран өлшемін орнатқан бастапқы әдіске оралуға болады.

Аралық қорытынды

Келесі бөлімде біз оқ ату мүмкіндігін қосамыз, ол bullet.py деп аталатын жаңа файлды қосып, кейбір файлдарға өзгертулер енгізуді қамтиды. Дәл қазір бізде бірнеше класстар мен әдістерді қамтитын үш файл бар. Жобаның қалай ұйымдастырылғанын түсіну үшін қосымша функцияларды қоспас бұрын осы файлдардың әрқайсысын қарап шығайық.

alien_invasion.py

Негізгі файл alien_invasion.py құрамында AlienInvasion классы бар. Бұл класс ойын барысында қолданылатын бірқатар маңызды атрибуттарды жасайды: параметрлер settings, негізгі дисплей беті screen және ship үшін тағайындалады. данасы осы файлда да жасалған. Ойынның негізгі циклі, while циклі де осы модульде сақталады. while циклі _check_events(), ship.update() және _update_screen() шақырады. Ол сонымен қатар цикл арқылы әр өту кезінде сағатты белгілейді.

_check_events() әдісі пернені басу және шығару сияқты сәйкес оқиғаларды анықтайды және осы оқиғалар түрлерінің әрқайсысын _check_keydown_events() және әдістері арқылы өңдейді. _check_keyup_events(). Әзірге бұл әдістер кеменің қозғалысын басқарады. AlienInvasion классында сонымен қатар негізгі цикл арқылы әрбір өтуде экранды қайта сызатын _update_screen() бар.

alien_invasion.py файлы Alien Invasion ойынын ойнағыңыз келгенде іске қосу қажет жалғыз файл. Басқа файлдар, settings.py және ship.py, осы файлға импортталған кодты қамтиды.

settings.py

settings.py файлында Параметрлер классы бар. Бұл класста ойынның сыртқы түрі мен кеменің жылдамдығын басқаратын атрибуттарды инициализациялайтын __init__() әдісі ғана бар.

ship.py

ship.py файлында Ship классы бар. Ship классында __init__() әдісі, кеменің орнын басқаруға арналған update() әдісі және blitme() бар. әдісі арқылы кемені экранға шығару. Кеме суреті images каталогында орналасқан ship.bmp ішінде сақталады.

Оқ ату

Енді оқ ату мүмкіндігін қосайық. Ойыншы бос орын пернесін басқан кезде біз кішкентай тіктөртбұрышпен бейнеленген оқ ататын кодты жазамыз. Содан кейін оқтар экранның жоғарғы жағында жоғалып кеткенше тікелей экранға көтеріледі.

Маркер параметрлерін қосу

__init__() әдісінің соңында жаңа нұсқаға қажет мәндерді қосу үшін settings.py жаңартамыз. Bullet класы:

settings.py

    def __init__(self):
                --snip/код үзіндісі--
                # Bullet settings
                self.bullet_speed = 2.0
                self.bullet_width = 3
                self.bullet_height = 15
                self.bullet_color = (60, 60, 60)

Бұл параметрлер ені 3 пиксель және биіктігі 15 пиксель болатын қою сұр түсті таңбалауыштарды жасайды. Оқтар кемеден сәл жылдамырақ қозғалады.

Маркер классын жасау

Енді Bullet классымызды сақтау үшін bullet.py файлын жасаңыз. Міне, bullet.py файлының бірінші бөлігі:

bullet.py

import pygame
        from pygame.sprite import Sprite
        
        class Bullet(Sprite):
            """Кемеден атылған оқтарды басқару класы."""
        
            def __init__(self, ai_game):
                """Кеменің ағымдағы орнында оқ нысанын жасаңыз."""
                super().__init__()
                self.screen = ai_game.screen
                self.settings = ai_game.settings
                self.color = self.settings.bullet_color
        
                # Create a bullet rect at (0, 0) and then set correct position.
                 self.rect = pygame.Rect(0, 0, self.settings.bullet_width,
                    self.settings.bullet_height)
                 self.rect.midtop = ai_game.ship.rect.midtop
        
                # Store the bullet's position as a float.
                 self.y = float(self.rect.y)

Bullet классы Sprite класынан мұраланады, біз оны pygame.sprite модулінен импорттаймыз. Спрайттарды пайдаланған кезде ойыныңыздағы қатысты элементтерді топтап, барлық топтастырылған элементтерде бірден әрекет ете аласыз. Маркер данасын жасау үшін __init__() қолданбасына AlienInvasion ағымдағы данасы қажет және біз ішінен дұрыс мұра алу үшін super() шақырамыз. Sprite. Біз сондай-ақ экран мен параметрлер нысандары мен таңбалауыш түсі үшін атрибуттарды орнатамыз.

Содан кейін таңбалауыштың rect атрибутын жасаймыз❶. Маркер кескінге негізделмеген, сондықтан pygame.Rect() классын пайдаланып, нөлден бастап rect құруымыз керек. Бұл класс түзетудің жоғарғы сол жақ бұрышының x- және y- координаттарын және ені мен биіктігін қажет етеді. түзету. Біз тік мәнін (0, 0) инициализациялаймыз, бірақ оны келесі Тіркестегі дұрыс орынға жылжытамыз, себебі оқтың орны кеменің орнына байланысты. Маркердің ені мен биіктігін self.settings ішінде сақталған мәндерден аламыз.

Біз маркердің midtop атрибутын кеменің midtop атрибуты ❷ сәйкестендіру үшін орнаттық. Бұл оқ кеменің жоғарғы жағынан шығып, оқ кемеден атылғандай болады. Марканың y-координатасы үшін қалқымалы мәнді пайдаланамыз, осылайша таңбаның жылдамдығына ❸ дәл түзетулер жасай аламыз..

Міне, bullet.py, update() және draw_bullet() файлдарының екінші бөлігі:

bullet.py

    def update(self):
                """Оқ таңбаны экранда жоғары жылжытыңыз."""
                # Update the exact position of the bullet.
                 self.y -= self.settings.bullet_speed
                # Update the rect position.
                 self.rect.y = self.y
        
            def draw_bullet(self):
                """Оқ таңбаны экранға сызыңыз."""
                 pygame.draw.rect(self.screen, self.color, self.rect)

update() әдісі маркердің орнын басқарады. Оқ атылғанда, ол төмендейтін yкоординат мәніне сәйкес келетін экранда жоғары жылжиды. Орынды жаңарту үшін settings.bullet_speed ішінде сақталған соманы self.y ❶ ішінен шегереміз. Содан кейін self.y мәнін self.rect.y ❷ мәнін орнату үшін пайдаланамыз.

bullet_speed параметрі ойын барысында немесе ойын тәртібін жақсарту үшін қажет болғанда оқтардың жылдамдығын арттыруға мүмкіндік береді. Оқ атылғаннан кейін біз оның x-координатының мәнін ешқашан өзгертпейміз, сондықтан ол кеме қозғалса да, тік сызық бойымен қозғалады.

Маркер салғымыз келгенде, draw_bullet() деп атаймыз. draw.rect() функциясы таңбалауыштың түзу арқылы анықталған экран бөлігін self.color ішінде сақталған түспен толтырады.❸.

Марктарды топта сақтау

Енді бізде Bullet классы және анықталған қажетті параметрлер бар, біз ойнатқыш бос орын пернесін басқан сайын оқ шығару үшін код жаза аламыз. Біз барлық белсенді таңбаларды сақтау үшін AlienInvasion ішінде топ құрамыз, осылайша біз бұрыннан іске қосылған оқтарды басқара аламыз. Бұл топ pygame.sprite.Group классының данасы болады, ол ойындарды құру кезінде пайдалы болатын кейбір қосымша функциялары бар тізім сияқты әрекет етеді. Біз бұл топты негізгі цикл арқылы әрбір өтуде экранға таңбалар салу және әрбір таңбаның орнын жаңарту үшін пайдаланамыз.

Біріншіден, жаңа Bullet классын импорттаймыз:

alien_invasion.py

--snip/код үзіндісі--
        from ship import Ship
        from bullet import Bullet

Кейін біз __init__() ішіндегі таңбаларды сақтайтын топты жасаймыз:

alien_invasion.py

    def __init__(self):
                --snip/код үзіндісі--
                self.ship = Ship(self)
                self.bullets = pygame.sprite.Group()

Одан кейін біз while циклі арқылы әр өтудегі таңбалардың орнын жаңартуымыз керек:

alien_invasion.py

    def run_game(self):
                """Ойынның негізгі циклін бастау."""
                while True:
                    self._check_events()
                    self.ship.update()
                    self.bullets.update()
                    self._update_screen()
                    self.clock.tick(60)

Топта update() шақырған кезде, топ автоматты түрде топтағы әрбір спрайт үшін update() шақырады. self.bullets.update() жолы bullets тобына орналастыратын әрбір таңбалауыш үшін bullet.update() шақырады.

Оқ ату

AlienInvasion жүйесінде ойыншы бос орын пернесін басқан кезде оқ ату үшін _check_keydown_events() параметрін өзгертуіміз керек. Бізге _check_keyup_events() параметрін өзгертудің қажеті жоқ, себебі бос орын босатылған кезде ештеңе болмайды. Сондай-ақ, flip() шақырмас бұрын әрбір таңбалауыштың экранға сызылғанына көз жеткізу үшін _update_screen() өзгертуіміз керек.

Оқ атылғанда біраз жұмыс істеу керек, сондықтан осы жұмысты орындау үшін _fire_bullet() атты жаңа әдісті жазайық:

alien_invasion.py

    def _check_keydown_events(self, event):
                --snip/код үзіндісі--
                elif event.key == pygame.K_q:
                    sys.exit()
                 elif event.key == pygame.K_SPACE:
                    self._fire_bullet()
        
            def _check_keyup_events(self, event):
                --snip/код үзіндісі--
        
            def _fire_bullet(self):
                """Жаңа таңбалауыш жасаңыз және оны таңбалар тобына қосыңыз."""
                 new_bullet = Bullet(self)
                 self.bullets.add(new_bullet)
        
            def _update_screen(self):
                """Экрандағы кескіндерді жаңартыңыз және жаңа экранға өтіңіз."""
                self.screen.fill(self.settings.bg_color)
                 for bullet in self.bullets.sprites():
                    bullet.draw_bullet()
                self.ship.blitme()
        
                pygame.display.flip()
        --snip/код үзіндісі--

Бос орын басылғанда _fire_bullet() шақырамыз ❶. _fire_bullet() ішінде біз Bullet данасын жасап, оны new_bullet деп атаймыз.❷. Содан кейін оны add() әдісі арқылы bullets тобына қосамыз.❸. add() әдісі append() әдісіне ұқсас, бірақ ол Pygame топтары үшін арнайы жазылған.

bullets.sprites() әдісі bullets тобындағы барлық спрайттардың тізімін қайтарады. Барлық атылған оқтарды экранға салу үшін bullets ішіндегі спрайттарды айналдырып, әрқайсысында draw_bullet() шақырамыз . Біз бұл ілмекті кемені сызатын сызықтың алдына қоямыз, сондықтан оқтар кеменің үстінен шықпайды.

Қазір alien_invasion.py қолданбасын іске қосқан кезде, кемені оңға және солға жылжытып, қалағаныңызша көп оқ атуға мүмкіндігіңіз болуы керек. 12-3-сурет-де көрсетілгендей, оқтар экранда жоғары қозғалады және жоғарғы жағына жеткенде жоғалады. Таңбалардың өлшемін, түсін және жылдамдығын settings.py арқылы өзгертуге болады.

12-3-сурет: Оқтардың сериясын атқаннан кейінгі кеме

Ескі таңбаларды жою

Қазіргі уақытта оқтар шыңға жеткенде жоғалып кетеді, бірақ тек Pygame оларды экранның жоғарғы жағынан тарта алмайтындықтан ғана. Оқтар шын мәнінде бар болуын жалғастырады; олардың y-координат мәндері барған сайын теріс өседі. Бұл мәселе, себебі олар жад пен өңдеу қуатын тұтынуды жалғастыруда.

Осы ескі оқтардан құтылуымыз керек, әйтпесе ойын соншалықты қажетсіз жұмысты орындаудан баяулайды. Бұл әрекетті орындау үшін, таңбалауыштың rect мәнінің төменгі мәні экранның жоғарғы жағынан өткенін көрсететін 0 мәніне ие болғанда анықтауымыз керек:

alien_invasion.py

    def run_game(self):
                """Ойынның негізгі циклін бастау."""
                while True:
                    self._check_events()
                    self.ship.update()
                    self.bullets.update()
        
                    # Get rid of bullets that have disappeared.
                     for bullet in self.bullets.copy():
                         if bullet.rect.bottom <= 0:
                             self.bullets.remove(bullet)
                     print(len(self.bullets))
        
                    self._update_screen()
                    self.clock.tick(60)

Тізіммен (немесе Pygame жүйесіндегі топпен) for циклін пайдаланған кезде, Python цикл жұмыс істеп тұрған кезде тізім бірдей ұзындықта қалады деп күтеді. Бұл for цикліндегі тізімнен немесе топтан элементтерді жоя алмайтыныңызды білдіреді, сондықтан біз топтың көшірмесін айналдыруымыз керек. for циклін орнату үшін copy() әдісін қолданамыз❶,бұл бізге цикл ішіндегі бастапқы bullets тобын өзгертуге мүмкіндік береді. Біз әрбір оқтың экранның жоғарғы жағында жоғалып кеткенін тексеру үшін тексереміз ❷. Бар болса, оны bullets ішінен алып тастаймыз❸.Ойында қазір қанша таңбалауыш бар екенін көрсету және экранның жоғарғы жағына жеткенде олардың жойылып жатқанын тексеру үшін print() шақыруын енгіземіз.❹.

Егер бұл код дұрыс жұмыс істесе, біз оқтарды ату кезінде терминал шығысын бақылай аламыз және оқтардың әрбір сериясы экранның үстіңгі жағын тазартқаннан кейін оқтар саны нөлге дейін азайғанын көре аламыз. Ойынды іске қосып, таңбалардың дұрыс жойылып жатқанын тексергеннен кейін print() шақыруын алып тастаңыз. Оны қалдырсаңыз, ойын айтарлықтай баяулайды, себебі терминалға нәтиже жазу ойын терезесіне графика салуға қарағанда көбірек уақыт алады.

Маркалар санын шектеу

Көп ату ойындары ойыншының экранда бір уақытта болуы мүмкін оқтардың санын шектейді; бұл ойыншыларды дәл атуға ынталандырады. Біз Бөтендік шабуылда да солай істейміз.

Біріншіден, рұқсат етілген таңбалар санын settings.py ішінде сақтаңыз:

settings.py

        # Bullet settings
                --snip/код үзіндісі--
                self.bullet_color = (60, 60, 60)
                self.bullets_allowed = 3

This limits the player to three bullets at a time. We’ll use this setting in AlienInvasion to check how many bullets exist before creating a new bullet in _fire_bullet():

alien_invasion.py

    def _fire_bullet(self):
                """Жаңа таңбалауыш жасаңыз және оны таңбалар тобына қосыңыз."""
                if len(self.bullets) < self.settings.bullets_allowed:
                    new_bullet = Bullet(self)
                    self.bullets.add(new_bullet)

Ойыншы бос орын пернесін басқанда, біз оқтар ұзындығын тексереміз. Егер len(self.bullets) үштен аз болса, біз жаңа таңбалауыш жасаймыз. Бірақ егер үш таңба белсенді болса, бос орын пернесін басқанда ештеңе болмайды. Ойынды қазір іске қосқанда, сіз тек үш топта оқ атуыңыз керек.

_update_bullets() әдісін жасау

Біз AlienInvasion классын жақсы ұйымдастырылған ұстағымыз келеді, сондықтан таңбаларды басқару кодын жазып, тексергеннен кейін оны бөлек әдіске жылжытуға болады. Біз _update_bullets() деп аталатын жаңа әдісті жасаймыз және оны _update_screen() алдында қосамыз:

alien_invasion.py

    def _update_bullets(self):
                """Оқтардың орнын жаңартып, ескі оқтардан арылыңыз."""
                # Update bullet positions.
                self.bullets.update()
        
                # Get rid of bullets that have disappeared.
                for bullet in self.bullets.copy():
                    if bullet.rect.bottom <= 0:
                         self.bullets.remove(bullet)

_update_bullets() коды қиылып, run_game() ішінен қойылады; Мұнда біз тек түсініктемелерді нақтылау ғана істедік.

run_game() ішіндегі while циклі қайтадан қарапайым болып көрінеді:

alien_invasion.py

         while True:
                    self._check_events()
                    self.ship.update()
                    self._update_bullets()
                    self._update_screen()
                    self.clock.tick(60)

Енді біздің негізгі циклде тек минималды код бар, сондықтан әдіс атауларын жылдам оқып, ойында не болып жатқанын түсінуге болады. Негізгі цикл ойыншының енгізуін тексереді, содан кейін кеменің орнын және атылған кез-келген оқтарды жаңартады. Содан кейін біз жаңа экранды салу үшін жаңартылған позицияларды пайдаланамыз және цикл арқылы әр өтудің соңында сағатты белгілейміз.

alien_invasion.py қолданбасын тағы бір рет іске қосыңыз және оқтарды қатесіз жібере алатыныңызға көз жеткізіңіз.

Қорытынды

Бұл тарауда сіз ойынға жоспар құруды үйрендіңіз және Pygame-де жазылған ойынның негізгі құрылымын білдіңіз. Фон түсін орнатуды және параметрлерді оңай реттеуге болатын бөлек класста сақтауды үйрендіңіз. Сіз экранға сурет салуды және ойыншыға ойын элементтерінің қозғалысын басқаруды қалай беру керектігін көрдіңіз. Сіз экранда ұшатын оқтар сияқты өздігінен қозғалатын элементтерді жасадыңыз және енді қажет емес нысандарды жойдыңыз. Сондай-ақ жобадағы кодты тұрақты негізде қайта өңдеуді үйрендіңіз.

13-тарауда біз өзге планеталықтарды өзге планеталықтардың шабуылына қосамыз. Тараудың соңында сіз өзге планеталықтарды кемеңізге жеткенше атып түсіре аласыз!

Aliens!

ITUniver

13
Aliens!

Бұл тарауда біз өзге планеталықтарды Жат планеталық шабуылға қосамыз. Біз экранның жоғарғы жағына бір бөтен адамды қосамыз, содан кейін өзге планеталықтардың бүкіл флотын жасаймыз. Біз флотты бүйірден және төмен қарай жылжытамыз және оқ тиген кез-келген өзге планеталықтардан құтыламыз. Соңында, ойыншының кемелерінің санын шектейміз және ойыншының кемелері таусылғанда ойынды аяқтаймыз.

Осы тараумен жұмыс істеу барысында сіз Pygame және үлкен жобаны басқару туралы көбірек біле аласыз. Сіз сондай-ақ оқтар мен өзге планеталықтар сияқты ойын нысандары арасындағы қақтығыстарды анықтауды үйренесіз. Соқтығыстарды анықтау ойындарыңыздағы элементтер арасындағы өзара әрекеттесуді анықтауға көмектеседі. Мысалы, сіз кейіпкерді лабиринт қабырғаларының ішінде шектей аласыз немесе екі кейіпкердің арасында допты өткізе аласыз. Біз кодты жазу сеанстарының басты назарын сақтау үшін анда-санда қайталайтын жоспар бойынша жұмыс істеуді жалғастырамыз.

Экранға өзге планеталықтар флотын қосу үшін жаңа код жазуды бастамас бұрын, жобаны қарастырып, жоспарымызды жаңартайық.

Жобаны шолу

Үлкен жобада дамудың жаңа кезеңін бастағанда, жоспарыңызды қайта қарап шығып, жазғалы тұрған код арқылы нені орындағыңыз келетінін нақтылағаныңыз жөн. Бұл тарауда біз келесі әрекеттерді орындаймыз:

  • Экранның жоғарғы сол жақ бұрышына айналасында сәйкес бос орын қалдыра отырып, жалғыз бөтен планетаны қосыңыз.
  • Экранның үстіңгі бөлігін көлденеңінен мүмкіндігінше көп өзге планеталықтармен толтырыңыз. Содан кейін бізде толық флот болғанша, біз өзге планеталықтардың қосымша қатарларын жасаймыз.
  • Бүкіл флот атып түсірілгенше, бөтен адам кемені соққанша немесе бөтен адам жерге жеткенше флотты бүйіріне және төмен қарай жылжытыңыз. Егер бүкіл флот жойылса, біз жаңа флот құрамыз. Егер бөтен адам кемеге немесе жерге соғылса, біз кемені жойып, жаңа флот құрамыз.
  • Ойыншы пайдалана алатын кемелер санын шектеңіз және ойыншы бөлінген кемелер санын пайдаланған кезде ойынды аяқтаңыз.

Функцияларды іске асыру барысында біз бұл жоспарды нақтылаймыз, бірақ бұл код жазуды бастау үшін жеткілікті.

Сонымен қатар жобадағы мүмкіндіктердің жаңа сериясымен жұмыс істей бастағанда бар кодты қарап шығу керек. Әрбір жаңа кезең әдетте жобаны күрделірек ететіндіктен, кез-келген ретсіз немесе тиімсіз кодты тазалаған дұрыс. Біз барған сайын рефакторинг жүргізіп жатырмыз, сондықтан қазір қайта өңдеуді қажет ететін код жоқ.

Бірінші бөтен планеталықты жасау

Экранға бір бөтен адамды орналастыру экранға кеме орналастырумен бірдей. Әрбір бөтен адамның әрекетін Alien деп аталатын класс басқарады, біз оны Ship классы сияқты құрастырамыз. Қарапайымдылық үшін нүктелік кескіндерді пайдалануды жалғастырамыз. Сіз бөтен планеталық үшін өзіңіздің суретіңізді таба аласыз немесе кітап ресурстарында қол жетімді 13-1-сурет-де көрсетілген суретті пайдалана аласыз. https://ehmatthes.github.io/pcc_3e. Бұл кескінде экранның өң түсіне сәйкес келетін сұр фон бар. Таңдалған кескін файлын суреттер каталогында сақтағаныңызға көз жеткізіңіз.

13-1-сурет: флот құру үшін біз пайдаланатын бөтен адам

Бөтен классты жасау

Енді біз Alien классын жазып, оны alien.py ретінде сақтаймыз:

alien.py

import pygame
        from pygame.sprite import Sprite
        
        class Alien(Sprite):
            """Флоттағы жалғыз шетелдікті көрсететін сынып."""
        
            def __init__(self, ai_game):
                """Инопланетаны инициализациялаңыз және оның бастапқы орнын орнатыңыз."""
                super().__init__()
                self.screen = ai_game.screen
        
                # Load the alien image and set its rect attribute.
                self.image = pygame.image.load('images/alien.bmp')
                self.rect = self.image.get_rect()
        
                # Start each new alien near the top left of the screen.
                 self.rect.x = self.rect.width
                self.rect.y = self.rect.height
        
                # Store the alien's exact horizontal position.
                 self.x = float(self.rect.x)

Бұл класстың көпшілігі бөгде адамның экранда орналасуын қоспағанда, Ship классына ұқсайды. Бастапқыда біз әрбір бөтен адамды экранның жоғарғы сол жақ бұрышына жақын орналастырамыз; оның сол жағына бөтеннің еніне тең бос орын және оның биіктігіне тең бос орын ❶ қосамыз, сондықтан оны көру оңай. . Біз негізінен бөгде планетаның көлденең жылдамдығымен айналысамыз, сондықтан біз әрбір бөтеннің көлденең орналасуын дәл ❷ бақылаймыз.

Бұл Alien класы оны экранға салу әдісін қажет етпейді; оның орнына біз топтың барлық элементтерін экранға автоматты түрде тартатын Pygame тобы әдісін қолданамыз.

бөтен планеталықтың данасын жасау

Біз экранда бірінші бөтен планетаны көру үшін Alien данасын жасағымыз келеді. Бұл орнату жұмысымыздың бір бөлігі болғандықтан, біз осы дананың кодын AlienInvasion ішіндегі __init__() әдісінің соңына қосамыз. Ақыр соңында, біз өзге планеталықтардың толық флотын жасаймыз, бұл біршама жұмысты талап етеді, сондықтан _create_fleet() деп аталатын жаңа көмекші әдіс жасаймыз.

Класстағы әдістердің реті маңызды емес, тек олардың орналасуына сәйкестік болса. Мен _create_fleet() параметрін _update_screen() әдісінің дәл алдында орналастырамын, бірақ AlienInvasion қолданбасының кез-келген жерінде жұмыс істейді. Алдымен Alien классын импорттаймыз.

Міне, alien_invasion.py үшін жаңартылған import амалдары:

alien_invasion.py

--snip/код үзіндісі--
        from bullet import Bullet
        from alien import Alien

Міне, жаңартылған __init__() әдісі:

alien_invasion.py

    def __init__(self):
                --snip/код үзіндісі--
                self.ship = Ship(self)
                self.bullets = pygame.sprite.Group()
                self.aliens = pygame.sprite.Group()
        
                self._create_fleet()

Біз өзге планеталықтар флотын ұстау үшін топ құрамыз және біз жазғалы тұрған _create_fleet() деп атаймыз.

Міне, жаңа _create_fleet() әдісі:

alien_invasion.py

    def _create_fleet(self):
                """Шетелдіктер флотын жасаңыз."""
                # Make an alien.
                alien = Alien(self)
                self.aliens.add(alien)

Бұл әдісте біз Alien бір данасын жасап, оны флотты ұстайтын топқа қосамыз. Бөтен адам экранның әдепкі жоғарғы сол жақ аймағына орналастырылады.

бөтен планеталықтың пайда болуы үшін біз топтың _update_screen() ішіндегі draw() әдісін шақыруымыз керек:

alien_invasion.py

    def _update_screen(self):
                --snip/код үзіндісі--
                self.ship.blitme()
                self.aliens.draw(self.screen)
        
                pygame.display.flip()

Топта draw() функциясын шақырған кезде, Pygame топтағы әрбір элементті оның rect атрибутымен анықталған орынға салады. draw() әдісі бір аргументті талап етеді: топтан элементтерді сызуға болатын бет. 13-2-сурет экрандағы бірінші бөтен планетаны көрсетеді.

13-2-сурет: Бірінші бөгде адам пайда болады.

Енді бірінші бөтен планеталық дұрыс пайда болған соң, біз бүкіл флотты салу үшін кодты жазамыз.

Өзге планеталықтың флотын құру

Флотты салу үшін ойын терезесін толып кетпей, экранның жоғарғы бөлігін өзге планеталықтармен қалай толтыру керектігін анықтау керек. Бұл мақсатқа жетудің бірнеше жолы бар. Біз оған жаңа бөтен планеталық үшін бос орын қалмайынша, экранның жоғарғы жағына өзге планеталықтарды қосу арқылы жақындаймыз. Содан кейін бізде жаңа жол қосу үшін тік бос орын жеткілікті болған кезде бұл процесті қайталаймыз.

өзге планеталықтар қатарын жасау

Енді біз өзге планеталықтардың толық қатарын жасауға дайынбыз. Толық Тіркесті жасау үшін алдымен бір бөтен планетаны жасаймыз, осылайша біз бөтеннің еніне қол жеткізе аламыз. Біз бөтен планетаны экранның сол жағына орналастырамыз, содан кейін бос орын таусылғанша бөтен планеталықтарды қоса береміз:

alien_invasion.py

    def _create_fleet(self):
                """Шетелдіктер флотын жасаңыз."""
                # Create an alien and keep adding aliens until there's no room left.
                # Spacing between aliens is one alien width.
                alien = Alien(self)
                alien_width = alien.rect.width
        
                 current_x = alien_width
                 while current_x < (self.settings.screen_width - 2 * alien_width):
                     new_alien = Alien(self)
                     new_alien.x = current_x
                    new_alien.rect.x = current_x
                    self.aliens.add(new_alien)
                     current_x += 2 * alien_width

Біз бірінші жасаған бөтен планеталықтың енін аламыз, содан кейін current_x ❶ деп аталатын айнымалы мәнді анықтаймыз. Бұл экранға орналастырғалы отырған келесі бөтен адамның көлденең орналасуына қатысты. Флоттағы бірінші инопланетаны экранның сол жақ шетінен ығыстыру үшін біз оны бастапқыда бір бөтен енге орнаттық.

Кейін, while циклін бастаймыз ❷; біз оларды орналастыруға жеткілікті орын болғанша бөтен адамдарды қосуды жалғастырамыз. Басқа бөтен планетаны орналастыруға орын бар-жоғын анықтау үшін current_x мәнін максималды мәнмен салыстырамыз. Бұл циклды анықтаудың бірінші әрекеті келесідей болуы мүмкін:

while current_x < self.settings.screen_width:

Бұл жұмыс істейтін сияқты, бірақ ол соңғы бөгде адамды экранның оң жақ шетіндегі жолға орналастырады. Сонымен, біз экранның оң жағына аздап маржа қосамыз. Экранның оң жақ шетінде кемінде екі бөтен ені бос орын болса, біз циклге кіріп, флотқа басқа бөтен адамды қосамыз.

Циклді жалғастыру үшін көлденең кеңістік жеткілікті болған кезде, біз екі әрекетті орындағымыз келеді: дұрыс позицияда бөтен адамды жасау және Тіркестегі келесі бөтеннің көлденең орнын анықтау. Бөтен планетаны жасап, оны new_alien ❸ тағайындаймыз. Содан кейін біз дәл көлденең орынды current_x ❹ ағымдағы мәніне орнатамыз. Біз сондай-ақ бөтен планеталықтың rect-ін дәл осы x мәнінде орналастырамыз және жаңа бөтен планетаны self.aliens тобына қосамыз.

Соңында, current_x ❺ мәнін арттырамыз. Біз жаңа ғана қосқан бөгде планетаның жанынан өту және өзге планеталықтар арасында бос орын қалдыру үшін көлденең позицияға екі бөтен енді қосамыз. Python while циклінің басындағы жағдайды қайта бағалайды және басқа бөтен адамға орын бар-жоғын шешеді. Бос орын қалмағанда, цикл аяқталады және бізде өзге планеталықтардың толық қатары болуы керек.

Соңында, current_x ❺ мәнін арттырамыз. Біз жаңа ғана қосқан бөгде планетаның жанынан өту және өзге планеталықтар арасында бос орын қалдыру үшін көлденең позицияға екі бөтен енді қосамыз. Python while циклінің басындағы жағдайды қайта бағалайды және басқа бөтен адамға орын бар-жоғын шешеді. Бос орын қалмағанда, цикл аяқталады және бізде өзге планеталықтардың толық қатары болуы керек.

13-3-сурет: өзге планеталықтардың бірінші қатары

_create_fleet() рефакторингі

Егер біз осы уақытқа дейін жазған код флот құру үшін қажет болса, біз _create_fleet() қызметін сол күйінде қалдырар едік. Бірақ бізде көп жұмыс бар, сондықтан әдісті сәл тазартайық. Біз _create_alien() атты жаңа көмекші әдісті қосамыз және оны _create_fleet() арқылы шақырамыз:

alien_invasion.py

    def _create_fleet(self):
                --snip/код үзіндісі--
                while current_x < (self.settings.screen_width - 2 * alien_width):
                    self._create_alien(current_x)
                    current_x += 2 * alien_width
        
             def _create_alien(self, x_position):
                """Инопланетаны жасап, оны қатарға орналастырыңыз."""
                new_alien = Alien(self)
                new_alien.x = x_position
                new_alien.rect.x = x_position
                self.aliens.add(new_alien)

_create_alien() әдісі self параметріне қосымша бір параметрді қажет етеді: бөтен адамды қайда орналастыру керектігін көрсететін xмәні❶. _create_alien() корпусындағы код _create_fleet() ішіндегі кодпен бірдей, бірақ біз орында x_position параметр атауын қолданамыз. current_x. Бұл рефакторинг жаңа Тіркестерді қосуды және бүкіл флотты құруды жеңілдетеді.

Жолдар қосу

Флотты аяқтау үшін орын таусылғанша қосымша Тіркестерді қоса береміз. Біз кірістірілген циклды қолданамыз — ағымдағының айналасына тағы бір while циклін орап аламыз. Ішкі цикл өзге планеталықтардың xмәндеріне назар аудара отырып, өзге планеталықтарды бір қатарға көлденең орналастырады. Сыртқы цикл yмәндеріне назар аудару арқылы бөтен планеталарды тігінен орналастырады. Экранның төменгі жағына жақындағанда, кемеге жеткілікті орын қалдырып, бөгде планеталықтарға атуды бастау үшін біраз орын қалдырған кезде Тіркестерді қосуды тоқтатамыз.

Міне, екі while циклін _create_fleet() ішінде қалай кірістіру керек:

    def _create_fleet(self):
                """Шетелдіктер флотын жасаңыз."""
                # Create an alien and keep adding aliens until there's no room left.
                # Spacing between aliens is one alien width and one alien height.
                alien = Alien(self)
                 alien_width, alien_height = alien.rect.size
        
                 current_x, current_y = alien_width, alien_height
                 while current_y < (self.settings.screen_height - 3 * alien_height):
                    while current_x < (self.settings.screen_width - 2 * alien_width):
                         self._create_alien(current_x, current_y)
                        current_x += 2 * alien_width
        
                     # Finished a row; reset x value, and increment y value.
                    current_x = alien_width
                    current_y += 2 * alien_height

Тіркестерді орналастыру үшін бөтен адамның биіктігін білуіміз керек, сондықтан біз бөтен планеталықтың rect атрибуты арқылы бөтеннің ені мен биіктігін анықтаймыз.❶. rect-тің size атрибуты оның ені мен биіктігін қамтитын кортеж болып табылады..

Содан кейін біз флоттағы бірінші өзге планеталықтардыі орналастыру үшін бастапқы x- және yмәндерін орнатамыз.❷.Біз оны сол жақтан бір бөтен енді және жоғарыдан бір бөтен биіктікте орналастырамыз. Содан кейін экранға қанша жол орналастырылатынын басқаратын while циклін анықтаймыз.❸. Келесі Тіркестің yмәні экран биіктігінен кем болса, үш бөтен биіктікті алып тастағанда, біз Тіркестерді қосуды жалғастырамыз. (Егер бұл қажетті орын қалдырмаса, біз оны кейінірек реттей аламыз.)

Біз _create_alien() деп атаймыз және оған y-мәні, сонымен қатар оның x-позициясын береміз.❹.Бір сәтте _create_alien() өзгертеміз.

Кодтың соңғы екі жолының шегінісіне назар аударыңыз❺. Олар сыртқы while циклінің ішінде, бірақ ішкі while циклінің сыртында. Бұл блок ішкі цикл аяқталғаннан кейін орындалады; ол әрбір жол жасалғаннан кейін бір рет орындалады. Әрбір жол қосылғаннан кейін біз current_x мәнін қалпына келтіреміз, осылайша келесі Тіркестегі бірінші бөтен адам алдыңғы жолдардағы бірінші бөгделікпен бірдей орынға орналастырылады. Содан кейін біз current_y ағымдағы мәніне екі бөтен биіктікті қосамыз, осылайша келесі жол экранның одан әрі төменірек орналасады. Мұнда шегініс өте маңызды; егер осы бөлімнің соңында alien_invasion.py іске қосқан кезде дұрыс флотты көрмесеңіз, осы кірістірілген циклдардағы барлық Тіркестердің шегінісін тексеріңіз.

Инопланетаның тік орнын дұрыс орнату үшін _create_alien() өзгерту керек:

    def _create_alien(self, x_position, y_position):
                """Инопланетянды жасап, оны флотқа орналастырыңыз."""
                new_alien = Alien(self)
                new_alien.x = x_position
                new_alien.rect.x = x_position
                new_alien.rect.y = y_position
                self.aliens.add(new_alien)

Жаңа бөгде үшін y-мәнін қабылдау әдісінің анықтамасын өзгертеміз және әдістің негізгі бөлігіндегі rect тік орнын орнатамыз. .

Ойынды қазір іске қосқан кезде, суретте көрсетілгендей, өзге планеталықтардың толық флотын көруіңіз керек13-4-сурет.

13-4-сурет: Толық флот пайда болады.

Келесі бөлімде біз флотты жылжытамыз!

Флотты жылжыту

Енді өзге планеталықтар флотын экранның шетіне тигенше оң жаққа жылжытайық, содан кейін оны белгіленген мөлшерді түсіріп, басқа бағытта жылжытайық. Біз бұл қозғалысты барлық өзге планеталықтар атып түсірілгенше, біреуі кемемен соқтығысқанша немесе экранның төменгі жағына жеткенше жалғастырамыз. Флотты оңға жылжытудан бастайық.

өзге планеталықтарды оңға жылжыту

өзге планеталықтарды жылжыту үшін біз alien.py ішінде update() әдісін қолданамыз, оны әр бөтен планеталық үшін шақырамыз. өзге планеталықтар тобы. Алдымен әрбір бөтеннің жылдамдығын басқару үшін параметрді қосыңыз:

settings.py

    def __init__(self):
                --snip/код үзіндісі--
                # Alien settings
                self.alien_speed = 1.0

Одан кейін alien.py ішінде update() енгізу үшін осы параметрді пайдаланыңыз:

alien.py

    def __init__(self, ai_game):
                """Инопланетаны инициализациялаңыз және оның бастапқы орнын орнатыңыз."""
                super().__init__()
                self.screen = ai_game.screen
                self.settings = ai_game.settings
                --snip/код үзіндісі--
        
            def update(self):
                """ Бөтен адамды оңға жылжытыңыз."""
                 self.x += self.settings.alien_speed
                 self.rect.x = self.x

Біз __init__() ішінде settings параметрін жасаймыз, осылайша update() қолданбасында бөгде планетаның жылдамдығына қол жеткізе аламыз. Бөтен адамның орнын жаңартқан сайын, оны alien_speed ішінде сақталған сома бойынша оңға жылжытамыз. Біз бөтен адамның нақты орнын ❶ қалқымалы мәндерді сақтай алатын self.x атрибуты арқылы бақылаймыз. Одан кейін өзге планеталықтардың тік орнын жаңарту үшін self.x мәнін қолданамыз ❷.

Негізгі while циклінде бізде кеме және оқ позицияларын жаңарту үшін қоңыраулар бар. Енді біз әрбір өзге планеталықтардың орнын жаңарту үшін қоңырау қосамыз:

alien_invasion.py

        while True:
                    self._check_events()
                    self.ship.update()
                    self._update_bullets()
                    self._update_aliens()
                    self._update_screen()
                    self.clock.tick(60)

Біз флоттың қозғалысын басқару үшін кейбір кодты жазғалы жатырмыз, сондықтан _update_aliens() деп аталатын жаңа әдіс жасаймыз. Оқтар жаңартылғаннан кейін біз өзге планеталықтардың позицияларын жаңартамыз, өйткені жақын арада оқтардың кез-келген өзге планеталықтарға тигенін тексеретін боламыз.

Бұл әдісті модульде қай жерде орналастыру маңызды емес. Бірақ кодты реттелген күйде сақтау үшін мен оны _update_bullets()-дан кейін while цикліндегі әдіс шақыруларының ретімен сәйкестендіру үшін орналастырамын. Міне, _update_aliens() бірінші нұсқасы:

alien_invasion.py

    def _update_aliens(self):
                """Флоттағы барлық шетелдіктердің позицияларын жаңартыңыз."""
                self.aliens.update()

Біз әр бөтеннің update() әдісін шақыратын бөтен адамдар тобында update() әдісін қолданамыз. Alien Invasion қолданбасын қазір іске қосқанда, флоттың оңға қарай жылжып, экранның шетінен жоғалып кеткенін көруіңіз керек.

Флот бағытына арналған параметрлерді жасау

Енді біз флотты экранның оң жақ жиегіне соққанда экранның төмен және солға жылжуын қамтамасыз ететін параметрлерді жасаймыз. Бұл әрекетті орындау жолы:

settings.py

        # Alien settings
                self.alien_speed = 1.0
                self.fleet_drop_speed = 10
                # fleet_direction of 1 represents right; -1 represents left.
                self.fleet_direction = 1

fleet_drop_speed параметрі бөгде планетаның кез-келген шетіне жеткен сайын флоттың экранды қаншалықты жылдам түсіретінін басқарады. Бұл жылдамдықты өзге планеталықтардың көлденең жылдамдығынан бөліп алу пайдалы, осылайша екі жылдамдықты бір-бірінен тәуелсіз реттей аласыз.

fleet_direction параметрін енгізу үшін біз 'left' немесе 'right' сияқты мәтіндік мәнді пайдалана аламыз, бірақ біз флот бағыты үшін if-elif амалдарын сынау арқылы аяқтаңыз. Оның орнына, бізде тек екі бағыт бар болғандықтан, 1 және −1 мәндерін қолданып, флот бағытты өзгерткен сайын олардың арасында ауысайық. (Сандарды пайдаланудың да мағынасы бар, өйткені оңға жылжу әрбір бөтеннің x- координат мәніне қосуды, ал солға жылжыту әр бөтен планеталықтың x- координат мәнінен шегеруді қамтиды.)

өзге планеталықтардың шетке тигенін тексеру

Бізге бөтен адамның кез-келген шетінде бар-жоғын тексеру әдісі қажет және әрбір бөтен планеталықтың тиісті бағытта қозғалуына мүмкіндік беру үшін update() өзгертуіміз керек. Бұл код Alien класының бөлігі:

alien.py

    def check_edges(self):
                """Егер бөтен планета экранның шетінде болса, True мәнін қайтарыңыз."""
                screen_rect = self.screen.get_rect()
                 return (self.rect.right >= screen_rect.right) or (self.rect.left <= 0)
        
            def update(self):
                """ Бөтен адамды оңға немесе солға жылжытыңыз."""
                 self.x += self.settings.alien_speed * self.settings.fleet_direction
                self.rect.x = self.x

Жаңа әдісті check_edges() деп кез-келген бөтенде оның сол немесе оң жақ шетте екенін білуге болады. Егер оның rect атрибутының right атрибуты экранның атрибутының right атрибутынан үлкен немесе оған тең болса, бөгде адам оң жақ шетінде болады. түзу. Егер оның left мәні 0 ❶ мәнінен аз немесе оған тең болса, ол сол жақ шетте орналасады. Бұл шартты сынақты if блогына қоюдың орнына, біз сынақты тікелей return операторына қоямыз. Бұл әдіс бөгде планетаның оң немесе сол жақ шетінде болса, True мәнін, ал екі шетінде болмаса, False мәнін береді.

Біз update() әдісін бөтеннің жылдамдығын fleet_direction мәніне көбейту арқылы солға немесе оңға қозғалысқа рұқсат ету үшін өзгертеміз.❷. Егер fleet_direction 1 болса, alien_speed мәні бөтеннің ағымдағы орнына қосылып, бөтен адамды оңға жылжытады; егер fleet_direction −1 болса, мән бөтеннің орнынан шегеріліп, бөтен адамды солға жылжытады.

Флотты тастау және бағытты өзгерту

өзге планеталық шетке жеткенде, бүкіл флот төмен түсіп, бағытын өзгертуі керек. Сондықтан, AlienInvasion қолданбасына кейбір кодты қосуымыз керек, себебі сол жақта немесе оң жақта өзге планеталықтар бар-жоғын сол жерде тексереміз. Біз мұны _check_fleet_edges() және _change_fleet_direction() әдістерін жазып, содан кейін _update_aliens() өзгерту арқылы орындаймыз. Мен бұл жаңа әдістерді _create_alien() параметрінен кейін қоямын, бірақ бұл әдістерді класста орналастыру маңызды емес.

alien_invasion.py

    def _check_fleet_edges(self):
                """Шетелдіктер шегіне жеткен болса, тиісті жауап беріңіз."""
                 for alien in self.aliens.sprites():
                    if alien.check_edges():
                         self._change_fleet_direction()
                        break
        
            def _change_fleet_direction(self):
                """Бүкіл флотты тастап, флоттың бағытын өзгертіңіз."""
                for alien in self.aliens.sprites():
                     alien.rect.y += self.settings.fleet_drop_speed
                self.settings.fleet_direction *= -1

_check_fleet_edges() ішінде біз флотты айналып өтіп, әрбір бөтен планетада check_edges() шақырамыз. ❶. Егер check_edges() True мәнін қайтарса, біз бөтеннің шетте тұрғанын білеміз және бүкіл флот бағытты өзгерту керек; сондықтан біз _change_fleet_direction() деп атаймыз және ❷ циклінен шығамыз. _change_fleet_direction() ішінде біз барлық өзге планеталықтарды айналдырып, әрқайсысын fleet_drop_speed ❸ параметрін пайдаланып тастаймыз.; содан кейін fleet_direction мәнін оның ағымдағы мәнін −1-ге көбейту арқылы өзгертеміз. Флоттың бағытын өзгертетін сызық for циклінің бөлігі емес. Біз әрбір бөтеннің тік орнын өзгерткіміз келеді, бірақ флоттың бағытын тек бір рет өзгерткіміз келеді.

Міне, _update_aliens() өзгертулері:

alien_invasion.py

    def _update_aliens(self):
                """Флоттың шетте тұрғанын тексеріңіз, содан кейін позицияларды жаңартыңыз."""
                self._check_fleet_edges()
                self.aliens.update()

Әр бөтеннің орнын жаңарту алдында _check_fleet_edges() шақыру арқылы әдісті өзгерттік.

Ойынды қазір іске қосқан кезде, флот экранның жиектері арасында алға-артқа жылжып, шетіне тиген сайын төмен түсіп тұруы керек. Енді біз өзге планеталықтарды атып түсіруді бастай аламыз және кемеге соқтығысқан немесе экранның төменгі жағына жеткен кез-келген өзге планеталықтарды бақылай аламыз.

Өзге планеталықтарды ату

Біз өз кемемізді және өзге планеталықтар флотын жасадық, бірақ оқтар өзге планеталықтарға жеткенде, олар жай өтіп кетеді, өйткені біз соқтығысуды тексермейміз. Ойынды бағдарламалауда соқтығыстар ойын элементтері бір-біріне сәйкес келгенде орын алады. Оқтарды бөгде планеталықтарды атып түсіру үшін екі топ мүшелерінің арасындағы қақтығыстарды іздеу үшін sprite.groupcollide() функциясын қолданамыз.

Маркалар соқтығыстарын анықтау

Оқ бөтен планетаға тиген кезде бірден білгіміз келеді, осылайша бөтен планеталық тиген бойда жоғалып кетуі мүмкін. Ол үшін барлық таңбалардың орнын жаңартқаннан кейін бірден соқтығысуды іздейміз.

sprite.groupcollide() функциясы бір топтағы әрбір элементтің түзету-ларын басқа элементтің түзетусімен салыстырады. топ. Бұл жағдайда ол әрбір оқтың түзу мәнін әр бөтеннің тік белгісімен салыстырады және соқтығысқан оқтар мен өзге планеталықтарды қамтитын сөздікті қайтарады. Сөздіктегі әрбір кілт таңбалауыш болады, ал сәйкес мән соққыға ұшыраған бөтен болады. (Осы сөздікті 14-тарауда бағалау жүйесін енгізген кезде де пайдаланамыз.)

Маркалар мен өзге планеталықтар арасындағы соқтығысуды тексеру үшін _update_bullets() соңына келесі кодты қосыңыз:

alien_invasion.py

    def _update_bullets(self):
                """Оқтардың орнын жаңартып, ескі оқтардан арылыңыз."""
                --snip/код үзіндісі--
        
                # Check for any bullets that have hit aliens.
                #   If so, get rid of the bullet and the alien.
                collisions = pygame.sprite.groupcollide(
                        self.bullets, self.aliens, True, True)

Біз қосылған жаңа код self.bullets ішіндегі барлық таңбалауыштардың және self.aliens ішіндегі барлық өзге планеталықтардың орындарын салыстырады және кез-келген сәйкес келетіндерді анықтайды. Маркер мен бөгде элементтің түзетусәйкестігі кездескен сайын, groupcollide() қайтаратын сөздікке кілт-мән жұбын қосады. Екі True аргументі Pygame-ге соқтығысқан оқтарды және өзге планеталықтарды жоюды айтады. (Экранның жоғарғы жағына шығып, жолындағы әрбір бөтен адамды жоя алатын қуатты оқ жасау үшін бірінші логикалық аргументті False мәніне орнатуға және екінші логикалық аргументті < күйіне қоюға болады. code>True. Соққан өзге планеталықтар жоғалып кетеді, бірақ барлық оқтар экранның жоғарғы жағында жоғалып кеткенше белсенді болып қала береді.)

Қазір Alien Invasion іске қосылғанда, сіз соққыға жығылған өзге планеталықтар жоғалып кетуі керек. 13-5-сурет ішінара түсірілген флотты көрсетеді.

Figure 13-5: We can shoot aliens!

Тестілеу үшін үлкенірек таңбалауыштарды жасау

Ойынды іске қосу арқылы Бөтендік шабуылдың көптеген мүмкіндіктерін тексеруге болады, бірақ кейбір мүмкіндіктерді ойынның қалыпты нұсқасында сынау жалықтырмайды. Мысалы, кодыңыз бос флотқа дұрыс жауап беретінін тексеру үшін экрандағы әрбір бөтен адамды бірнеше рет атып түсіру көп жұмысты қажет етеді.

Белгілі бір мүмкіндіктерді тексеру үшін белгілі бір аймаққа назар аудару үшін белгілі бір ойын параметрлерін өзгертуге болады. Мысалы, түсіру немесе оқ жылдамдығын арттыру және өзіңізге бірден көп оқ беру үшін өзге планеталықтар аз болуы үшін экранды кішірейтуіңізге болады.

Менің Инвазияны сынаудағы таңдаулы өзгерісім - бөтен адамға тигеннен кейін де белсенді болып қалатын шын мәнінде кең оқтарды пайдалану (13-6-суретті қараңыз). bullet_width параметрін 300, тіпті 3000 етіп орнатып көріңіз, флотты қаншалықты жылдам атып түсіретініңізді көріңіз!

13-6-сурет: Өте күшті оқтар ойынның кейбір аспектілерін тексеруді жеңілдетеді.

Осындай өзгертулер ойынды тиімдірек сынауға көмектеседі және ойыншыларға бонустық құқықтар беру идеяларын ұшқындатуы мүмкін. Функцияны тексеруді аяқтаған кезде параметрлерді қалыпты күйге қайтаруды ұмытпаңыз.

Флотты қайта толтыру

Инвазияның басты ерекшеліктерінің бірі - өзге планеталықтар тынымсыз: флот жойылған сайын жаңа флот пайда болуы керек.

Флот жойылғаннан кейін өзге планеталықтардың жаңа флоты пайда болуы үшін алдымен бөтен планеталықтар тобының бос екенін тексереміз. Егер солай болса, біз _create_fleet() қызметіне қоңырау шаламыз. Біз бұл тексеруді _update_bullets() соңында орындаймыз, себебі бұл жерде жеке өзге планеталықтар жойылады.

alien_invasion.py

    def _update_bullets(self):
                --snip/код үзіндісі--
                 if not self.aliens:
                    # Destroy existing bullets and create new fleet.
                     self.bullets.empty()
                    self._create_fleet()

Біз бөтен адамдар тобының бос екенін тексереміз ❶. Бос топ False мәнін бағалайды, сондықтан бұл топтың бос екенін тексерудің қарапайым жолы. Егер солай болса, біз тобынан қалған барлық спрайттарды жоятын empty() әдісін пайдаланып, бар таңбалауыштардан құтыламыз. ❷. Біз сонымен қатар экранды бөгде планеталықтармен толтыратын _create_fleet() деп те атаймыз.

Қазіргі флот жойылған бойда жаңа флот пайда болады.

Оқтарды жылдамдату

Егер сіз ойынның қазіргі күйінде өзге планеталықтарға оқ атуға тырыссаңыз, оқтар ойын ойнау үшін ең жақсы жылдамдықта жүрмейтінін байқауыңыз мүмкін. Олар сәл тым баяу немесе сәл тым жылдам болуы мүмкін. Осы кезде сіз геймплейді қызықты ету үшін параметрлерді өзгерте аласыз. Ойынның біртіндеп жылдамдайтынын есте сақтаңыз, сондықтан ойынды басында тым жылдам жасамаңыз.

Біз таңбалауыштардың жылдамдығын settings.py ішіндегі bullet_speed мәнін реттеу арқылы өзгертеміз. Менің жүйемде мен bullet_speed мәнін 2,5 мәніне реттеймін, сондықтан таңбалар сәл жылдамырақ қозғалады:

settings.py

        # Bullet settings
                self.bullet_speed = 2.5
                self.bullet_width = 3
                --snip/код үзіндісі--

Бұл параметрдің ең жақсы мәні ойын тәжірибесіне байланысты, сондықтан сізге сәйкес келетін мәнді табыңыз. Басқа параметрлерді де реттеуге болады.

_update_bullets() қайта өңдеу

Келіңіз, _update_bullets() рефакторын жасайық, сондықтан ол әртүрлі тапсырмаларды орындамайды. Оқ-бөтен соқтығыстармен күресу үшін кодты бөлек әдіске жылжытамыз:

alien_invasion.py

   def _update_bullets(self):
                --snip/код үзіндісі--
                # Get rid of bullets that have disappeared.
                for bullet in self.bullets.copy():
                    if bullet.rect.bottom <= 0:
                         self.bullets.remove(bullet)
        
                self._check_bullet_alien_collisions()
        
            def _check_bullet_alien_collisions(self):
                """Оқ-бөтен планеталық соқтығыстарға жауап беріңіз."""
                # Remove any bullets and aliens that have collided.
                collisions = pygame.sprite.groupcollide(
                        self.bullets, self.aliens, True, True)
        
                if not self.aliens:
                    # Destroy existing bullets and create new fleet.
                    self.bullets.empty()
                    self._create_fleet()

Оқ оқтары мен өзге планеталықтар арасындағы соқтығыстарды іздеу және бүкіл флот жойылған жағдайда тиісті жауап беру үшін _check_bullet_alien_collisions() атты жаңа әдісті жасадық. Бұл _update_bullets() тым ұзақ өсуден сақтайды және одан әрі дамытуды жеңілдетеді.

Ойынның аяқталуы

Жеңілмейтін ойынды ойнаудың қызығы мен қиындығы қандай? Егер ойыншы флотты тез түсірмесе, біз өзге планеталықтар байланысқа түскен кезде кемені жойып жібереміз. Сонымен бірге біз ойыншы пайдалана алатын кемелер санын шектейміз және бөтен адам экранның төменгі жағына жеткенде кемені жоямыз. Ойыншы барлық кемелерін пайдаланған кезде ойын аяқталады.

өзге планеталықтар мен кемелердің қақтығыстарын анықтау

Біз өзге планеталықтар мен кеме арасындағы соқтығыстарды тексеруден бастаймыз, осылайша бөгде планеталық соққанда тиісті жауап қайтарамыз. AlienInvasion:

ішіндегі әрбір бөтеннің орнын жаңартқаннан кейін біз өзге планеталық кемелердің соқтығысуын бірден тексереміз:

alien_invasion.py

    def _update_aliens(self):
                --snip/код үзіндісі--
                self.aliens.update()
        
                # Look for alien-ship collisions.
                 if pygame.sprite.spritecollideany(self.ship, self.aliens):
                     print("Ship hit!!!")

spritecollideany() функциясы екі аргументті қабылдайды: спрайт және топ. Функция спрайтпен соқтығысқан топтың кез-келген мүшесін іздейді және ол спрайтпен соқтығысқан бір мүшені тапқан бойда топ арқылы айналымды тоқтатады. Мұнда ол бөтен планеталықтар тобын айналып өтіп, ship-мен соқтығысқан бірінші бөтен планетаны қайтарады.

Егер соқтығыс болмаса, spritecollideany() None қайтарады және if блогы орындалмайды❶. Егер ол кемемен соқтығысқан бөтен адамды тапса, ол бөтен адамды қайтарады және if блогы орындалады: ол Кеме соққысы!!! басып шығарады.❷.Бөтен адам кемені соққанда, бізге бірқатар тапсырмаларды орындау керек болады: қалған барлық өзге планеталықтар мен оқтарды жою, кемені қайта орнату және жаңа флот құру. Осының бәрін орындау үшін кодты жазбас бұрын, біз бөтен кемелермен соқтығысуды анықтауға деген көзқарасымыз дұрыс жұмыс істейтінін білгіміз келеді. print() шақыруын жазу - бұл соқтығысуларды дұрыс анықтағанымызға көз жеткізудің қарапайым жолы.

Енді Alien Invasion қолданбасын іске қосқан кезде, бөтен адам кемеге кірген сайын терминалда Кеме соқты!!! хабары пайда болуы керек. Бұл мүмкіндікті сынап жатқанда, fleet_drop_speed мәнін 50 немесе 100 сияқты жоғарырақ мәнге орнатыңыз, сонда өзге планеталықтар кемеңізге жылдам жетеді.

өзге планеталықтар мен кемелердің соқтығысуына жауап беру

Енді біз бөтен адам кемемен соқтығысқанда не болатынын нақты анықтауымыз керек. ship данасын жойып, жаңасын жасаудың орнына, ойын статистикасын қадағалау арқылы кеме қанша рет соғылғанын есептейміз. Бақылау статистикасы ұпай жинау үшін де пайдалы болады.

Ойын статистикасын бақылау үшін GameStats атты жаңа класс жазайық және оны game_stats.py ретінде сақтайық:

game_stats.py

class GameStats:
            """Жат планеталық шабуылға қатысты статистиканы қадағалаңыз."""
        
            def __init__(self, ai_game):
                """Статистиканы инициализациялау."""
                self.settings = ai_game.settings
                 self.reset_stats()
        
            def reset_stats(self):
                """Ойын барысында өзгеруі мүмкін статистиканы инициализациялау."""
                self.ships_left = self.settings.ship_limit

Біз Alien Invasion іске қосылған бүкіл уақыт бойы бір GameStats данасын жасаймыз, бірақ ойыншы жаңа ойынды бастаған сайын кейбір статистиканы қалпына келтіруіміз керек. . Мұны істеу үшін біз статистиканың көпшілігін тікелей __init__() әдісінің орнына reset_stats() әдісінде инициализациялаймыз. Біз бұл әдісті __init__() арқылы шақырамыз, сондықтан GameStats данасы алғаш рет жасалған кезде статистика дұрыс орнатылады . Бірақ біз ойыншы жаңа ойынды бастаған кез-келген уақытта reset_stats() қызметіне қоңырау шала аламыз. Дәл қазір бізде бір ғана статистика бар, ships_left, оның мәні ойын барысында өзгереді.

Ойыншы бастайтын кемелер саны settings.py ішінде ship_limit ретінде сақталуы керек:

settings.py

        # Ship settings
                self.ship_speed = 1.5
                self.ship_limit = 3

Сонымен қатар GameStats данасын жасау үшін alien_invasion.py сайтына бірнеше өзгертулер енгізуіміз керек. Алдымен, файлдың жоғарғы жағындағы import амалдарын жаңартамыз:

alien_invasion.py

import sys
        from time import sleep
        
        import pygame
        
        from settings import Settings
        from game_stats import GameStats
        from ship import Ship
        --snip/код үзіндісі--

Біз Python стандартты кітапханасындағы time модулінен sleep() функциясын импорттаймыз, осылайша кеме соғылып қалған кезде ойынды бір сәтке тоқтата аламыз. Біз сондай-ақ GameStats импорттаймыз.

Біз __init__() ішінде GameStats данасын жасаймыз:

alien_invasion.py

    def __init__(self):
                --snip/код үзіндісі--
                self.screen = pygame.display.set_mode(
                    (self.settings.screen_width, self.settings.screen_height))
                pygame.display.set_caption("Alien Invasion")
        
                # Create an instance to store game statistics.
                self.stats = GameStats(self)
        
                self.ship = Ship(self)
                --snip/код үзіндісі--

Дананы ойын терезесін жасағаннан кейін, бірақ кеме сияқты басқа ойын элементтерін анықтамас бұрын жасаймыз.

Кемені бөгде планеталық соққанда, біз қалған кемелер санынан 1-ді алып тастаймыз, барлық бар өзге планеталықтар мен оқтарды жоямыз, жаңа флот құрамыз және кемені экранның ортасына ауыстырамыз. Сондай-ақ, ойыншы соқтығысты байқап, жаңа флот пайда болғанға дейін қайта топтасу үшін ойынды біраз уақытқа тоқтатамыз.

Осы кодтың көп бөлігін _ship_hit() деп аталатын жаңа әдіске салайық. Бөтен планеталық кемені соққанда, біз бұл әдісті _update_aliens() арқылы шақырамыз:

alien_invasion.py

    def _ship_hit(self):
                """Кемені бөгде планеталық соққанына жауап беріңіз."""
                # Decrement ships_left.
                 self.stats.ships_left -= 1
        
                # Get rid of any remaining bullets and aliens.
                 self.bullets.empty()
                self.aliens.empty()
        
                # Create a new fleet and center the ship.
                 self._create_fleet()
                self.ship.center_ship()
        
                # Pause.
                 sleep(0.5)

Жаңа әдіс _ship_hit() бөгде адам кемені соққанда жауапты үйлестіреді. _ship_hit() ішінде қалған кемелер саны 1-ге азаяды.❶, содан кейін біз bullets және бөтен адамдар топтарын босатамыз.❷.

Әрі қарай, біз жаңа флот құрып, кемені орталықтандырамыз ❸. (Бір сәтте Center_ship() әдісін Ship қызметіне қосамыз.) Содан кейін барлық ойын элементтеріне жаңартулар енгізілгеннен кейін, бірақ кез-келген жаңартудан бұрын үзіліс қосамыз. өзгертулер экранға түсірілді, сондықтан ойыншы өз кемесінің соғылғанын көре алады❹. sleep() шақыруы бағдарламаның орындалуын жарты секундқа кідіртеді, бұл ойыншы бөтен планеталықтың кемені соққанын көру үшін жеткілікті. sleep() функциясы аяқталғанда, кодтың орындалуы жаңа флотты экранға тартатын _update_screen() әдісіне көшеді.

_update_aliens() ішінде бөтен адам кемеге соғылған кезде print() шақыруын _ship_hit() шақыруымен ауыстырамыз:

alien_invasion.py

    def _update_aliens(self):
                --snip/код үзіндісі--
                if pygame.sprite.spritecollideany(self.ship, self.aliens):
                    self._ship_hit()

Міне, ship.py ішіне жататын center_ship() жаңа әдісі:

ship.py

    def center_ship(self):
                """Кемені экранның ортасына қойыңыз."""
                self.rect.midbottom = self.screen_rect.midbottom
                self.x = float(self.rect.x)

Кемені __init__() қолданбасында жасағандай ортаға саламыз. Оны ортаға қойғаннан кейін біз кеменің нақты орнын бақылауға мүмкіндік беретін self.x атрибутын қалпына келтіреміз.

Ойынды іске қосыңыз, бірнеше өзге планеталықтарды атып тастаңыз және бөтен адамның кемеге соқтығысуына мүмкіндік беріңіз. Ойын кідіртіліп, экранның төменгі жағындағы кеме қайтадан ортасына орналастырылған жаңа флот пайда болуы керек.

Экранның төменгі жағына жеткен өзге планеталықтар

Егер бөтен планеталық экранның төменгі жағына жетсе, біз ойынға бөгде планеталық кемені соққан кездегідей жауап береді. Бұл орын алған кезде тексеру үшін alien_invasion.py ішіне жаңа әдіс қосыңыз:

alien_invasion.py

    def _check_aliens_bottom(self):
                """кез-келген шетелдіктердің экранның төменгі жағына жеткенін тексеріңіз."""
                for alien in self.aliens.sprites():
                     if alien.rect.bottom >= self.settings.screen_height:
                        # Treat this the same as if the ship got hit.
                        self._ship_hit()
                        break

_check_aliens_bottom() әдісі бөгде планеталықтар экранның төменгі жағына жеткен-жетпегенін тексереді. Бөтен планета оның rect.bottom мәні экран биіктігінен үлкен немесе оған тең болған кезде, оның төменгі жағына жетеді ❶. Егер бөтен адам түбіне жетсе, біз _ship_hit() деп атаймыз. Егер бір бөтен планеталық астыңғы жағына тиіп кетсе, қалғанын тексерудің қажеті жоқ, сондықтан _ship_hit() шақырғаннан кейін циклдан шығамыз.

Бұл әдісті _update_aliens() арқылы шақырамыз:

alien_invasion.py

    def _update_aliens(self):
                --snip/код үзіндісі--
                # Look for alien-ship collisions.
                if pygame.sprite.spritecollideany(self.ship, self.aliens):
                    self._ship_hit()
        
                # Look for aliens hitting the bottom of the screen.
                self._check_aliens_bottom()

Барлық өзге планеталықтардың позицияларын жаңартқаннан кейін және бөтен кемелермен соқтығысуды іздегеннен кейін _check_aliens_bottom() деп атаймыз. Енді кемені бөтен планеталық соққан сайын немесе бөтен адам экранның төменгі жағына жеткен сайын жаңа флот пайда болады.

Game Over!

Жат планеталық шабуыл қазір өзін толық сезінеді, бірақ ойын ешқашан аяқталмайды. ships_left мәні барған сайын теріс өседі. game_active жалаушасын қосайық, сондықтан ойыншының кемелері таусылғанда ойынды аяқтай аламыз. Бұл жалаушаны AlienInvasion ішіндегі __init__() әдісінің соңына орнатамыз:

alien_invasion.py

    def __init__(self):
                --snip/код үзіндісі--
                # Start Alien Invasion in an active state.
                self.game_active = True

Енді біз ойыншы барлық кемелерін пайдаланған кезде game_active мәнін False күйіне орнататын _ship_hit() кодын қосамыз:

alien_invasion.py

    def _ship_hit(self):
                """Кемені бөтен планеталық соққанына жауап беріңіз."""
                if self.stats.ships_left > 0:
                    # Decrement ships_left.
                    self.stats.ships_left -= 1
                    --snip/код үзіндісі--
                    # Pause.
                    sleep(0.5)
                else:
                    self.game_active = False

_ship_hit() көпшілігі өзгеріссіз. Біз барлық бар кодты if блогына көшірдік, ол ойыншыда кемінде бір кеме қалғанына көз жеткізу үшін сынақтан өтеді. Олай болса, біз жаңа флот жасаймыз, кідіртеміз және әрі қарай жүреміз. Ойыншының кемелері қалмаса, game_active мәнін False күйіне орнатамыз.

Ойын бөліктері қашан іске қосылуы керектігін анықтау

Ойынның әрқашан іске қосылуы керек бөліктерін және ойын белсенді болғанда ғана іске қосылатын бөліктерін анықтауымыз керек:

alien_invasion.py

    def run_game(self):
                """Ойынның негізгі циклін бастау."""
                while True:
                    self._check_events()
        
                    if self.game_active:
                        self.ship.update()
                        self._update_bullets()
                        self._update_aliens()
        
                    self._update_screen()
                    self.clock.tick(60)

Негізгі циклде ойын белсенді емес болса да, біз әрқашан _check_events() шақыруымыз керек. Мысалы, пайдаланушы ойыннан шығу үшін Q түймесін басатынын немесе терезені жабу үшін түймені басатынын білуіміз керек. Сондай-ақ біз экранды жаңартуды жалғастырамыз, осылайша ойыншы жаңа ойынды бастауды таңдаған-таңдамайтынын күту кезінде экранға өзгертулер енгізе аламыз. Қалған функция шақырулары ойын белсенді болғанда ғана орындалуы керек, себебі ойын белсенді емес кезде, бізге ойын элементтерінің орындарын жаңартудың қажеті жоқ.

Енді Alien Invasion ойнаған кезде, барлық кемелеріңіз біткеннен кейін ойын қатып қалуы керек.

Қорытынды

Бұл тарауда сіз өзге планеталықтар флотын құру арқылы ойынға бірдей элементтердің көп санын қосу жолын үйрендіңіз. Сіз элементтер торын жасау үшін кірістірілген циклдарды қолдандыңыз және әр элементтің update() әдісін шақыру арқылы ойын элементтерінің үлкен жинағын жылжыттыңыз. Сіз экрандағы нысандардың бағытын басқаруды және флот экранның шетіне жеткендегі сияқты нақты жағдайларға жауап беруді үйрендіңіз. Сіз оқтар өзге планеталықтарға тиген кезде соқтығысуды анықтап, оларға жауап бердіңіз. Сондай-ақ ойынның статистикасын бақылауды және ойынның қашан аяқталғанын анықтау үшін game_active жалаушасын пайдалануды үйрендіңіз.

Осы жобаның келесі және соңғы тарауында біз Ойнату түймесін қосамыз, осылайша ойыншы бірінші ойынды қашан бастау керектігін және ойын аяқталғанда қайта ойнауды таңдай алады. Ойыншы бүкіл флотты атып түсірген сайын ойынды тездетеміз және ұпай жүйесін қосамыз. Соңғы нәтиже толығымен ойнатылатын ойын болады!

Ұпай жинау

ITUniver

14
Ұпай жинау

Бұл тарауда біз Жат планеталық шабуыл құрылысын аяқтаймыз. Ойынды талап бойынша бастау және ойын аяқталғаннан кейін қайта бастау үшін «Ойнату» түймесін қосамыз. Біз сондай-ақ ойыншы деңгейге көтерілген кезде оны жылдамдату үшін ойынды өзгертеміз және ұпай жүйесін енгіземіз. Тараудың соңында сіз ойыншы алға жылжған сайын қиындығы арта түсетін және толық ұпай жүйесі бар ойындар жазуды бастау үшін жеткілікті білетін боласыз.

Ойнату түймесін қосу

Бұл бөлімде біз ойын басталар алдында пайда болатын және ойын аяқталған кезде қайта пайда болатын Ойнату түймесін қосамыз, осылайша ойыншы қайта ойнай алады.

Дәл қазір, ойын alien_invasion.py іске қосылғаннан кейін бірден басталады. Ойынды белсенді емес күйде бастайық, содан кейін ойыншыны бастау үшін «Ойнату» түймесін басуды сұраймыз. Ол үшін AlienInvasion __init__() әдісін өзгертіңіз:

alien_invasion.py

    def __init__(self):
                """Ойынды инициализациялаңыз және ойын ресурстарын жасаңыз."""
                pygame.init()
                --snip/код үзіндісі--
        
                # Start Alien Invasion in an inactive state.
                self.game_active = False

Енді ойын белсенді емес күйде басталуы керек, біз «Ойнату» түймесін жасамайынша, ойыншы оны бастауға мүмкіндік бермейді.

Түйме классын жасау

Pygame-де түймелерді жасаудың кірістірілген әдісі болмағандықтан, белгісі бар толтырылған тіктөртбұрышты жасау үшін Button классын жазамыз. Бұл кодты ойында кез-келген түймені жасау үшін пайдалануға болады. Міне, Button класының бірінші бөлігі; оны button.py ретінде сақтаңыз:

button.py

import pygame.font
        
        class Button:
            """Ойынға арналған түймелерді құрастыруға арналған сынып."""
        
             def __init__(self, ai_game, msg):
                """Түйме атрибуттарын инициализациялау."""
                self.screen = ai_game.screen
                self.screen_rect = self.screen.get_rect()
        
                # Set the dimensions and properties of the button.
                 self.width, self.height = 200, 50
                self.button_color = (0, 135, 0)
                self.text_color = (255, 255, 255)
                 self.font = pygame.font.SysFont(None, 48)
        
                # Build the button's rect object and center it.
                 self.rect = pygame.Rect(0, 0, self.width, self.height)
                self.rect.center = self.screen_rect.center
        
                # The button message needs to be prepped only once.
                 self._prep_msg(msg)

Біріншіден, Pygame мәтінді экранға шығаруға мүмкіндік беретін pygame.font модулін импорттаймыз. __init__() әдісі түйме мәтінін қамтитын self, ai_game нысаны және msg параметрлерін қабылдайды. ❶. Түйме өлшемдерін ❷ орнатамыз, түйменің тік нысанын қою жасыл түске бояу үшін button_color мәнін орнатамыз. , және мәтінді ақ түспен көрсету үшін text_color параметрін орнатыңыз.

Кейін, ❸ мәтінін көрсету үшін font атрибутын дайындаймыз. None аргументі Pygame-ге әдепкі қаріпті пайдалануды ұсынады, ал 48 мәтін өлшемін көрсетеді. Түймені экранның ортасына қою үшін ❹ түймесі үшін тік жасаймыз және оның орталығын орнатамыз. атрибуты экранға сәйкес келеді.

Pygame кескін ретінде көрсеткіңіз келетін Тіркесті көрсету арқылы мәтінмен жұмыс істейді. Соңында, бұл көрсетуді өңдеу үшін _prep_msg() шақырамыз ❺.

Міне, _prep_msg() коды:

button.py

    def _prep_msg(self, msg):
                """Хабарды бейнеленген кескінге айналдырыңыз""" 
                """және мәтінді түйменің ортасына қойыңыз."""
                 self.msg_image = self.font.render(msg, True, self.text_color,
                        self.button_color)
                 self.msg_image_rect = self.msg_image.get_rect()
                self.msg_image_rect.center = self.rect.center

_prep_msg() әдісіне self параметрі және сурет (msg) ретінде көрсетілетін мәтін қажет. font.render() шақыру msg ішінде сақталған мәтінді кескінге айналдырады, содан кейін біз оны self.msg_image ішінде сақтаймыз.❶.font.render() әдісі антиалиазингті қосу немесе өшіру үшін логикалық мәнді де қабылдайды (антиалиазинг мәтіннің жиектерін тегіс етеді). Қалған аргументтер көрсетілген қаріп түсі мен фон түсі болып табылады. Біз антиалиасингті True мәніне орнатып, мәтіннің фонын түйменің түсімен бірдей етіп орнатамыз. (Егер фон түсін қоспасаңыз, Pygame қаріпті мөлдір фонмен көрсетуге тырысады.)

Суреттен rect жасап, оның center атрибутын түйменің атрибутын сәйкестендіру арқылы мәтіндік кескінді түйменің ортасына келтіреміз. ❷.

Соңында, экранда түймені көрсету үшін шақыруға болатын draw_button() әдісін жасаймыз:

button.py

    def draw_button(self):
                """Бос түймені сызып, хабарламаны сызыңыз."""
                self.screen.fill(self.button_color, self.rect)
                self.screen.blit(self.msg_image, self.msg_image_rect)

Түйменің тікбұрышты бөлігін салу үшін screen.fill() деп атаймыз. Содан кейін мәтіндік кескінді экранға салу үшін screen.blit() шақырамыз, оған кескінді және кескінмен байланысты rect нысанын жібереміз. Бұл Button классын аяқтайды.

Экранға түймені салу

Біз Button классын AlienInvasion ішінде Ойнату түймешігін жасау үшін қолданамыз. Алдымен, import амалдарын жаңартамыз:

alien_invasion.py

--snip/код үзіндісі--
        from game_stats import GameStats
        from button import Button

Бізге бір ғана Ойнату түймесі қажет болғандықтан, біз түймені AlienInvasion қолданбасының __init__() әдісінде жасаймыз. Біз бұл кодты __init__() ең соңына орналастыра аламыз:

alien_invasion.py

    def __init__(self):
                --snip/код үзіндісі--
                self.game_active = False
        
                # Make the Play button.
                self.play_button = Button(self, "Play")

Бұл код Oyna белгісімен Button данасын жасайды, бірақ ол түймені экранға тартпайды. Мұны істеу үшін біз _update_screen() ішіндегі түйменің draw_button() әдісін шақырамыз:

alien_invasion.py

    def _update_screen(self):
                --snip/код үзіндісі--
                self.aliens.draw(self.screen)
        
                # Draw the play button if the game is inactive.
                if not self.game_active:
                    self.play_button.draw_button()
        
                pygame.display.flip()

Ойнату түймешігін экрандағы барлық басқа элементтердің үстінен көрсету үшін, біз оны барлық басқа элементтер сызылғаннан кейін, бірақ жаңа экранға өтпес бұрын саламыз. Біз оны if блогына қосамыз, сондықтан түйме ойын белсенді емес кезде ғана пайда болады.

Енді Alien Invasion қолданбасын іске қосқан кезде экранның ортасында келесі бөлімде көрсетілгендей Ойнату түймешігін көресіз. 14-1-сурет.

14-1-сурет: Ойын белсенді емес кезде ойнату түймесі пайда болады.

Ойынның басталуы

Ойыншы Ойнату түймесін басқанда жаңа ойынды бастау үшін, тінтуірдің оқиғаларын бақылау үшін _check_events() соңына келесі elif блогын қосыңыз. түймесі:

alien_invasion.py

    def _check_events(self):
                """Пернелерді басу және тінтуір оқиғаларына жауап беру."""
                for event in pygame.event.get():
                    if event.type == pygame.QUIT:
                        --snip/код үзіндісі--
                     elif event.type == pygame.MOUSEBUTTONDOWN:
                         mouse_pos = pygame.mouse.get_pos()
                         self._check_play_button(mouse_pos)

Ойыншы экранның кез-келген жерін басқан кезде Pygame MOUSEBUTTONDOWN оқиғасын анықтайды ❶, бірақ біз ойынымызды тек Ойнату түймешігіндегі тінтуірдің басылуына жауап беру үшін шектегіміз келеді. Мұны орындау үшін біз тінтуір курсорының x- және y- координаталары бар кортежді қайтаратын pygame.mouse.get_pos() қолданамыз. тінтуірдің түймесі басылады❷. Бұл мәндерді _check_play_button() жаңа әдісіне жібереміз ❸.

Міне, _check_play_button(), мен оны _check_events() кейін орналастыруды таңдадым.:

alien_invasion.py

    def _check_play_button(self, mouse_pos):
                """Ойыншы "Ойнату" түймесін басқан кезде жаңа ойынды бастаңыз."""
                 if self.play_button.rect.collidepoint(mouse_pos):
                    self.game_active = True

Тінтуірдің басу нүктесінің Ойнату түймесінің түзу арқылы анықталған аймақпен қабаттасатынын тексеру үшін rect әдісін collidepoint() қолданамыз. ❶. Олай болса, game_active параметрін True күйіне орнатамыз және ойын басталады!

Осы кезде сіз толық ойынды бастап, ойнай алуыңыз керек. Ойын аяқталғанда, game_active мәні False болып, Ойнату түймесі қайта пайда болуы керек.

Ойынды қалпына келтіру

Біз жаңа ғана жазған Ойнату түймесінің коды ойнатқыш Play түймесін бірінші рет басқанда жұмыс істейді. Бірақ бірінші ойын аяқталғаннан кейін ол жұмыс істемейді, себебі ойынның аяқталуына себеп болған шарттар қалпына келтірілмеген.

Ойыншы «Ойнату» түймесін басқан сайын ойынды бастапқы күйге қайтару үшін ойын статистикасын қалпына келтіру, ескі өзге планеталықтар мен оқтарды жою, жаңа флот құру және мұнда көрсетілгендей кемені ортаға қою керек:

alien_invasion.py

    def _check_play_button(self, mouse_pos):
                """Ойыншы "Ойнату" түймесін""" 
          """басқан кезде жаңа ойынды бастаңыз."""
                if self.play_button.rect.collidepoint(mouse_pos):
                    # Reset the game statistics.
                     self.stats.reset_stats()
                    self.game_active = True
        
                    # Get rid of any remaining bullets and aliens.
                     self.bullets.empty()
                    self.aliens.empty()
        
                    # Create a new fleet and center the ship.
                     self._create_fleet()
                    self.ship.center_ship()

Біз ойын статистикасын қалпына келтіреміз ❶, бұл ойыншыға үш жаңа кеме береді. Содан кейін біз game_active параметрін True күйіне орнатамыз, осылайша ойын осы функциядағы код іске қосылған кезде бірден басталады. Біз бөтен планеталықтар және bullets топтарын босатамыз ❷, содан кейін біз жаңа флот құрып, кемені орталықтандырамыз❸.

Енді Ойнату түймесін басқан сайын ойын дұрыс қалпына келтіріліп, оны қалағаныңызша ойнауға мүмкіндік береді!

Ойнату түймесін өшіру

Ойнату түймесіне қатысты бір мәселе экрандағы түйме аймағы «Ойнату» түймесі көрінбесе де, басылғандарға жауап бере береді. Ойын басталғаннан кейін «Ойнату» түймесін кездейсоқ бассаңыз, ойын қайта басталады!

Мұны түзету үшін ойынды game_active False болғанда ғана басталатын етіп орнатыңыз:

alien_invasion.py

    def _check_play_button(self, mouse_pos):
                """Ойыншы "Ойнату" түймесін басқан кезде жаңа ойынды бастаңыз."""
                 button_clicked = self.play_button.rect.collidepoint(mouse_pos)
                 if button_clicked and not self.game_active:
                    # Reset the game statistics.
                    self.stats.reset_stats()
                    --snip/код үзіндісі--

button_clicked жалауы True немесе False мәнін сақтайды ❶ және Ойнату түймесін басқанда және ойын қазіргі уақытта ❷ белсенді емес болса ғана ойын қайта басталады. Бұл әрекетті тексеру үшін жаңа ойынды бастаңыз және «Ойнату» түймесін қайта-қайта басыңыз. Барлығы күткендей жұмыс істесе, «Ойнату» түймесін басу геймплейге әсер етпеуі керек.

Тінтуір курсорын жасыру

Ойын белсенді емес кезде тінтуір курсорының көрінуін қалаймыз, бірақ ойын басталған кезде ол жай ғана кедергі жасайды. Мұны түзету үшін ойын белсенді болған кезде оны көрінбейтін етіп жасаймыз. Біз мұны _check_play_button() ішіндегі if блогының соңында жасай аламыз:

alien_invasion.py

    def _check_play_button(self, mouse_pos):
                """Ойыншы "Ойнату" түймесін басқан кезде жаңа ойынды бастаңыз."""
                button_clicked = self.play_button.rect.collidepoint(mouse_pos)
                if button_clicked and not self.game_active:
                    --snip/код үзіндісі--
                    # Hide the mouse cursor.
                    pygame.mouse.set_visible(False)

False параметрін set_visible() параметріне беру Pygame жүйесіне тінтуір ойын терезесінің үстінде тұрғанда курсорды жасыру керектігін айтады.

Ойын аяқталғаннан кейін жүгіргіні қайта көрсетеміз, осылайша ойыншы жаңа ойынды бастау үшін «Ойнату» түймесін қайта басуы мүмкін. Міне, мұны істеу үшін код:

alien_invasion.py

    def _ship_hit(self):
                """Кемені бөтен планеталық соққанына жауап беріңіз."""
                if self.stats.ships_left > 0:
                    --snip/код үзіндісі--
                else:
                    self.game_active = False
                    pygame.mouse.set_visible(True)

Ойын белсенді емес күйге ауысқан кезде курсорды қайтадан көрінетін етіп жасаймыз, бұл _ship_hit() ішінде орын алады. Осы сияқты мәліметтерге назар аудару ойыныңызды кәсібирек етеді және ойыншыға пайдаланушы интерфейсін анықтауға емес, ойнауға назар аударуға мүмкіндік береді.

Деңгейге көтерілу

Қазіргі ойынымызда ойыншы бүкіл бөтен флотты атып түсіргеннен кейін, ойыншы жаңа деңгейге жетеді, бірақ ойынның қиындығы өзгермейді. Ойыншы экранды тазалаған сайын ойын жылдамдығын арттырып, жағдайды сәл жандандырып, ойынды қиындатайық.

Жылдамдық параметрлерін өзгерту

Ойын параметрлерін статикалық және динамикалық болып топтау үшін алдымен Параметрлер классын қайта ұйымдастырамыз. Сондай-ақ, біз жаңа ойынды бастаған кезде ойын кезінде өзгеретін кез-келген параметрлерді қалпына келтіреміз. Мұнда settings.py үшін __init__() әдісі берілген:

settings.py

    def __init__(self):
                """Ойынның статикалық параметрлерін инициализациялау."""
                # Screen settings
                self.screen_width = 1200
                self.screen_height = 800
                self.bg_color = (230, 230, 230)
        
                # Ship settings
                self.ship_limit = 3
        
                # Bullet settings
                self.bullet_width = 3
                self.bullet_height = 15
                self.bullet_color = 60, 60, 60
                self.bullets_allowed = 3
        
                # Alien settings
                self.fleet_drop_speed = 10
        
                # How quickly the game speeds up
                 self.speedup_scale = 1.1
        
                 self.initialize_dynamic_settings()

Біз __init__() әдісінде тұрақты болып қалатын параметрлерді инициализациялауды жалғастырамыз. Ойынның жылдамдығын басқару үшін speedup_scale параметрін ❶ қосамыз: 2 мәні ойын жылдамдығын екі есе арттырады ойыншы жаңа деңгейге жеткен сайын; 1 мәні жылдамдықты тұрақты сақтайды. 1.1 сияқты мән ойынды қиындату үшін жеткілікті жылдамдықты арттыруы керек, бірақ мүмкін емес. Соңында, ❷ ойынында өзгеруі қажет атрибуттардың мәндерін инициализациялау үшін initialize_dynamic_settings() әдісін шақырамыз.

Міне, initialize_dynamic_settings() коды:

settings.py

    def initialize_dynamic_settings(self):
                """Ойын бойы өзгеретін параметрлерді инициализациялау."""
                self.ship_speed = 1.5
                self.bullet_speed = 2.5
                self.alien_speed = 1.0
        
                # fleet_direction of 1 represents right; -1 represents left.
                self.fleet_direction = 1

Бұл әдіс кеменің, оқтың және бөгде жылдамдықтардың бастапқы мәндерін орнатады. Ойыншы ойында алға жылжыған сайын бұл жылдамдықтарды арттырамыз және ойыншы жаңа ойынды бастаған сайын оларды қалпына келтіреміз. Біз бұл әдіске fleet_direction қосамыз, сондықтан өзге планеталықтар әрқашан жаңа ойынның басында тура қозғалады. Бізге fleet_drop_speed мәнін арттырудың қажеті жоқ, себебі бөгде планеталықтар экранда жылдамырақ қозғалғанда, олар да экраннан жылдамырақ түседі.

Ойыншы жаңа деңгейге жеткен сайын кеменің, оқтардың және өзге планеталықтардың жылдамдығын арттыру үшін increase_speed() деп аталатын жаңа әдіс жазамыз:

settings.py

    def increase_speed(self):
                """Жылдамдық параметрлерін арттыру."""
                self.ship_speed *= self.speedup_scale
                self.bullet_speed *= self.speedup_scale
                self.alien_speed *= self.speedup_scale

Осы ойын элементтерінің жылдамдығын арттыру үшін біз әрбір жылдамдық параметрін speedup_scale мәніне көбейтеміз.

Флоттағы соңғы бөтен планеталық атып түсірілген кезде _check_bullet_alien_collisions() ішіндегі increase_speed() функциясын шақыру арқылы ойын қарқынын арттырамыз:

alien_invasion.py

    def _check_bullet_alien_collisions(self):
                --snip/код үзіндісі--
                if not self.aliens:
                    # Destroy existing bullets and create new fleet.
                    self.bullets.empty()
                    self._create_fleet()
                    self.settings.increase_speed()

Бүкіл ойынды жылдамдату үшін ship_speed, alien_speed және bullet_speed жылдамдық параметрлерінің мәндерін өзгерту жеткілікті!

Жылдамдықты қалпына келтіру

Енді ойыншы жаңа ойынды бастаған сайын өзгертілген параметрлерді бастапқы мәндеріне қайтаруымыз керек; әйтпесе, әрбір жаңа ойын алдыңғы ойынның жоғарылатылған жылдамдық параметрлерімен басталады:

alien_invasion.py

    def _check_play_button(self, mouse_pos):
                """Ойыншы "Ойнату" түймесін басқан кезде жаңа ойынды бастаңыз."""
                button_clicked = self.play_button.rect.collidepoint(mouse_pos)
                if button_clicked and not self.game_active:
                    # Reset the game settings.
                    self.settings.initialize_dynamic_settings()
                    --snip/код үзіндісі--

Alien Invasion ойынын ойнау қазір қызық әрі қиын болуы керек. Экранды тазалаған сайын ойын жылдамдығын арттыруы және сәл қиындауы керек. Ойын тым тез қиындаса, settings.speedup_scale мәнін азайтыңыз. Немесе ойын жеткілікті қиын болмаса, мәнді сәл арттырыңыз. Ақылға қонымды уақыт ішінде қиындықты арттыру арқылы тәтті орынды табыңыз. Алғашқы екі экран оңай болуы керек, келесі бірнеше экран қиын, бірақ орындалатын болуы керек, ал кейінгі экрандар мүмкін емес дерлік қиын болуы керек.

Бағалау

Ойынның ұпайын нақты уақытта қадағалап, жоғары ұпайды, деңгейді және қалған кемелер санын көрсету үшін баллдық жүйені енгізейік.

Ұпай - бұл ойын статистикасы, сондықтан GameStats-ға score атрибутын қосамыз:

game_stats.py

class GameStats:
            --snip/код үзіндісі--
            def reset_stats(self):
                """Ойын барысында өзгеруі мүмкін статистиканы инициализациялау."""
                self.ships_left = self.ai_settings.ship_limit
                self.score = 0

Жаңа ойын басталған сайын ұпайды қалпына келтіру үшін __init__() орнына reset_stats() ішінде score инициализациялаймыз.

Ұпайды көрсету

Ұпайды экранда көрсету үшін алдымен Балдар тақтасы жаңа класс жасаймыз. Әзірге бұл класс ағымдағы ұпайды көрсетеді. Ақыр соңында, біз оны жоғары балл, деңгей және қалған кемелер саны туралы хабарлау үшін қолданамыз. Міне, кластың бірінші бөлімі; оны scoreboard.py ретінде сақтаңыз:

scoreboard.py

import pygame.font
        
        class Scoreboard:
            """Ұпай туралы ақпаратты хабарлауға арналған сынып."""
        
             def __init__(self, ai_game):
                """Ұпайларды есепке алу атрибуттарын инициализациялау."""
                self.screen = ai_game.screen
                self.screen_rect = self.screen.get_rect()
                self.settings = ai_game.settings
                self.stats = ai_game.stats
        
                # Font settings for scoring information.
                 self.text_color = (30, 30, 30)
                 self.font = pygame.font.SysFont(None, 48)
        
                # Prepare the initial score image.
                 self.prep_score()

Scoreboard экранға мәтін жазатындықтан, біз pygame.font модулін импорттаудан бастаймыз. Содан кейін біз __init__() параметрін ai_game параметрін береміз, осылайша ол параметрлерге, экран және қол жеткізе алады. >stats нысандары, ол біз қадағалап отырған мәндерді хабарлау үшін қажет болады ❶. Содан кейін біз мәтін түсін орнатамыз ❷ және қаріп нысанын іске қосыңыз ❸.

Көрсетілетін мәтінді кескінге айналдыру үшін prep_score() шақырамыз.❹, біз мұнда анықтаймыз:

scoreboard.py

    def prep_score(self):
                """Ұпайды көрсетілген кескінге айналдырыңыз."""
                 score_str = str(self.stats.score)
                 self.score_image = self.font.render(score_str, True,
                        self.text_color, self.settings.bg_color)
        
                # Display the score at the top right of the screen.
                 self.score_rect = self.score_image.get_rect()
                 self.score_rect.right = self.screen_rect.right - 20
                 self.score_rect.top = 20

prep_score() ішінде stats.score сандық мәнін ❶ жолына айналдырамыз. және одан кейін осы Тіркесті ❷ кескінін жасайтын render() параметріне өткізіңіз. Экранда ұпайды анық көрсету үшін біз экранның фон түсін және мәтін түсін render()-ге береміз.

Ұпайды экранның жоғарғы оң жақ бұрышына орналастырамыз және ұпай ұлғайған сайын және сан ені ұлғайған сайын оны солға қарай кеңейтеміз. Ұпай әрқашан экранның оң жағына сәйкес келетініне көз жеткізу үшін біз score_rect деп аталатын тік жасаймыз және оның оң жақ жиегін экранның оң жақ шетінен 20 пиксельге ❹ орнатыңыз. Содан кейін жоғарғы жиекті экранның жоғарғы жағынан 20 пиксель төмен қарай орналастырамыз ❺.

Одан кейін көрсетілген ұпай кескінін көрсету үшін show_score() әдісін жасаймыз:

scoreboard.py

    def show_score(self):
                """Экранға ұпай салыңыз."""
                self.screen.blit(self.score_image, self.score_rect)

Бұл әдіс экрандағы ұпай кескінін score_rect көрсеткен жерде салады.

Көрсеткіштер тақтасын жасау

Ұпайды көрсету үшін AlienInvasion ішінде Балдар тақтасы данасын жасаймыз. Алдымен import амалдарын жаңартайық:

alien_invasion.py

--snip/код үзіндісі--
        from game_stats import GameStats
        from scoreboard import Scoreboard
        --snip/код үзіндісі--

Келесі, __init__() ішінде Балдар тақтасы данасын жасаймыз:

alien_invasion.py

    def __init__(self):
                --snip/код үзіндісі--
                pygame.display.set_caption("Alien Invasion")
        
                # Create an instance to store game statistics,
                #   and create a scoreboard.
                self.stats = GameStats(self)
                self.sb = Scoreboard(self)
                --snip/код үзіндісі--

Одан кейін экрандағы таблоны _update_screen() ішінде саламыз:

alien_invasion.py

    def _update_screen(self):
                --snip/код үзіндісі--
                self.aliens.draw(self.screen)
        
                # Draw the score information.
                self.sb.show_score()
        
                # Draw the play button if the game is inactive.
                --snip/код үзіндісі--

Ойнату түймесін салар алдында біз show_score() деп атаймыз.

Қазір Alien Invasion іске қосылғанда, экранның жоғарғы оң жағында 0 пайда болуы керек. (Осы кезде біз баллдық жүйені әрі қарай дамытпас бұрын ұпайдың дұрыс жерде пайда болғанына көз жеткізгіміз келеді.) 14-2-сурет ұпайды ойын басталмай тұрып көрсетеді.

Одан әрі біз әрбір бөтен адамға ұпай мәндерін тағайындаймыз!

14-2-сурет: ұпай экранның жоғарғы оң жақ бұрышында көрсетіледі.

өзге планеталықтар атылғанда ұпайды жаңарту

Тікелей нәтижені экранға жазу үшін біз бөтен адамға тиген сайын stats.score мәнін жаңартамыз, содан кейін prep_score()-ге қоңырау шаламыз. ұпай кескінін жаңартыңыз. Алдымен, ойыншы бөтен планетаны атып түсірген сайын қанша ұпай алатынын анықтап алайық:

settings.py

    def initialize_dynamic_settings(self):
                --snip/код үзіндісі--
        
                # Scoring settings
                self.alien_points = 50

Ойын барысында біз әрбір бөтеннің ұпайын арттырамыз. Жаңа ойын басталған сайын бұл нүкте мәні қалпына келтірілетініне көз жеткізу үшін мәнді initialize_dynamic_settings() ішінде орнатамыз.

Келіңіз, бөтен планеталық атып түсірілген сайын _check_bullet_alien_collisions() ішіндегі ұпайды жаңартайық:

alien_invasion.py

    def _check_bullet_alien_collisions(self):
                """Оқ-бөтен планеталық соқтығыстарға жауап беріңіз."""
                # Remove any bullets and aliens that have collided.
                collisions = pygame.sprite.groupcollide(
                        self.bullets, self.aliens, True, True)
        
                if collisions:
                    self.stats.score += self.settings.alien_points
                    self.sb.prep_score()
                --snip/код үзіндісі--

Оқ бөтенге тиген кезде, Pygame соқтығыстар сөздігін қайтарады. Біз сөздіктің бар-жоғын тексереміз, егер бар болса, бөтеннің мәні ұпайға қосылады. Содан кейін жаңартылған ұпай үшін жаңа кескін жасау үшін prep_score() шақырамыз.

Енді Alien Invasion ойынын ойнаған кезде ұпай жинай алуыңыз керек!

Балды қалпына келтіру

Дәл қазір біз ойынның көп бөлігінде жұмыс істейтін бөтен планеталық соққыға жығылғаннан кейін ғана соңғы жаңа ұпай дайындап жатырмыз. Бірақ жаңа ойынды бастағанда, бірінші бөтен планеталық соққыға дейін бұрынғы ойындағы ұпайымызды көреміз.

Жаңа ойынды бастау кезінде ұпайды дайындау арқылы мұны түзете аламыз:

alien_invasion.py

    def _check_play_button(self, mouse_pos):
                --snip/код үзіндісі--
                if button_clicked and not self.game_active:
                    --snip/код үзіндісі--
                    # Reset the game statistics.
                    self.stats.reset_stats()
                    self.sb.prep_score()
                    --snip/код үзіндісі--

Жаңа ойынды бастаған кезде ойын статистикасын қалпына келтіргеннен кейін prep_score() деп атаймыз. Бұл таблоны 0 ұпаймен дайындайды.

Барлық хиттерді жинау

Қазір жазылғандай, біздің код кейбір өзге планеталықтар үшін ұпай жинамауы мүмкін. Мысалы, егер цикл арқылы бір өту кезінде екі оқ бөтен планеталықтармен соқтығысса немесе бірнеше өзге планеталықтарды тигізу үшін қосымша кең оқ жасасақ, ойыншы тек өзге планеталықтардың біреуіне тигені үшін ұпай алады. Мұны түзету үшін оқ пен бөтен планеталықтың соқтығысуын анықтау әдісін нақтылайық.

_check_bullet_alien_collisions() ішінде бөгде адаммен соқтығысқан кез-келген таңбалауыш соқтығыстар сөздігінде кілтке айналады. Әрбір таңбамен байланысты мән ол соқтығысқан өзге планеталықтардың тізімі болып табылады. Біз соқтығыстар сөздігіндегі мәндерді айналып өтіп, әрбір бөтен соққыға ұпай беретінімізге көз жеткіземіз:

alien_invasion.py

    def _check_bullet_alien_collisions(self):
                --snip/код үзіндісі--
                if collisions:
                    for aliens in collisions.values():
                        self.stats.score += self.settings.alien_points * len(aliens)
                    self.sb.prep_score()
            --snip/код үзіндісі--

Егер соқтығыстар сөздігі анықталған болса, біз сөздіктегі барлық мәндерді айналдырамыз. Әрбір мән бір оқ тиген өзге планеталықтардың тізімі екенін есте сақтаңыз. Біз әрбір бөтеннің мәнін әр тізімдегі өзге планеталықтар санына көбейтеміз және бұл соманы ағымдағы ұпайға қосамыз. Мұны тексеру үшін оқтың енін 300 пиксельге өзгертіңіз және қосымша кең оқтарыңызбен соққан әрбір бөтен адам үшін ұпай алатыныңызды тексеріңіз; содан кейін таңбалауыш енін қалыпты мәніне қайтарыңыз.

Нүкте мәндерін арттыру

Ойыншы жаңа деңгейге жеткен сайын ойын қиындай түсетіндіктен, кейінгі деңгейлердегі өзге планеталықтар көбірек ұпай алуы керек. Бұл функцияны іске асыру үшін ойын жылдамдығы артқан кезде ұпай мәнін арттыру үшін код қосамыз:

settings.py

class Settings:
            """Жат планеталық шабуылға арналған барлық параметрлерді сақтауға арналған сынып."""
        
            def __init__(self):
                --snip/код үзіндісі--
                # How quickly the game speeds up
                self.speedup_scale = 1.1
                # How quickly the alien point values increase
                 self.score_scale = 1.5
        
                self.initialize_dynamic_settings()
        
            def initialize_dynamic_settings(self):
                --snip/код үзіндісі--
        
            def increase_speed(self):
                """Жылдамдық параметрлерін және бөгде нүкте мәндерін арттырыңыз."""
                self.ship_speed *= self.speedup_scale
                self.bullet_speed *= self.speedup_scale
                self.alien_speed *= self.speedup_scale
        
                 self.alien_points = int(self.alien_points * self.score_scale)

Біз ұпайлардың өсу жылдамдығын анықтаймыз, оны score_scale ❶ деп атаймыз. Жылдамдықтың шамалы өсуі (1.1) ойынды тезірек қиындатады. Бірақ ұпай санының айтарлықтай айырмашылығын көру үшін біз бөгде нүкте мәнін үлкенірек мөлшерге өзгертуіміз керек (1,5). Енді ойын жылдамдығын арттырған кезде, әр соққының ұпай мәнін де арттырамыз ❷. Нүкте мәнін бүтін бүтін сандарға көбейту үшін int() функциясын қолданамыз.

Әр бөтеннің мәнін көру үшін Параметрлер ішіндегі increase_speed() әдісіне print() шақыруын қосыңыз:

settings.py

    def increase_speed(self):
                --snip/код үзіндісі--
                self.alien_points = int(self.alien_points * self.score_scale)
                print(self.alien_points)

Жаңа нүкте мәні жаңа деңгейге жеткен сайын терминалда пайда болуы керек.

Ұпайды дөңгелектеу

Аркада стиліндегі ату ойындарының көпшілігі ұпайларды 10-ға еселік деп есептейді, сондықтан ұпайларымызбен осы көшті жалғастырайық. Сондай-ақ, үлкен сандарға үтір бөлгіштерін қосу үшін ұпайды пішімдейік. Біз бұл өзгерісті Балдар тақтасы ішінде жасаймыз:

scoreboard.py

    def prep_score(self):
                """Ұпайды көрсетілген кескінге айналдырыңыз."""
                rounded_score = round(self.stats.score, -1)
                score_str = f"{rounded_score:,}"
                self.score_image = self.font.render(score_str, True,
                        self.text_color, self.settings.bg_color)
                --snip/код үзіндісі--

round() функциясы әдетте қалқымалы мәнді екінші аргумент ретінде берілген ондық таңбалардың белгіленген санына дейін дөңгелектейді. Дегенмен, екінші аргумент ретінде теріс санды бергенде, round() мәнді 10, 100, 1000 және т.б. дәлдікке дейін дөңгелектейді. Бұл код Python бағдарламасына stats.score мәнін ең жақын 10-ға дейін дөңгелектеп, оны rounded_score мәніне тағайындауды айтады.

Одан кейін ұпай үшін f жолындағы пішім спецификаторын қолданамыз. Пішім спецификаторы — айнымалы мәннің ұсынылу жолын өзгертетін таңбалардың арнайы тізбегі. Бұл жағдайда :, тізбегі Python-ға берілген сандық мәннің сәйкес жерлеріне үтірлерді қоюды ұсынады. Бұл 1000000 орнына 1,000,000 сияқты жолдарға әкеледі.

Енді ойынды іске қосқан кезде, суретте көрсетілгендей, көптеген ұпай жинасаңыз да, дұрыс пішімделген, дөңгелектелген ұпайды көресіз. 14-3.

14-3-сурет: үтір бөлгіштері бар дөңгелектелген ұпай

Жоғары ұпайлар

Әр ойыншы ойынның жоғары ұпайын жеңгісі келеді, сондықтан ойыншыларға жұмыс істеуге болатын нәрсе беру үшін жоғары ұпайларды қадағалап, есеп берейік. Біз жоғары ұпайларды GameStats ішінде сақтаймыз:

game_stats.py

    def __init__(self, ai_game):
                --snip/код үзіндісі--
                # High score should never be reset.
                self.high_score = 0

Жоғары балл ешқашан қалпына келтірілмеуі керек болғандықтан, біз high_score мәнін reset_stats() емес, __init__() параметрінде инициализациялаймыз.

Келесі, біз жоғары ұпайды көрсету үшін Балдар тақтасын өзгертеміз. __init__() әдісінен бастайық:

scoreboard.py

    def __init__(self, ai_game):
                --snip/код үзіндісі--
                # Prepare the initial score images.
                self.prep_score()
                 self.prep_high_score()

Жоғары балл ұпайдан бөлек көрсетіледі, сондықтан жоғары ұпайлы кескінді дайындау үшін бізге жаңа әдіс, prep_high_score() қажет .

Міне, prep_high_score() әдісі:

scoreboard.py

    def prep_high_score(self):
                """Жоғары ұпайды көрсетілген кескінге айналдырыңыз."""
                 high_score = round(self.stats.high_score, -1)
                high_score_str = f"{high_score:,}"
                 self.high_score_image = self.font.render(high_score_str, True,
                        self.text_color, self.settings.bg_color)
        
                # Center the high score at the top of the screen.
                self.high_score_rect = self.high_score_image.get_rect()
                 self.high_score_rect.centerx = self.screen_rect.centerx
                 self.high_score_rect.top = self.score_rect.top

Жоғары ұпайды 10-ға дейін дөңгелектеп, үтірмен пішімдейміз ❶. Содан кейін біз жоғары ұпайдан кескін жасаймыз ❷, rect жоғары ұпайды көлденеңінен ортаға қойыңыз❸, және оның top атрибутын ұпай кескінінің жоғарғы жағына сәйкестендіру үшін орнатыңыз❹.

show_score() әдісі енді ағымдағы ұпайды экранның жоғарғы оң жағында және жоғарғы ұпайды экранның жоғарғы ортасына салады:

scoreboard.py

    def show_score(self):
                """Экранға ұпай салыңыз."""
                self.screen.blit(self.score_image, self.score_rect)
                self.screen.blit(self.high_score_image, self.high_score_rect)

Жоғары балл бар-жоғын тексеру үшін Көрсеткіштер тақтасында жаңа әдісті, check_high_score() жазамыз:

scoreboard.py

    def check_high_score(self):
                """Жаңа жоғары балл бар-жоғын тексеріңіз."""
                if self.stats.score > self.stats.high_score:
                    self.stats.high_score = self.stats.score
                    self.prep_high_score()

check_high_score() әдісі ағымдағы ұпайды жоғары баллмен салыстырады. Ағымдағы балл үлкенірек болса, high_score мәнін жаңартамыз және жоғары ұпай кескінін жаңарту үшін prep_high_score() шақырамыз.

_check_bullet_alien_collisions() ішіндегі ұпайды жаңартқаннан кейін бөтен адамға тиген сайын check_high_score() деп қоңырау шалуымыз керек:

alien_invasion.py

    def _check_bullet_alien_collisions(self):
                --snip/код үзіндісі--
                if collisions:
                    for aliens in collisions.values():
                        self.stats.score += self.settings.alien_points * len(aliens)
                    self.sb.prep_score()
                    self.sb.check_high_score()
                --snip/код үзіндісі--

Біз colisions сөздігі бар кезде check_high_score() деп атаймыз және оны соққыға ұшыраған барлық өзге планеталықтар үшін баллды жаңартқаннан кейін жасаймыз.

Алғаш рет Invasion Invasion ойынын ойнаған кезде сіздің ұпайыңыз жоғары ұпай болады, сондықтан ол ағымдағы ұпай және жоғары ұпай ретінде көрсетіледі. Бірақ екінші ойынды бастағанда, сіздің жоғары ұпайыңыз ортасында, ал ағымдағы ұпайыңыз оң жақта пайда болуы керек, 14-суретте көрсетілгендей. 4.

14-4-сурет: Жоғары ұпай экранның жоғарғы ортасында көрсетіледі.

Деңгейді көрсету

Ойындағы ойыншының деңгейін көрсету үшін алдымен GameStats ішінде ағымдағы деңгейді білдіретін атрибут қажет. Әрбір жаңа ойынның басында деңгейді қалпына келтіру үшін оны reset_stats() ішінде инициализациялаңыз:

game_stats.py

    def reset_stats(self):
                """Ойын барысында өзгеруі мүмкін статистиканы инициализациялау."""
                self.ships_left = self.settings.ship_limit
                self.score = 0
                self.level = 1

Scoreboard ағымдағы деңгейді көрсету үшін __init__() жаңа әдісті, prep_level() шақырамыз.:

scoreboard.py

    def __init__(self, ai_game):
                --snip/код үзіндісі--
                self.prep_high_score()
                self.prep_level()

Міне, prep_level():

scoreboard.py

    def prep_level(self):
                """Деңгейді көрсетілген кескінге айналдырыңыз."""
                level_str = str(self.stats.level)
                 self.level_image = self.font.render(level_str, True,
                        self.text_color, self.settings.bg_color)
        
                # Position the level below the score.
                self.level_rect = self.level_image.get_rect()
                 self.level_rect.right = self.score_rect.right
                 self.level_rect.top = self.score_rect.bottom + 10

prep_level() әдісі stats.level ішінде сақталған мәннен кескін жасайды. ❶ және суреттің right атрибутын ұпайдың right атрибутына сәйкестендіру үшін орнатады ❷. Содан кейін ол ұпай мен деңгей арасында бос орын қалдыру үшін top атрибутын ұпай кескінінің төменгі жағына 10 пиксельге орнатады. ❸.

Біз сондай-ақ show_score() жаңартуымыз керек.:

scoreboard.py

    def show_score(self):
                """Ұпайларды салыңыз және экранға деңгей қойыңыз."""
                self.screen.blit(self.score_image, self.score_rect)
                self.screen.blit(self.high_score_image, self.high_score_rect)
                self.screen.blit(self.level_image, self.level_rect)

Бұл жаңа сызық деңгейлік кескінді экранға тартады.

Біз stats.level деңгейін арттырамыз және _check_bullet_alien_collisions() ішіндегі деңгей кескінін жаңартамыз:

alien_invasion.py

    def _check_bullet_alien_collisions(self):
                --snip/код үзіндісі--
                if not self.aliens:
                    # Destroy existing bullets and create new fleet.
                    self.bullets.empty()
                    self._create_fleet()
                    self.settings.increase_speed()
        
                    # Increase level.
                    self.stats.level += 1
                    self.sb.prep_level()

Егер флот жойылса, біз stats.level мәнін арттырамыз және жаңа деңгей дұрыс көрсетілетініне көз жеткізу үшін prep_level() шақырамыз.

Жаңа ойынның басында деңгей кескінінің дұрыс жаңартылуын қамтамасыз ету үшін ойыншы Ойнату түймесін басқанда prep_level() деп те шақырамыз:

alien_invasion.py

    def _check_play_button(self, mouse_pos):
                --snip/код үзіндісі--
                if button_clicked and not self.game_active:
                    --snip/код үзіндісі--
                    self.sb.prep_score()
                    self.sb.prep_level()
                    --snip/код үзіндісі--

Біз prep_level() қызметіне prep_score() қоңырау шалғаннан кейін бірден қоңырау шаламыз.

Енді 14-5-сурет-де көрсетілгендей қанша деңгейді аяқтағаныңызды көресіз.

14-5-сурет: Ағымдағы деңгей ағымдағы ұпайдан сәл төмен көрінеді.

Кемелердің санын көрсету

Соңында, ойыншы қалдырған кемелер санын көрсетейік, бірақ бұл жолы графиканы қолданайық. Мұны істеу үшін, көптеген классикалық аркада ойындары сияқты қанша кеме қалғанын көрсету үшін экранның жоғарғы сол жақ бұрышына кемелерді саламыз.

Біріншіден, біз кемелер тобын құру үшін Ship мұрағатын Sprite жасауымыз керек:

ship.py

import pygame
        from pygame.sprite import Sprite
        
         class Ship(Sprite):
            """Кемені басқаруға арналған сынып."""
        
            def __init__(self, ai_game):
                """Кемені инициализациялаңыз және оның бастапқы орнын орнатыңыз."""
                 super().__init__()
                --snip/код үзіндісі--

Мұнда біз Sprite импорттаймыз, Ship-ның Sprite-тен мұраланғанына көз жеткізіңіз. ❶, және __init__() басында super() деп атаңыз.❷.

Кейін, біз көрсете алатын кемелер тобын жасау үшін Көрсеткіштер тақтасын өзгертуіміз керек. Міне, Импорт амалдары Көрсеткіштер тақтасы:

scoreboard.py

import pygame.font
        from pygame.sprite import Group
        
        from ship import Ship

Біз кемелер тобын жасап жатқандықтан, Group және Ship класстарын импорттаймыз.

Here’s __init__():

scoreboard.py

    def __init__(self, ai_game):
                """Ұпайларды есепке алу атрибуттарын инициализациялау."""
                self.ai_game = ai_game
                self.screen = ai_game.screen
                --snip/код үзіндісі--
                self.prep_level()
                self.prep_ships()

Ойын данасын атрибутқа тағайындаймыз, себебі ол кейбір кемелерді жасау үшін қажет болады. Біз prep_ships() шақырудан кейін prep_level() шақырамыз.

Міне, prep_ships():

scoreboard.py

    def prep_ships(self):
                """Қанша кеме қалғанын көрсетіңіз."""
                 self.ships = Group()
                 for ship_number in range(self.stats.ships_left):
                    ship = Ship(self.ai_game)
                     ship.rect.x = 10 + ship_number * ship.rect.width
                     ship.rect.y = 10
                     self.ships.add(ship)

prep_ships() әдісі кеме даналарын ұстау үшін бос топты жасайды, self.ships ❶. Бұл топты толтыру үшін ойыншы қалдырған әрбір кеме үшін цикл бір рет орындалады ❷. Цикл ішінде біз жаңа кеме жасаймыз және әрбір кеменің xкоординаталық мәнін орнатамыз, осылайша кемелер бір-бірінің жанында, кемелер тобының сол жағында 10 пиксельді маржамен пайда болады. ❸. Біз y-координаталық мәнді экранның жоғарғы жағынан 10 пиксель төмен орнаттық, осылайша кемелер экранның жоғарғы сол жақ бұрышында пайда болады. ❹. Содан кейін әрбір жаңа кемені ships тобына қосамыз ❺.

Енді бізге кемелерді экранға салу керек:

scoreboard.py

    def show_score(self):
                """Ұпайларды, деңгейді сызыңыз және экранға жіберіңіз."""
                self.screen.blit(self.score_image, self.score_rect)
                self.screen.blit(self.high_score_image, self.high_score_rect)
                self.screen.blit(self.level_image, self.level_rect)
                self.ships.draw(self.screen)

Кемелерді экранда көрсету үшін топтағы draw() деп атаймыз, ал Pygame әрбір кемені тартады.

Ойыншыға қанша кемеден бастау керек екенін көрсету үшін жаңа ойын басталғанда prep_ships() деп атаймыз. Біз мұны _check_play_button() ішінде AlienInvasion ішінде орындаймыз:

alien_invasion.py

    def _check_play_button(self, mouse_pos):
                --snip/код үзіндісі--
                if button_clicked and not self.game_active:
                    --snip/код үзіндісі--
                    self.sb.prep_level()
                    self.sb.prep_ships()
                    --snip/код үзіндісі--

Сондай-ақ, ойыншы кемені жоғалтқан кезде кеме суреттерінің дисплейін жаңарту үшін, біз prep_ships() функциясын кемеге соққан кезде шақырамыз:

alien_invasion.py

    def _ship_hit(self):
                """Кемені бөтен планеталық соққанына жауап беріңіз."""
                if self.stats.ships_left > 0:
                    # Decrement ships_left, and update scoreboard.
                    self.stats.ships_left -= 1
                    self.sb.prep_ships()
                    --snip/код үзіндісі--

Біз ships_left мәнін азайтқаннан кейін prep_ships() деп атаймыз, сондықтан кеме жойылған сайын қалған кемелердің дұрыс саны көрсетіледі.

14-6суретте қалған кемелер экранның жоғарғы сол жағында көрсетілген толық баллдық жүйе көрсетілген.

Сурет 14-6: Инвазияға арналған толық баллдық жүйе

Қорытынды

Бұл тарауда сіз жаңа ойынды бастау үшін Ойнату түймесін қалай іске қосу керектігін білдіңіз. Сондай-ақ белсенді ойындарда тінтуірдің оқиғаларын анықтауды және курсорды жасыруды үйрендіңіз. Ойындарды ойнау туралы нұсқауларды көрсету үшін Анықтама түймесі сияқты басқа түймелерді жасау үшін үйренгендеріңізді пайдалана аласыз. Сондай-ақ, сіз ойынның өту жылдамдығын өзгертуді, прогрессивті бағалау жүйесін енгізуді және ақпаратты мәтіндік және мәтіндік емес Тіркестермен көрсетуді үйрендіңіз.

Деректер генерациялау

ITUniver

15
Generating Data. Деректер генерациялау

Деректерді визуализациялау — деректер-жиынындағы(datasets) үлгілерді зерттеу және көрсету үшін визуалды графиканы (көрнекі көріністерді) пайдалану. Ол data analysis-пен (деректер талдауымен) тығыз байланысты. Data analysys-та деректер-жиынындағы үлгілер мен байланыстарды зерттеу үшін кодты пайдаланады. Деректер жиыны кодтың бір жолына сәйкес келетін сандардың шағын тізімі болуы мүмкін немесе ақпараттың көптеген түрлерін қамтитын деректердің терабайттары болуы мүмкін.

Тиімді деректер визуализациясын жасау ақпаратты әдемі көрсету ғана емес. Деректер жинағының визуалды көрінісі қарапайым және көрнекі болса, оның мағынасы көрермендерге түсінікті болады. Адамдар деректер жинақтарыңыздан бұрын білмеген үлгілер мен маңыздылықты көреді.

Бақытымызға орай, күрделі деректерді визуализациялау үшін суперкомпьютер қажет емес. Python-ның тиімділігі соншалық, бар болғаны ноутбукпен миллиондаған жеке деректер мәні бар деректер-жиынын жылдам зерттеуге болады. Бұл дерек мәндерінің сандар болуы міндетті емес; осы кітаптың бірінші бөлігінде үйренген Python негіздердің көмегімен сандық емес деректерді де талдай аласыз.

Адамдар Python-ды генетика, климатты зерттеу, саяси және экономикалық талдау және т.б. бойынша деректерді қажет ететін жұмыс үшін пайдаланады. Деректер ғалымдары (Data scientists) Python-да визуализация және талдау құралдарының куатты жиынын жазды, олардың көпшілігі сізге де қол жетімді. Ең танымал құралдардың бірі Matplotlib, математикалық графиктер кітапханасы. Бұл тарауда біз Matplotlib-ті сызықтық графиктер және шашыраңқы графиктер сияқты қарапайым графиктер жасау үшін қолданамыз. Содан кейін біз кездейсоқ серуен (random walk) тұжырымдамасына негізделген қызықты деректер жинағын жасаймыз — кездейсоқ шешімдер сериясынан жасалған визуализация.

Сонымен қатар біз ойын сүйектерін лақтыру нәтижелерін талдау үшін цифрлық құрылғыларда жақсы жұмыс істейтін визуализацияларды жасайтын Plotly деп аталатын пакетті қолданамыз. Plotly - автоматты түрде өлшемін өзгертетін, әртүрлі дисплей құрылғыларына сәйкес келетін визуализацияларды жасайды. Бұл визуализациялар (көрнекіліктер) сонымен қатар пайдаланушылар визуализацияның әртүрлі бөліктерінің үстіне меңзерді апарған кезде деректер-жиынының нақты аспектілерін атап көрсету сияқты бірқатар интерактивті мүмкіндіктерді қамтуы мүмкін. Matplotlib және Plotly қолдануды үйрену сізді ең қызықтыратын деректер түрлерін визуализациялауды бастауға көмектеседі.

Matplotlib орнату

Бастапқы визуализациялар жинағы үшін Matplotlib пайдалану үшін оны pip арқылы орнату керек, дәл 11-тараудағы pytest-ті pip-пен орнату сияқты.

Matplotlib-ті орнату үшін терминалға келесі пәрменді енгізіңіз:

$ python -m pip install --user matplotlib

Бағдарламаларды іске қосу немесе терминал сеансын бастау үшін python пәрменінен басқа пәрменді пайдалансаңыз, мысалы, python3, сіздің пәрменіңіз келесідей болады:

$ python3 -m pip install --user matplotlib

Matplotlib көмегімен жасауға болатын визуализация түрлерін көру үшін https://matplotlib.org мекенжайындағы Matplotlib басты бетіне кіріңіз және Plot types түймесін басыңыз. Галереядағы визуализацияны басқан кезде, Plot жасау үшін пайдаланылатын кодты көресіз.

График салу. Қарапайым сызықтық графикті салу

Matplotlib көмегімен қарапайым сызықтық графикті салайық, содан кейін өте түсінікті деректер визуализациясын көрсететіндей етіп жетілдірейік.График үшін деректер ретінде 1, 4, 9, 16 және 25 шаршы сандар тізбегін қолданамыз.

Қарапайым сызықтық графикті жасау үшін жұмыс істегіңіз келетін сандарды көрсетіңіз және қалғанын Matplotlib-ке беріңіз:

mpl_squares.py


        import matplotlib.pyplot as plt
        
        squares = [1, 4, 9, 16, 25]
        
        ❶ fig, ax = plt.subplots()
        ax.plot(squares)
        
        plt.show()

Алдымен pyplot модулін plt бүркеншік атын пайдаланып импорттаймыз, сондықтан pyplot қайталап терудің қажеті жоқ. (Бұл конвенцияны желідегі мысалдарда жиі көресіз, сондықтан біз оны осында қолданамыз.) pyplot модулі диаграммалар мен графиктерді жасауға көмектесетін бірқатар функцияларды қамтиды.

Біз сызатын деректерді сақтау үшін squares деп аталатын тізім жасаймыз. Содан кейін біз subplots() функциясын ❶ шақыру арқылы басқа жалпы Matplotlib конвенциясын орындаймыз. Бұл функция бір суретте бір немесе бірнеше сызбаларды жасай алады. fig айнымалысы бүкіл фигураны білдіреді, ол құрылған сызбалардың жиыны болып табылады. ax айнымалысы суреттегі жалғыз сызбаны білдіреді; бұл бір сызбаны анықтау және теңшеу кезінде біз жиі қолданатын айнымалы мән.

Одан кейін біз берілген деректерді мағыналы түрде салуға тырысатын plot() әдісін қолданамыз. plt.show() функциясы Matplotlib қарау құралын ашады және 15-1-сурет ішінде көрсетілгендей сызбаны көрсетеді. Қарау құралы сызбаны үлкейтуге және шарлауға мүмкіндік береді және диск белгішесін басу арқылы кез келген сызбалық кескіндерді сақтауға болады.

15-1-сурет: Matplotlib бағдарламасында жасауға болатын ең қарапайым сызбалардың бірі

Белгіні және сызық қалыңдығын өзгерту

15-1-сурет сызбасында сандар көбейіп жатқанын көрсеткенімен, белгілер тым кішкентай және сызық оңай оқу үшін жұқа. Бақытымызға орай, Matplotlib визуализацияның әрбір мүмкіндігін реттеуге мүмкіндік береді.

Осы сызбаны оқу мүмкіндігін жақсарту үшін қолжетімді теңшеулердің бірнешеуін қолданамыз. Тақырып қосу және осьтерді белгілеу арқылы бастайық:

mpl_squares.py

import matplotlib.pyplot as plt
        
        squares = [1, 4, 9, 16, 25]
        
        fig, ax = plt.subplots()
        ❶ ax.plot(squares, linewidth=3)
        
        # Set chart title and label axes.
        ❷ ax.set_title("Square Numbers", fontsize=24)
        ❸ ax.set_xlabel("Value", fontsize=14)
        ax.set_ylabel("Square of Value", fontsize=14)
        
        # Set size of tick labels.
        ❹ ax.tick_params(labelsize=14)
        
        plt.show()

linewidth параметрі plot() ❶ жасайтын сызықтың қалыңдығын басқарады. сызбаны жасағаннан кейін, оны ұсынғанға дейін оны өзгертудің көптеген әдістері бар. set_title() әдісі диаграмма ❷ үшін жалпы тақырыпты орнатады. Код бойына қайта-қайта пайда болатын fontsize параметрлері диаграммадағы әртүрлі элементтердегі мәтін өлшемін басқарады.

set_xlabel() және set_ylabel() әдістері осьтердің әрқайсысына ❸ және tick_params() әдісіне тақырып орнатуға мүмкіндік береді. code> құсбелгі белгілерін ❹ стильдейді. Мұнда tick_params() құсбелгі белгілерінің қаріп өлшемін екі осьте де 14-ке орнатады.

15-2-суретте көріп отырғаныңыздай, алынған диаграмманы оқу әлдеқайда оңай. Белгі түрі үлкенірек, ал сызықтық график қалыңырақ. Алынған графикте не жақсы жұмыс істейтінін көру үшін жиі осы мәндермен тәжірибе жасаған жөн.

15-2-сурет: Диаграмманы оқу қазір әлдеқайда оңай.

сызбаны түзету

Енді біз диаграмманы жақсырақ оқи алатындықтан, деректердің дұрыс салынбағанын көреміз. Графиктің соңында 4,0 квадраты 25 ретінде көрсетілгеніне назар аударыңыз! Оны түзетейік.

Сіз plot() бір сандар тізбегін бергенде, ол бірінші деректер нүктесін x-0 мәніне сәйкес деп есептейді, бірақ біздің бірінші нүкте x-1 мәні. Квадраттарды есептеу үшін пайдаланылатын кіріс және шығыс мәндерін plot() беру арқылы әдепкі әрекетті қайта анықтауға болады:

mpl_squares.py

import matplotlib.pyplot as plt
        
        input_values = [1, 2, 3, 4, 5]
        squares = [1, 4, 9, 16, 25]
        
        fig, ax = plt.subplots()
        ax.plot(input_values, squares, linewidth=3)
        
        # Set chart title and label axes.
        --snip--

Енді plot() шығыс сандары қалай жасалғаны туралы ешқандай болжам жасаудың қажеті жоқ. 15-3-сурет-де көрсетілген нәтиже сызбасы дұрыс.

15-3-сурет: Деректер енді дұрыс сызылған.

Сіз plot() қызметіне қоңырау шалған кезде бірнеше аргументтерді көрсете аласыз және оларды жасағаннан кейін сызбаларыңызды теңшеу үшін бірнеше әдістерді пайдалана аласыз. Біз осы тарауда қызықты деректер жинақтарымен жұмыс істей отырып, теңшеудің осы тәсілдерін зерттеуді жалғастырамыз.

Кірістірілген мәнерлерді пайдалану

Matplotlib-те бірнеше алдын ала анықталған стильдер бар. Бұл стильдер өң түстері, тор сызықтары, сызық ендері, қаріптер, қаріп өлшемдері және т.б. үшін әдепкі параметрлердің әртүрлілігін қамтиды. Олар көп теңшеуді қажет етпей-ақ визуализацияларыңызды тартымды ете алады. Қол жетімді стильдердің толық тізімін көру үшін терминал сеансында келесі жолдарды іске қосыңыз:

>>> import matplotlib.pyplot as plt
        >>> plt.style.available
        ['Solarize_Light2', '_classic_test_patch', '_mpl-gallery',
        --snip--

Осы мәнерлердің кез келгенін пайдалану үшін subplots() шақыру алдында кодтың бір жолын қосыңыз:

mpl_squares.py

import matplotlib.pyplot as plt
        
        input_values = [1, 2, 3, 4, 5]
        squares = [1, 4, 9, 16, 25]
        
        plt.style.use('seaborn')
        fig, ax = plt.subplots()
        --snip--

Бұл код 15-4-сурет-де көрсетілген сызбаны жасайды. Стильдердің кең таңдауы бар; Өзіңізге ұнайтын стильдерді табу үшін осы стильдермен ойнаңыз.

15-4-сурет: Кірістірілген теңіз стилі

Scatter() көмегімен жеке нүктелерді сызу және сәндеу

Кейде белгілі бір сипаттамаларға негізделген жеке нүктелерді салу және стильдеу пайдалы. Мысалы, кішкене мәндерді бір түсте және үлкен мәндерді басқа түсте салуға болады. Сондай-ақ, сәндеу опцияларының бір жиынтығы бар үлкен деректер жинағын сызып, содан кейін оларды әртүрлі опциялармен қайта бөлу арқылы жеке нүктелерді ерекшелеуге болады.

Бір нүктені салу үшін нүктенің жалғыз x- және y-мәндерін scatter() параметріне жіберіңіз:

scatter_squares.py

import matplotlib.pyplot as plt
        
        plt.style.use('seaborn')
        fig, ax = plt.subplots()
        ax.scatter(2, 4)
        
        plt.show()

Шығарылымды қызықтырақ ету үшін мәнерлеп көрейік. Тақырып қосамыз, осьтерді белгілейміз және барлық мәтін оқуға жеткілікті үлкен екеніне көз жеткіземіз:

import matplotlib.pyplot as plt
        
        plt.style.use('seaborn')
        fig, ax = plt.subplots()
        ❶ ax.scatter(2, 4, s=200)
        
        # Set chart title and label axes.
        ax.set_title("Square Numbers", fontsize=24)
        ax.set_xlabel("Value", fontsize=14)
        ax.set_ylabel("Square of Value", fontsize=14)
        
        # Set size of tick labels.
        ax.tick_params(labelsize=14)
        
        plt.show()

Біз scatter() деп атаймыз және графикті ❶ салу үшін қолданылатын нүктелердің өлшемін орнату үшін s аргументін қолданамыз. scatter_squares.py қазір іске қосқан кезде, суретте көрсетілгендей диаграмманың ортасында бір нүктені көресіз. 15-5.

15-5-сурет: Бір нүктенің графигін салу

Scatter() көмегімен нүктелер қатарын салу

Нүктелер тізбегін салу үшін біз scatter() бөлек x- және y- тізімдерін бере аламыз. мына сияқты мәндер:

scatter_squares.py

import matplotlib.pyplot as plt
        
        x_values = [1, 2, 3, 4, 5]
        y_values = [1, 4, 9, 16, 25]
        
        plt.style.use('seaborn')
        fig, ax = plt.subplots()
        ax.scatter(x_values, y_values, s=100)
        
        # Set chart title and label axes.
        --snip--

x_values тізімі квадратқа алынатын сандарды, ал y_values әр санның квадратын қамтиды. Бұл тізімдер scatter() параметріне берілгенде, Matplotlib әрбір нүктені сызу кезінде әрбір тізімнен бір мәнді оқиды. Салынатын нүктелер (1, 1), (2, 4), (3, 9), (4, 16) және (5, 25); 15-6-сурет нәтижені көрсетеді.

15-6-сурет: Бірнеше нүктелері бар шашырау сызбасы

Деректерді автоматты түрде есептеу

Тізімдерді қолмен жазу тиімсіз болуы мүмкін, әсіресе ұпайлар көп болған кезде. Әр мәнді жазудың орнына, біз үшін есептеулер жасау үшін циклды қолданайық.

Міне, 1000 ұпаймен бұл қалай көрінеді:

scatter_squares.py

import matplotlib.pyplot as plt
        
        ❶ x_values = range(1, 1001)
        y_values = [x**2 for x in x_values]
        
        plt.style.use('seaborn')
        fig, ax = plt.subplots()
        ❷ ax.scatter(x_values, y_values, s=10)
        
        # Set chart title and label axes.
        --snip--
        
        # Set the range for each axis.
        ❸ ax.axis([0, 1100, 0, 1_100_000])
        
        plt.show()

1 мен 1000 ❶ аралығындағы сандарды қамтитын x-мәндер ауқымынан бастаймыз. Әрі қарай, тізімді түсіну x-мәндері (x_x_values ішіндегі x үшін) арқылы цикл арқылы yмәндерін жасайды (<), әр санның квадратына (< code>x**2) және нәтижелерді y_values мәніне тағайындау. Содан кейін біз кіріс және шығыс тізімдерін scatter() ❷ параметріне береміз. Бұл үлкен деректер жинағы болғандықтан, біз кішірек нүкте өлшемін пайдаланамыз.

сызбаны көрсетпес бұрын, әрбір осьтің ❸ ауқымын көрсету үшін axis() әдісін қолданамыз. axis() әдісі төрт мәнді қажет етеді: x-осі және y-осі үшін ең төменгі және ең үлкен мәндер. Мұнда біз xосін 0-ден 1100-ге дейін және yосін 0-ден 1100000-ға дейін орындаймыз. 15-7-сурет нәтижені көрсетеді.

15-7-сурет: Python 5 нүктені салғандай оңай 1000 нүктені сала алады.

Текбелгілерді теңшеу

Остегі сандар жеткілікті үлкен болған кезде, Matplotlib әдепкі бойынша белгі белгілерінің ғылыми белгісін қояды. Бұл әдетте жақсы нәрсе, себебі кәдімгі жазудағы үлкенірек сандар визуализацияда қажетсіз көп орынды алады.

Диаграмманың әрбір дерлік элементі теңшеуге болады, сондықтан Matplotlib-ке егер қаласаңыз, кәдімгі белгілерді пайдалануды жалғастыра беруге болады:

--snip--
        # Set the range for each axis.
        ax.axis([0, 1100, 0, 1_100_000])
        ax.ticklabel_format(style='plain')
        
        plt.show()

ticklabel_format() әдісі кез келген график үшін әдепкі белгі мәнерін қайта анықтауға мүмкіндік береді.

Теңшелетін түстерді анықтау

Нүктелердің түсін өзгерту үшін, color аргументін тырнақша ішінде қолданылатын түс атауымен scatter() параметріне беріңіз, мұнда көрсетілгендей:

ax.scatter(x_values, y_values, color='red', s=10)

Сондай-ақ RGB түс үлгісін пайдаланып реттелетін түстерді анықтауға болады. Түсті анықтау үшін, color аргументіне 0 мен 1 арасындағы мәндерді пайдаланып, үш қалқымалы мәні бар кортежді (қызыл, жасыл және көк үшін әрқайсысы осы ретпен) жіберіңіз. Мысалы, келесі сызық ашық-жасыл нүктелері бар сызбаны жасайды:

ax.scatter(x_values, y_values, color=(0, 0.8, 0), s=10)

0-ге жақын мәндер қою түстерді, ал 1-ге жақын мәндер ашық түстерді береді.

Түс картасын пайдалану

түс картасы - градиенттегі түстердің тізбегі, ол бастапқы түстен соңғы түске дейін жылжиды. Көрнекіліктерде түс карталары деректердегі үлгілерді ерекшелеу үшін пайдаланылады. Мысалы, төмен мәндерді ашық түске, ал жоғары мәндерді қоюырақ түске айналдыра аласыз. Түс картасын пайдалану визуализациядағы барлық нүктелердің жақсы жобаланған түс шкаласы бойынша біркелкі және дәл өзгеруін қамтамасыз етеді.

pyplot модулі кірістірілген түс карталарының жинағын қамтиды. Осы түс карталарының бірін пайдалану үшін pyplot деректер-жиынындағы әрбір нүктеге қалай түс тағайындау керектігін көрсету керек. Міне, әр нүктеге оның y-мәніне негізделген түс тағайындау жолы:

scatter_squares.py

--snip--
        plt.style.use('seaborn')
        fig, ax = plt.subplots()
        ax.scatter(x_values, y_values, c=y_values, cmap=plt.cm.Blues, s=10)
        
        # Set chart title and label axes.
        --snip--

c аргументі color-ға ұқсас, бірақ ол мәндер тізбегін түсті салыстырумен байланыстыру үшін пайдаланылады. y-мәндер тізімін c-ге береміз, содан кейін pyplot-ға cmap көмегімен қандай түс картасын пайдалану керектігін айтамыз. аргумент. Бұл код нүктелерді төменгі y-мәндері ашық көк және жоғары y мәндері бар нүктелерді қою көк түске бояйды. 15-8-сурет нәтиже сызбасын көрсетеді.

15-8-сурет: Көгілдір түс картасын пайдаланатын сызба

Сызбаларды автоматты түрде сақтау

сызбаны Matplotlib қарау құралында көрсетудің орнына файлға сақтағыңыз келсе, plt.show орнына plt.savefig() пайдалана аласыз. ():

plt.savefig('squares_plot.png', bbox_inches='tight')

Бірінші аргумент - сызбалық кескінге арналған файл атауы, ол scatter_squares.py сияқты бір каталогта сақталады. Екінші аргумент сызбадан қосымша бос орынды қысқартады. сызбаның айналасында қосымша бос орын қажет болса, бұл аргументті өткізіп жіберуге болады. Сондай-ақ, savefig() нысанын Path нысанымен шақыруға және шығыс файлын жүйеңіздің кез келген жеріне жазуыңызға болады.

Кездейсоқ серуендер

Бұл бөлімде біз кездейсоқ серуендеуге арналған деректерді жасау үшін Python-ды қолданамыз, содан кейін сол деректердің көрнекі түрде тартымды көрінісін жасау үшін Matplotlib-ті қолданамыз. кездейсоқ серуендеу - бұл әрқайсысы толығымен кездейсоқтыққа қалдырылатын қарапайым шешімдер сериясымен анықталатын жол. Шатастырылған құмырсқа кез келген қадамды кездейсоқ бағытта жасаса, онда кездейсоқ жүруді елестете аласыз.

Кездейсоқ серуендердің табиғатта, физикада, биологияда, химияда және экономикада практикалық қолданылуы бар. Мысалы, су тамшысының үстінде қалқып жүрген тозаң дәні судың бетімен қозғалады, өйткені оны су молекулалары үнемі итеріп отырады. Су тамшысындағы молекулалық қозғалыс кездейсоқ, сондықтан тозаң дәнінің бетінде ізі болатын жол кездейсоқ жүру болып табылады. Біз келесі жазатын код көптеген нақты жағдайларды модельдейді.

RandomWalk сыныбын жасау

Кездейсоқ серуен жасау үшін біз RandomWalk сыныбын жасаймыз, ол серуеннің қай бағытта жүруі керектігі туралы кездейсоқ шешім қабылдайды. Сыныпқа үш атрибут қажет: серуендегі нүктелердің санын бақылау үшін бір айнымалы және серуендегі әрбір нүктенің x- және y- координаттарын сақтау үшін екі тізім. .

Бізге RandomWalk сыныбы үшін тек екі әдіс қажет: __init__() әдісі және fill_walk(), ол серуендегі нүктелер. __init__() әдісінен бастайық:

random_walk.py

❶ from random import choice
        
        class RandomWalk:
            """A class to generate random walks."""
        
        ❷     def __init__(self, num_points=5000):
                """Initialize attributes of a walk."""
                self.num_points = num_points
        
                # All walks start at (0, 0).
        ❸         self.x_values = [0]
                self.y_values = [0]

Кездейсоқ шешімдер қабылдау үшін біз ықтимал қозғалыстарды тізімге сақтаймыз және қандай жылжытуды жасау керектігін шешу үшін choice() функциясын (random модулінен) пайдаланамыз. қадам жасалған сайын ❶. Біз серуендегі нүктелердің әдепкі санын 5000 етіп орнаттық, ол кейбір қызықты үлгілерді жасау үшін жеткілікті үлкен, бірақ серуендерді жылдам жасау үшін жеткілікті аз ❷. Содан кейін x- және y- мәндерін ұстау үшін екі тізім жасаймыз және әрбір жүрісті (0, 0) ❸ нүктесінен бастаймыз.

Бағыттарды таңдау

Жүрістегі нүктелердің толық тізбегін анықтау үшін fill_walk() әдісін қолданамыз. Бұл әдісті random_walk.py ішіне қосыңыз:

random_walk.py

    def fill_walk(self):
                """Calculate all the points in the walk."""
        
                # Keep taking steps until the walk reaches the desired length.
        ❶         while len(self.x_values) < self.num_points:
        
                    # Decide which direction to go, and how far to go.
        ❷             x_direction = choice([1, -1])
                    x_distance = choice([0, 1, 2, 3, 4])
        ❸             x_step = x_direction * x_distance
        
                    y_direction = choice([1, -1])
                    y_distance = choice([0, 1, 2, 3, 4])
        ❹             y_step = y_direction * y_distance
        
                    # Reject moves that go nowhere.
        ❺             if x_step == 0 and y_step == 0:
                        continue
        
                    # Calculate the new position.
        ❻             x = self.x_values[-1] + x_step
                    y = self.y_values[-1] + y_step
        
                    self.x_values.append(x)
                    self.y_values.append(y)

Алдымен жүгіру нүктелердің дұрыс санымен толтырылғанша жұмыс істейтін циклды орнатамыз ❶. fill_walk() негізгі бөлігі Python-ға төрт кездейсоқ шешімді қалай модельдеу керектігін айтады: серуен оңға немесе солға кете ме? Бұл бағытта ол қаншалықты алыс болады? Ол көтеріле ме, әлде төмендей ме? Бұл бағытта ол қаншалықты жүреді?

Біз choice([1, -1]) мәнін x_direction мәнін таңдау үшін қолданамыз, ол оңға жылжу үшін 1 мәнін немесе келесіге жылжыту үшін −1 мәнін қайтарады. сол ❷. Одан кейін choice([0, 1, 2, 3, 4]) осы бағытта жылжу үшін қашықтықты кездейсоқ таңдайды. Бұл мәнді x_distance мәніне тағайындаймыз. 0 мәнін қосу тек бір ось бойымен қозғалатын қадамдар мүмкіндігін береді.

Біз x- және y-бағыттары бойынша әрбір қадамның ұзындығын қозғалыс бағытын таңдалған ❸ ❹ қашықтыққа көбейту арқылы анықтаймыз. x_step үшін оң нәтиже оңға жылжу дегенді білдіреді, теріс нәтиже солға жылжу дегенді білдіреді және 0 тігінен жылжу дегенді білдіреді. y_step үшін оң нәтиже - жоғары, теріс - төмен, ал 0 - көлденең жылжу дегенді білдіреді. x_step және y_step екеуінің де мәндері 0 болса, серуен ешқайда кетпейді; бұл орын алғанда, циклды ❺ жалғастырамыз.

Жаяу жүру үшін келесі x мәнін алу үшін x_step ішіндегі мәнді x_values ішінде сақталған соңғы мәнге қосамыз ❻ және yмәндері үшін де солай жасаңыз. Жаңа нүктенің координаталары болған кезде, біз оларды x_values және y_values-ға қосамыз.

Кездейсоқ серуендеу графигі

Міне, серуендегі барлық нүктелерді сызуға арналған код:

rw_visual.py

import matplotlib.pyplot as plt
        
        from random_walk import RandomWalk
        
        # Make a random walk.
        ❶ rw = RandomWalk()
        rw.fill_walk()
        
        # Plot the points in the walk.
        plt.style.use('classic')
        fig, ax = plt.subplots()
        ❷ ax.scatter(rw.x_values, rw.y_values, s=15)
        ❸ ax.set_aspect('equal')
        plt.show()

Біз pyplot және RandomWalk импорттаудан бастаймыз. Содан кейін біз кездейсоқ жүріс жасаймыз және оны rw ❶-ге тағайындаймыз, fill_walk() шақыру керек. Жаяу жүруді визуализациялау үшін біз серуеннің x- және y-мәндерін scatter() мәніне береміз және сәйкес нүкте өлшемін ❷ таңдаймыз. Әдепкі бойынша, Matplotlib әрбір осьті дербес масштабтайды. Бірақ бұл тәсіл көптеген серуендерді көлденең немесе тігінен созады. Мұнда екі осьте де құсбелгі белгілерінің ❸ арасында бірдей аралық болуы керек екенін көрсету үшін set_aspect() әдісін қолданамыз.

15-9-сурет 5000 ұпайдан тұратын нәтиже сызбасын көрсетеді. Бұл бөлімдегі суреттер Matplotlib қарау құралын көрсетпейді, бірақ оны rw_visual.py іске қосқан кезде көре бересіз.

15-9-сурет: 5000 ұпаймен кездейсоқ жүру

Бірнеше рет кездейсоқ жүруді жасау

Әр кездейсоқ жүру әртүрлі және жасауға болатын әртүрлі үлгілерді зерттеу қызықты. Бағдарламаны бірнеше рет іске қоспай-ақ, бірнеше серуендер жасау үшін алдыңғы кодты пайдаланудың бір жолы оны келесідей while цикліне орау болып табылады:

rw_visual.py

import matplotlib.pyplot as plt
        
        from random_walk import RandomWalk
        
        # Keep making new walks, as long as the program is active.
        while True:
            # Make a random walk.
            --snip--
            plt.show()
        
            keep_running = input("Make another walk? (y/n): ")
            if keep_running == 'n':
                break

Бұл код кездейсоқ жүруді жасайды, оны Matplotlib қарау құралында көрсетеді және қарау құралы ашық болған кезде кідіртеді. Көру құралын жапқанда, сізден басқа серуен жасағыңыз келе ме деп сұралады. Бірнеше серуен жасасаңыз, бастапқы нүктеге жақын тұратын кейбіреулерді, кейбіреулері негізінен бір бағытта кетіп бара жатқандарды, кейбіреулерінің үлкенірек нүктелер топтарын біріктіретін жіңішке бөліктерін және серуендеудің көптеген басқа түрлерін көруіңіз керек. Бағдарламаны аяқтағыңыз келгенде, N түймесін басыңыз.

Серуенді сәндеу

Бұл бөлімде біз әр серуеннің маңызды сипаттамаларын атап көрсету және алаңдататын элементтерді азайту үшін сызбаларымызды реттейміз. Ол үшін біз серуеннің қай жерде басталғанын, қай жерде аяқталғанын және жүріп өткен жолды атап өткіміз келетін сипаттарды анықтаймыз. Әрі қарай, біз құсбелгілер мен белгілер сияқты ерекшеленетін сипаттамаларды анықтаймыз. Нәтиже әрбір кездейсоқ жүру кезінде алынған жолды анық көрсететін қарапайым көрнекі бейне болуы керек.

Нүктелерді бояу

Біз серуендегі нүктелердің ретін көрсету үшін түс картасын қолданамыз және нүктелердің түсі айқынырақ болуы үшін әрбір нүктеден қара контурды алып тастаймыз. Нүктелерді серуендегі орнына сәйкес бояу үшін біз c аргументіне әрбір нүктенің орнын қамтитын тізімді береміз. Нүктелер ретімен салынғандықтан, бұл тізім тек 0-ден 4999-ға дейінгі сандарды қамтиды:

rw_visual.py

--snip--
        while True:
            # Make a random walk.
            rw = RandomWalk()
            rw.fill_walk()
        
            # Plot the points in the walk.
            plt.style.use('classic')
            fig, ax = plt.subplots()
        ❶     point_numbers = range(rw.num_points)
            ax.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.Blues,
                edgecolors='none', s=15)
            ax.set_aspect('equal')
            plt.show()
            --snip--

Біз серуендегі нүктелер санына тең сандар тізімін жасау үшін range() қолданамыз ❶. Біз бұл тізімді серуендегі әрбір нүктенің түсін орнату үшін қолданатын point_numbers тізіміне тағайындаймыз. point_numbers мәнін c аргументіне жібереміз, Blues түс картасын қолданамыз, содан кейін edgecolors='none' жібереміз әр нүктенің айналасындағы қара контурдан құтылыңыз. Нәтиже - ашықтан қою көкке дейін өзгеретін сызба, серуеннің бастапқы нүктесінен аяқталу нүктесіне дейін қалай қозғалатынын нақты көрсетеді. Бұл 15-10-суретте көрсетілген.

15-10-сурет: Көгілдір түс картасымен боялған кездейсоқ серуен

Бастау және аяқталу нүктелерін салу

Серуен кезінде олардың орнын көрсету үшін нүктелерді бояумен қатар, әр серуеннің қай жерде басталып, қай жерде аяқталатынын көру пайдалы болар еді. Ол үшін біз негізгі қатар сызылғаннан кейін бірінші және соңғы нүктелерді жеке-жеке сала аламыз. Біз шеткі нүктелерді үлкейтіп, ерекше болу үшін оларды басқаша бояймыз:

rw_visual.py

--snip--
        while True:
            --snip--
            ax.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.Blues,
                edgecolors='none', s=15)
            ax.set_aspect('equal')
        
            # Emphasize the first and last points.
            ax.scatter(0, 0, c='green', edgecolors='none', s=100)
            ax.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolors='none',
                s=100)
        
            plt.show()
            --snip--

Бастау нүктесін көрсету үшін біз (0, 0) нүктені жасыл түспен және қалған нүктелерге қарағанда үлкенірек өлшемде (s=100) саламыз. Соңғы нүктені белгілеу үшін біз соңғы x- және yмәндерін де 100 өлшемімен қызыл түспен саламыз. Бұл кодты plt.show() қызметіне қоңырау шалар алдында енгізгеніңізге көз жеткізіңіз, сонда бастапқы және аяқталу нүктелері барлық басқа нүктелердің үстіне сызылады.

Осы кодты іске қосқан кезде әр серуеннің қай жерде басталып, қай жерде аяқталатынын дәл анықтауыңыз керек. Егер бұл соңғы нүктелер жеткілікті түрде ерекшеленбесе, олар пайда болғанша олардың түсі мен өлшемін реттеңіз.

Біліктерді тазалау

Осы сызбада осьтерді алып тастап көрейік, сонда олар әр жүру жолынан алаңдамас үшін. Міне осьтерді жасыру жолы:

rw_visual.py

--snip--
        while True:
            --snip--
            ax.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolors='none',
                s=100)
        
            # Remove the axes.
            ax.get_xaxis().set_visible(False)
            ax.get_yaxis().set_visible(False)
        
            plt.show()
            --snip--

Остерді өзгерту үшін біз әрбір осьті алу үшін ax.get_xaxis() және ax.get_yaxis() әдістерін қолданамыз, содан кейін set_visible тізбегі () әдісі әрбір осьті көрінбейтін етеді. Көрнекіліктермен жұмыс істеуді жалғастыра отырып, визуализацияның әртүрлі аспектілерін теңшеуге арналған әдістердің осы тізбегін жиі көресіз.

Қазір rw_visual.py іске қосыңыз; осьтері жоқ сызбалар сериясын көру керек.

Сызба нүктелерін қосу

Жұмыс істеуге көбірек деректер беру үшін ұпай санын көбейтейік. Ол үшін біз RandomWalk данасын жасағанда num_points мәнін арттырамыз және сызбаны салу кезінде әрбір нүктенің өлшемін реттейміз:

rw_visual.py

--snip--
        while True:
            # Make a random walk.
            rw = RandomWalk(50_000)
            rw.fill_walk()
        
            # Plot the points in the walk.
            plt.style.use('classic')
            fig, ax = plt.subplots()
            point_numbers = range(rw.num_points)
            ax.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.Blues,
                edgecolors='none', s=1)
            --snip--

Бұл мысал 50 000 нүктеден тұратын кездейсоқ жүруді жасайды және әр нүктені s=1 өлшемінде сызады. Нәтижедегі серуен 15-11-сурет-де көрсетілгендей, бұлтты және бұлт тәрізді. Біз қарапайым шашыраңқы сызбадан өнер туындысын жасадық!

Жүйе айтарлықтай баяулай бастағанға дейін немесе сызба өзінің көрнекі тартымдылығын жоғалтпай тұрып, серуендеу кезінде ұпайлар санын қаншалықты арттыруға болатынын көру үшін осы кодпен тәжірибе жасап көріңіз.

15-11-сурет: 50 000 ұпаймен серуендеу

Экранды толтыру үшін өлшемді өзгерту

Көрнекілігі экранға жақсы сәйкес келсе, деректердегі үлгілерді жеткізуде әлдеқайда тиімді. Сызба терезесін экранға жақсырақ сәйкестендіру үшін Matplotlib шығысының өлшемін реттеуге болады. Бұл subplots() шақыруында орындалады:

fig, ax = plt.subplots(figsize=(15, 9))

сызбаны құру кезінде фигураның өлшемін орнататын subplots() figsize аргументін беруге болады. figsize параметрі Matplotlib-ке сызу терезесінің өлшемдерін дюйммен көрсететін кортежді алады.

Matplotlib экран ажыратымдылығы бір дюймге 100 пиксель деп есептейді; егер бұл код нақты сызба өлшемін бермесе, қажетінше сандарды реттеңіз. Немесе жүйенің ажыратымдылығын білсеңіз, subplots() ажыратымдылығын dpi параметрін пайдаланып жібере аласыз:

fig, ax = plt.subplots(figsize=(10, 6), dpi=128)

Бұл экрандағы бос орынды барынша тиімді пайдалануға көмектеседі.

Plotly. Plotly-мен ойын сүйектерін лақтыру

Бұл бөлімде интерактивті визуализациялар жасау үшін Plotly қолданбасын қолданамыз. Plotly әсіресе браузерде көрсетілетін визуализацияларды жасағанда пайдалы, себебі визуализациялар қараушының экранына сәйкес келетіндей автоматты түрде масштабталады. Бұл визуализациялар да интерактивті; пайдаланушы экрандағы белгілі бір элементтердің үстіне меңзерді апарғанда, сол элементтер туралы ақпарат бөлектеледі. Біз бастапқы визуализациямызды кодтың бірнеше жолында, мүмкіндігінше аз кодпен сызбалар жасауға бағытталған Plotly ішкі жиыны Plotly Express арқылы құрастырамыз. Сюжеміздің дұрыс екенін білгеннен кейін, Matplotlib қолданбасымен жасағандай нәтижені теңшейміз.

Бұл жобада біз сүйектерді лақтыру нәтижелерін талдаймыз. Бір қалыпты, алты жақты матрицаны лақтырған кезде, 1-ден 6-ға дейінгі кез келген санды айналдыру мүмкіндігі бірдей болады. Дегенмен, екі сүйекті пайдаланған кезде, басқаларға қарағанда белгілі бір сандарды лақтыру ықтималдығы жоғары болады. Біз сүйектерді көрсететін деректер жинағын жасау арқылы қай сандар орын алуы ықтимал екенін анықтауға тырысамыз. Содан кейін қай нәтижелер басқаларға қарағанда ықтималырақ екенін анықтау үшін көптеген орамдардың нәтижелерін сызып аламыз.

Бұл жұмыс сүйектерді қамтитын ойындарды модельдеуге көмектеседі, бірақ негізгі идеялар карта ойындары сияқты кез келген мүмкіндікті қамтитын ойындарға да қолданылады. Бұл кездейсоқтық маңызды факторды ойнайтын көптеген нақты жағдайларға да қатысты.

Plotly орнату

Plotly бағдарламасын Matplotlib үшін жасағаныңыздай pip көмегімен орнатыңыз:

$ python -m pip install --user plotly
        $ python -m pip install --user pandas

Plotly Express деректермен тиімді жұмыс істеуге арналған кітапхана болып табылатын pandas-ға тәуелді, сондықтан оны да орнатуымыз керек. Matplotlib бағдарламасын орнату кезінде python3 немесе басқа бірдеңені пайдалансаңыз, осы жерде бірдей пәрменді пайдаланғаныңызға көз жеткізіңіз.

Plotly көмегімен қандай көрнекіліктер мүмкін екенін көру үшін https://plotly.com/ сайтындағы диаграмма түрлерінің галереясына кіріңіз. питон. Әрбір мысалда бастапқы код бар, сондықтан Plotly визуализацияларды қалай жасайтынын көре аласыз.

Мөлшер класын жасау

Бір матрицаны имитациялау үшін келесі Die сыныбын жасаймыз:

die.py

from random import randint
        
        class Die:
            """A class representing a single die."""
        
        ❶     def __init__(self, num_sides=6):
                """Assume a six-sided die."""
                self.num_sides = num_sides
        
            def roll(self):
                """"Return a random value between 1 and number of sides."""
        ❷         return randint(1, self.num_sides)

__init__() әдісі бір қосымша аргумент ❶ қабылдайды. Die сыныбымен, біздің дананың данасы жасалғанда, ешқандай аргумент қосылмаса, жақтардың саны алты болады. Егер аргумент қосылса, бұл мән матрицадағы жақтардың санын орнатады. (Көршектер жақтарының санына байланысты аталады: алты қырлы матриц - D6, сегіз қырлы - D8 және т.б.)

roll() әдісі 1 мен жақтардың саны ❷ арасындағы кездейсоқ санды қайтару үшін randint() функциясын пайдаланады. Бұл функция бастапқы мәнді (1), аяқталу мәнін (num_sides) немесе екеуінің арасындағы кез келген бүтін санды қайтара алады.

Өлшемді айналдыру

Die сыныбына негізделген визуализация жасамас бұрын, D6-ны айналдырып, нәтижелерді басып шығарайық және нәтижелердің орынды екенін тексерейік:

die_visual.py

from die import Die
        
        # Create a D6.
        ❶ die = Die()
        
        # Make some rolls, and store results in a list.
        results = []
        ❷ for roll_num in range(100):
            result = die.roll()
            results.append(result)
        
        print(results)

Біз әдепкі алты жағы ❶ бар Die данасын жасаймыз. Содан кейін біз пішінді 100 рет ❷ айналдырамыз және әрбір орамның нәтижесін нәтижелер тізімінде сақтаймыз. Мұнда нәтижелердің үлгі жинағы берілген:


        [4, 6, 5, 6, 1, 5, 6, 3, 5, 3, 5, 3, 2, 2, 1, 3,
        1, 5, 3, 6, 3, 6, 5, 4,  1, 1, 4, 2, 3, 6, 4, 2,
        6, 4, 1, 3, 2, 5, 6, 3, 6, 2, 1, 1, 3, 4, 1, 4,
        3, 5, 1, 4, 5, 5, 2, 3, 3, 1, 2, 3, 5, 6, 2, 5,
        6, 1, 3, 2, 1, 1, 1, 6, 5, 5, 2, 2, 6, 4, 1, 4,
        5, 1, 1, 1, 4, 5, 3, 3, 1, 3, 5, 4, 5, 6, 5, 4,
        1, 5, 1, 2]

Осы нәтижелерді жылдам сканерлеу Die сыныбының жұмыс істеп тұрғанын көрсетеді. Біз 1 және 6 мәндерін көреміз, сондықтан ең кіші және ең үлкен мүмкін мәндер қайтарылып жатқанын білеміз және 0 немесе 7 мәндерін көрмегендіктен, барлық нәтижелер сәйкес ауқымда екенін білеміз. Біз сондай-ақ 1-ден 6-ға дейінгі әрбір санды көреміз, бұл барлық ықтимал нәтижелер ұсынылғанын көрсетеді. Әр санның нақты қанша рет шығатынын анықтайық.

Нәтижелерді талдау

Әр санды қанша рет айналдырғанымызды санау арқылы бір D6 айналдыру нәтижелерін талдаймыз:

die_visual.py

--snip--
        # Make some rolls, and store results in a list.
        results = []
        ❶ for roll_num in range(1000):
            result = die.roll()
            results.append(result)
        
        # Analyze the results.
        frequencies = []
        ❷ poss_results = range(1, die.num_sides+1)
        for value in poss_results:
        ❸     frequency = results.count(value)
        ❹     frequencies.append(frequency)
        
        print(frequencies)

Нәтижелерді енді басып шығармайтындықтан, имитацияланған орамдар санын 1000 ❶-ге дейін көбейте аламыз. Орамдарды талдау үшін әрбір мәннің оралу санын сақтау үшін жиіліктердің бос тізімін жасаймыз. Содан кейін біз алуға болатын барлық ықтимал нәтижелерді жасаймыз; бұл мысалда 1-ден die-дың ❷ жақтары қанша болса да, бұл барлық сандар. Біз мүмкін мәндерді айналдырамыз, әр санның нәтижелер ❸ ішінде қанша рет пайда болатынын есептейміз, содан кейін бұл мәнді жиіліктерге ❹ қосамыз. Біз бұл тізімді визуализация жасамас бұрын басып шығарамыз:

[155, 167, 168, 170, 159, 181]

Бұл нәтижелер ақылға қонымды көрінеді: біз D6 айналдырған кезде әрбір ықтимал сан үшін бір-бірден болатын алты жиілікті көреміз. Біз сондай-ақ ешбір жиіліктің басқалардан айтарлықтай жоғары емес екенін көреміз. Енді осы нәтижелерді елестетіп көрейік.

Гистограмма жасау

Енді бізде қажетті деректер бар, біз Plotly Express көмегімен кодтың бірнеше жолында визуализация жасай аламыз:

die_visual.py

import plotly.express as px
        
        from die import Die
        --snip--
        
        for value in poss_results:
            frequency = results.count(value)
            frequencies.append(frequency)
        
        # Visualize the results.
        fig = px.bar(x=poss_results, y=frequencies)
        fig.show()

Алдымен plotly.express модулін әдеттегі px бүркеншік атын пайдаланып импорттаймыз. Содан кейін штрих-графиканы құру үшін px.bar() функциясын қолданамыз. Бұл функцияны қарапайым қолдануда бізге тек x-мәндер жиынын және y-мәндер жиынын беру керек. Мұндағы xмәндері - бір штампты айналдырудың мүмкін нәтижелері, ал y-мәндері - әрбір ықтимал нәтиженің жиілігі.

Соңғы жол fig.show() деп аталады, ол Плотлиге нәтиже диаграммасын HTML файлы ретінде көрсетуді және сол файлды жаңа шолғыш қойындысында ашуды ұсынады. Нәтиже 15-12-суретте көрсетілген.

Бұл өте қарапайым диаграмма және ол, әрине, толық емес. Бірақ дәл осылай Plotly Express пайдаланылуы керек; сіз кодтың бірнеше жолын жазасыз, сызбаға қарап, деректерді өзіңіз қалағандай көрсететініне көз жеткізіңіз. Көргеніңіз ұнаса, белгілер мен стильдер сияқты диаграмма элементтерін теңшеуге көшуге болады. Бірақ басқа ықтимал диаграмма түрлерін зерттегіңіз келсе, теңшеу жұмыстарына қосымша уақыт жұмсамай-ақ мұны қазір жасай аласыз. px.bar() параметрін px.scatter() немесе px.line() сияқты нәрсеге өзгерту арқылы мұны қазір байқап көріңіз. Қол жетімді диаграмма түрлерінің толық тізімін https://plotly.com/python/plotly-express< сайтынан таба аласыз. /a>.

Бұл диаграмма динамикалық және интерактивті. Браузер терезесінің өлшемін өзгертсеңіз, диаграмма қолжетімді кеңістікке сәйкес келетіндей өлшемін өзгертеді. Меңзерді кез келген жолақтың үстіне апарсаңыз, сол жолаққа қатысты нақты деректерді бөлектейтін қалқымалы терезені көресіз.

15-12-сурет: Plotly Express шығарған бастапқы сызба

сызбаны теңшеу

Енді бізде сызбаның дұрыс түрі бар екенін және деректеріміз дәл көрсетіліп жатқанын білгендіктен, біз диаграммаға сәйкес белгілер мен стильдерді қосуға назар аудара аламыз.

сызбаны Plotly көмегімен теңшеудің бірінші жолы - сызбаны жасайтын бастапқы шақыруда кейбір қосымша параметрлерді пайдалану, бұл жағдайда px.bar(). Мұнда әрбір ось үшін жалпы тақырып пен белгіні қосу жолы берілген:

die_visual.py

--snip--
        # Visualize the results.
        ❶ title = "Results of Rolling One D6 1,000 Times"
        ❷ labels = {'x': 'Result', 'y': 'Frequency of Result'}
        fig = px.bar(x=poss_results, y=frequencies, title=title, labels=labels)
        fig.show()

Біз алдымен өзімізге қажет тақырыпты анықтаймыз, мұнда title ❶ тағайындалады. Ось белгілерін анықтау үшін сөздік ❷ жазамыз. Сөздіктегі кілттер біз реттегіміз келетін белгілерге сілтеме жасайды, ал мәндер біз пайдаланғымыз келетін теңшелетін белгілер болып табылады. Мұнда біз x- осіне Нәтиже белгісін және y осіне Нәтиже жиілігі белгісін береміз. px.bar() шақыру енді title және label қосымша аргументтерін қамтиды.

Енді сызба жасалған кезде, 15-13-сурет ішінде көрсетілгендей әр ось үшін сәйкес тақырып пен белгіні қамтиды. .

15-13-сурет: Plotly көмегімен жасалған қарапайым бағаналы диаграмма

Екі сүйекті лақтыру

Екі сүйекті лақтыру үлкенірек сандар мен нәтижелердің басқаша таралуына әкеледі. Бір жұп сүйекті лақтыру жолын имитациялау үшін екі D6 сүйегін жасау үшін кодымызды өзгертейік. Жұпты айналдырған сайын біз екі санды қосамыз (әр өлкеден бір) және соманы нәтижелерде сақтаймыз. die_visual.py көшірмесін dice_visual.py ретінде сақтаңыз және келесі өзгерістерді енгізіңіз:

dice_visual.py

import plotly.express as px
        
        from die import Die
        
        # Create two D6 dice.
        die_1 = Die()
        die_2 = Die()
        
        # Make some rolls, and store results in a list.
        results = []
        for roll_num in range(1000):
        ❶     result = die_1.roll() + die_2.roll()
            results.append(result)
        
        # Analyze the results.
        frequencies = []
        ❷ max_result = die_1.num_sides + die_2.num_sides
        ❸ poss_results = range(2, max_result+1)
        for value in poss_results:
            frequency = results.count(value)
            frequencies.append(frequency)
        
        # Visualize the results.
        title = "Results of Rolling Two D6 Dice 1,000 Times"
        labels = {'x': 'Result', 'y': 'Frequency of Result'}
        fig = px.bar(x=poss_results, y=frequencies, title=title, labels=labels)
        fig.show()

Die екі данасын жасағаннан кейін біз сүйектерді лақтырамыз және әрбір атылған ❶ үшін екі сүйектің қосындысын есептейміз. Мүмкін болатын ең кіші нәтиже (2) - әрбір штамптағы ең кіші санның қосындысы. Мүмкін болатын ең үлкен нәтиже (12) әрбір штамптағы ең үлкен санның қосындысы болып табылады, оны біз max_result ❷ мәніне тағайындаймыз. max_result айнымалысы poss_results жасау үшін кодты оқуды ❸ әлдеқайда жеңілдетеді. Біз range(2, 13) жаза алар едік, бірақ бұл тек екі D6 сүйегі үшін жұмыс істейді. Нақты әлемдегі жағдайларды модельдеу кезінде әртүрлі жағдайларды оңай модельдейтін кодты жазған дұрыс. Бұл код бізге кез келген жақ саны бар сүйек жұбын айналдыруға ұқсауға мүмкіндік береді.

Осы кодты іске қосқаннан кейін сіз 15-14-сурет сияқты диаграмманы көресіз.

15-14-сурет: екі алты қырлы сүйекті 1000 рет лақтырудың модельденген нәтижелері

Бұл график D6 сүйегінің жұбын лақтырған кезде алуға болатын нәтижелердің шамамен үлестірілуін көрсетеді. Көріп отырғаныңыздай, сіз ең аз 2 немесе 12 және 7-ні айналдыруыңыз ықтимал. Бұл 7-ні айналдырудың алты жолы бар болғандықтан болады: 1 және 6, 2 және 5, 3 және 4, 4 және 3, 5 және 2, және 6 және 1.

Қосымша теңшеулер

Жаңа ғана жасаған сызбаға байланысты шешуіміз керек бір мәселе бар. Енді 11 жолақ болғандықтан, x-осі үшін әдепкі орналасу параметрлері кейбір жолақтарды таңбасыз қалдырады. Әдепкі параметрлер көптеген визуализациялар үшін жақсы жұмыс істегенімен, бұл диаграмма белгіленген барлық жолақтармен жақсырақ көрінеді.

Плотлидің update_layout() әдісі бар, ол фигураны жасағаннан кейін оған әр түрлі жаңартулар енгізу үшін қолданылады. Плотлиге әр жолақтың өз белгісін беруді қалай айту керек:

dice_visual.py

--snip--
        fig = px.bar(x=poss_results, y=frequencies, title=title, labels=labels)
        
        # Further customize chart.
        fig.update_layout(xaxis_dtick=1)
        
        fig.show()

update_layout() әдісі жалпы диаграмманы көрсететін fig нысанында әрекет етеді. Мұнда біз x осіндегі құсбелгілер арасындағы қашықтықты көрсететін xaxis_dtick аргументін қолданамыз. Біз бұл аралықты 1 етіп орнаттық, сонда әрбір жолақ белгіленеді. dice_visual.py файлын қайта іске қосқанда, әр жолақта белгіні көресіз.

Әртүрлі өлшемдегі сүйектерді домалату

Алты жақты матрицаны және он жақты матрицаны жасайық және оларды 50 000 рет айналдырсақ не болатынын көрейік:

dice_visual_d6d10.py

import plotly.express as px
        
        from die import Die
        
        # Create a D6 and a D10.
        die_1 = Die()
        ❶ die_2 = Die(10)
        
        # Make some rolls, and store results in a list.
        results = []
        for roll_num in range(50_000):
            result = die_1.roll() + die_2.roll()
            results.append(result)
        
        # Analyze the results.
        --snip--
        
        # Visualize the results.
        ❷ title = "Results of Rolling a D6 and a D10 50,000 Times"
        labels = {'x': 'Result', 'y': 'Frequency of Result'}
        --snip--

D10 жасау үшін екінші Die ❶ данасын жасау кезінде 10 аргументін береміз және 1000 орнына 50000 орамды модельдеу үшін бірінші циклды өзгертеміз. Графиктің тақырыбын да өзгертеміз ❷.

15-15-сурет нәтиже диаграммасын көрсетеді. Бір ықтимал нәтиженің орнына осындай бес нәтиже бар. Бұл ең кіші мәнді (1 және 1) және ең үлкен мәнді (6 және 10) айналдырудың әлі де бір ғана жолы болғандықтан орын алады, бірақ кішірек штамп орташа сандарды шығару жолдарының санын шектейді. 7, 8, 9, 10 немесе 11 сандарын айналдырудың алты жолы бар, бұл ең көп таралған нәтижелер және олардың кез келгенін айналдыру ықтималдығы бірдей.

15-15-сурет: алты қырлы матрицаны және он қырлы матрицаны 50 000 рет айналдыру нәтижелері

Біздің сүйектердің лақтырылуын модельдеу үшін Плотлиді пайдалану мүмкіндігіміз бізге бұл құбылысты зерттеуде айтарлықтай еркіндік береді. Бірнеше минут ішінде сіз сүйектердің көп түрін пайдаланып, орасан көп орамдарды имитациялай аласыз.

Фигураларды сақтау

Сізге ұнайтын фигура болған кезде, сіз әрқашан браузер арқылы диаграмманы HTML файлы ретінде сақтай аласыз. Бірақ сіз мұны бағдарламалы түрде де жасай аласыз. Диаграммаңызды HTML файлы ретінде сақтау үшін fig.show() қоңырауын fig.write_html() шақыруымен ауыстырыңыз:

fig.write_html('dice_visual_d6d10.html')

write_html() әдісі бір аргументті қажет етеді: жазылатын файлдың атауы. Егер сіз тек файл атауын берсеңіз, файл .py файлымен бірдей каталогта сақталады. Сондай-ақ write_html() нысанын Path нысанымен шақырып, шығыс файлын жүйеде қалаған жеріңізге жаза аласыз.

Қорытынды

Бұл тарауда сіз деректер-жиынын жасауды және сол деректердің визуализациясын жасауды үйрендіңіз. Сіз Matplotlib көмегімен қарапайым сызбалар құрдыңыз және кездейсоқ серуендерді зерттеу үшін шашырау сызбасын қолдандыңыз. Сіз сондай-ақ Plotly көмегімен гистограмма жасап, оны әртүрлі өлшемдегі сүйектерді лақтыру нәтижелерін зерттеу үшін пайдаландыңыз.

Кодпен жеке деректер-жиынын жасау - нақты әлемдегі жағдайлардың алуан түрін модельдеудің және зерттеудің қызықты және қуатты тәсілі. Келесі деректерді визуализациялау жобаларымен жұмыс істеуді жалғастыра отырып, кодпен модельдеуге болатын жағдайларды қадағалаңыз. Жаңалықтар медиасында көретін визуализацияларды қараңыз және осы жобаларда үйреніп жатқан әдістерге ұқсас әдістер арқылы жасалғандарын анықтай алатыныңызды тексеріңіз.

16-тарауда деректерді онлайн көздерден жүктеп алып, сол деректерді зерттеу үшін Matplotlib пен Plotly пайдалануды жалғастырасыз.

Ақпарат жүктеу

ITUniver

16
Ақпарат жүктеу

Бұл тарауда сіз онлайн көздерден деректер-жиынын жүктеп алып, сол деректердің жұмыс визуализациясын жасайсыз. Интернетте сіз көптеген мәліметтерді таба аласыз, олардың көпшілігі мұқият зерттелмеген. Бұл деректерді талдау мүмкіндігі ешкім таппаған үлгілер мен байланыстарды табуға мүмкіндік береді.

Біз екі жалпы деректер пішімінде сақталған деректерге қол жеткіземіз және визуализациялаймыз: CSV және JSON. CSV пішімінде сақталған ауа райы деректерін өңдеу және екі түрлі жерде уақыт өте жоғары және төмен температураларды талдау үшін Python бағдарламасының csv модулін қолданамыз. Содан кейін біз Matplotlib қолданбасын жүктеп алған деректерімізге негізделген диаграмманы жасау үшін пайдаланамыз, ол екі түрлі ортада температураның өзгеруін көрсетеді: Ситка, Аляска және Өлім алқабы, Калифорния. Кейінірек тарауда GeoJSON пішімінде сақталған жер сілкінісі деректеріне қол жеткізу үшін json модулін қолданамыз және соңғы жер сілкінісінің орындары мен магнитудасын көрсететін әлем картасын салу үшін Plotly қолданбасын қолданамыз.

Осы тараудың соңында сіз әртүрлі пішімдегі деректер-жиынының әртүрлі түрлерімен жұмыс істеуге дайын боласыз және күрделі визуализацияларды құру жолын тереңірек түсінесіз. Желідегі деректерге қол жеткізу және оларды визуализациялау мүмкіндігі нақты әлемдегі деректер жиындарының кең ауқымымен жұмыс істеу үшін өте маңызды.

CSV файл пішімі

Мәтіндік файлда деректерді сақтаудың бір қарапайым жолы - деректерді үтірмен бөлінген мәндер деп аталатын үтірмен бөлінген мәндер қатары ретінде жазу. Алынған файлдар CSV файлдары болып табылады. Мысалы, CSV пішіміндегі ауа райы деректерінің бір бөлігі:

"USW00025333","SITKA AIRPORT, AK US","2021-01-01",,"44","40"

Бұл 2021 жылдың 1 қаңтарындағы Ситка, Аляскадағы ауа райы деректерінің үзіндісі. Оған күннің жоғары және төмен температуралары, сондай-ақ сол күннің басқа да бірқатар өлшемдері кіреді. CSV файлдарын оқу адамға жалықтыруы мүмкін, бірақ бағдарламалар олардан ақпаратты жылдам және дәл өңдеп, шығарып алады.

Біз Ситкада жазылған CSV форматындағы ауа райы деректерінің шағын жиынтығынан бастаймыз; ол осы кітаптың ресурстарында https://ehmatthes.github.io/pcc_3e мекенжайында қолжетімді. Осы тараудың бағдарламаларын сақтайтын каталог ішінде ауа райы_деректері деп аталатын каталогты жасаңыз. sitka_weather_07-2021_simple.csv файлын осы жаңа каталогқа көшіріңіз. (Осы кітаптың ресурстарын жүктеп алғаннан кейін сізде осы жобаға қажет файлдардың барлығы болады.)

CSV файл тақырыптарын талдау

Стандартты кітапханадағы Python бағдарламасының csv модулі CSV файлындағы Тіркестерді талдайды және бізді қызықтыратын мәндерді жылдам шығаруға мүмкіндік береді. Бірінші Тіркесті тексеруден бастайық. деректерге арналған тақырыптар қатарын қамтитын файлдың. Бұл тақырыптар деректерде қандай ақпарат бар екенін айтады:

sitka_highs.py

from pathlib import Path
        import csv
        
         path = Path('weather_data/sitka_weather_07-2021_simple.csv')
        lines = path.read_text().splitlines()
        
         reader = csv.reader(lines)
         header_row = next(reader)
        print(header_row)

Алдымен Path және csv модулін импорттаймыз. Содан кейін біз weather_data каталогында көрінетін және біз жұмыс істегіміз келетін арнайы ауа райы деректерінің файлын көрсететін Path нысанын жасаймыз. ❶. Біз файлды оқып, файлдағы барлық Тіркестердің тізімін алу үшін splitlines() әдісін тізбектейміз, біз оны lines-ға тағайындаймыз.

Кейін, біз reader нысанын ❷ жасаймыз. Бұл файлдағы әрбір Тіркесті талдау үшін пайдалануға болатын нысан. Оқырман нысанын жасау үшін csv.reader() функциясын шақырыңыз және оған CSV файлындағы жолдар тізімін беріңіз.

reader нысаны берілгенде, next() функциясы файлдың басынан бастап файлдағы келесі Тіркесті қайтарады. Мұнда біз тек бір рет next() шақырамыз, сондықтан біз файлдың тақырыптарын қамтитын файлдың бірінші жолын аламыз. ❸. Біз header_row ішіне қайтарылған деректерді тағайындаймыз. Көріп отырғаныңыздай, header_row мазмұнында ауа райына қатысты тақырыптар бар, олар бізге деректердің әрбір жолында қандай ақпаратты қамтитынын айтады:

['STATION', 'NAME', 'DATE', 'TAVG', 'TMAX', 'TMIN']

reader нысаны файлдағы үтірмен бөлінген мәндердің бірінші жолын өңдейді және әрбір мәнді тізімдегі элемент ретінде сақтайды. STATION тақырыбы осы деректерді жазған метеостанцияның кодын білдіреді. Бұл тақырыптың орны әрбір Тіркестегі бірінші мән метеостанция коды болатынын көрсетеді. NAME тақырыбы әрбір Тіркестегі екінші мән жазбаны жасаған метеостанцияның атауы екенін көрсетеді. Қалған тақырыптар әрбір оқылымда қандай ақпарат түрлері жазылғанын көрсетеді. Бізді қазір ең қызықтыратын деректер күн (DATE), жоғары температура (TMAX) және төмен температура (TMIN) Бұл тек температураға қатысты деректерді қамтитын қарапайым деректер жинағы. Жеке ауа райы деректерін жүктеп алған кезде жел жылдамдығына, жел бағытына және жауын-шашын деректеріне қатысты бірқатар басқа өлшемдерді қосуды таңдауға болады.

Тақырыптарды және олардың орындарын басып шығару

Файл тақырыбының деректерін түсінуді жеңілдету үшін әрбір тақырыпты және оның тізімдегі орнын басып шығарайық:

sitka_highs.py

--snip/код үзіндісі--
        reader = csv.reader(lines)
        header_row = next(reader)
        
        for index, column_header in enumerate(header_row):
            print(index, column_header)

enumerate() функциясы тізімді айналдырған кезде әрбір элементтің индексін де, әрбір элементтің мәнін де қайтарады. (Осы егжей-тегжейлі нұсқаның пайдасына print(header_row) жолын алып тастағанымызды ескеріңіз.)

Міне, әрбір тақырыптың индексін көрсететін шығыс:

0 STATION
        1 NAME
        2 DATE
        3 TAVG
        4 TMAX
        5 TMIN

Біз күндер мен олардың жоғары температуралары 2 және 4-бағандарда сақталғанын көреміз. Бұл деректерді зерттеу үшін sitka_weather_07-2021_simple.csv ішіндегі деректердің әрбір жолын өңдеп, оны шығарып аламыз. 2 және 4 индекстері бар мәндер.

Деректерді шығару және оқу

Енді бізге қандай деректер бағандары қажет екенін білеміз, сол деректердің кейбірін оқып көрейік. Біріншіден, біз әр күн үшін жоғары температурада оқимыз:

sitka_highs.py

--snip/код үзіндісі--
        reader = csv.reader(lines)
        header_row = next(reader)
        
        # Extract high temperatures.
         highs = []
         for row in reader:
             high = int(row[4])
            highs.append(high)
        
        print(highs)

Біз highs деп аталатын бос тізім жасаймыз ❶содан кейін файлдағы қалған жолдар арқылы айналдырыңыз ❷. reader нысаны CSV файлында тоқтаған жерінен жалғасады және әрбір Тіркесті автоматты түрде ағымдағы орнынан кейін қайтарады. Біз тақырып жолын оқып қойғандықтан, цикл нақты деректер басталатын екінші жолдан басталады. Әрбір цикл арқылы өткенде біз TMAX тақырыбына сәйкес келетін 4 индексінен деректерді шығарып, оны high айнымалысына тағайындаймыз. ❸. Жол ретінде сақталатын деректерді сандық пішімге түрлендіру үшін int() функциясын қолданамыз, осылайша оны пайдалана аламыз. Содан кейін бұл мәнді highs мәніне қосамыз.

Келесі тізім қазір highs ішінде сақталған деректерді көрсетеді:

[61, 60, 66, 60, 65, 59, 58, 58, 57, 60, 60, 60, 57, 58, 60, 61, 63, 63, 70, 64, 59, 63, 61, 58, 59, 64, 62, 70, 70, 73, 66]

Біз әр күн үшін жоғары температураны шығарып, әрбір мәнді тізімде сақтадық. Енді осы деректердің визуализациясын жасайық.

Температура диаграммасында деректерді салу

Бізде бар температура деректерін визуализациялау үшін алдымен Matplotlib көмегімен күнделікті ең жоғары көрсеткіштердің қарапайым сызбасын мына жерде көрсетілгендей жасаймыз:

sitka_highs.py

from pathlib import Path
        import csv
        
        import matplotlib.pyplot as plt
        
        path = Path('weather_data/sitka_weather_07-2021_simple.csv')
        lines = path.read_text().splitlines()
            --snip/код үзіндісі--
        
        # Plot the high temperatures.
        plt.style.use('seaborn')
        fig, ax = plt.subplots()
         ax.plot(highs, color='red')
        
        # Format plot.
         ax.set_title("Daily High Temperatures, July 2021", fontsize=24)
         ax.set_xlabel('', fontsize=16)
        ax.set_ylabel("Temperature (F)", fontsize=16)
        ax.tick_params(labelsize=16)
        
        plt.show()

Біз биіктіктер тізімін plot() параметріне береміз және нүктелерді қызыл түспен салу үшін color='red' жібереміз. ❶. (Біз ең жоғарғы нүктелерді қызыл түспен, ал төменгі нүктелерді көк түспен белгілейміз.) Содан кейін тақырып, қаріп өлшемі және белгілер сияқты басқа пішімдеу мәліметтерін көрсетеміз. ❷, дәл біз 15-тарауда істегеніміздей. Күндерді әлі қосуымыз керек болғандықтан, біз x-осін белгілемейміз, бірақ ax.set_xlabel() әдепкі белгілерді көбірек ету үшін қаріп өлшемін өзгертеді. оқылатын ❸. 16-1суретте алынған сызба көрсетілген: 2021 жылдың шілде айындағы Ситка, Аляскадағы жоғары температураның қарапайым сызықтық графигі.

16-1-сурет: 2021 жылдың шілде айындағы Ситка, Аляскадағы күнделікті жоғары температураны көрсететін сызықтық график

Datetime модулі

Графигімізді пайдалырақ ету үшін күндерді қосамыз. Ауа райы деректері файлының бірінші күні файлдың екінші жолында:

"USW00025333","SITKA AIRPORT, AK US","2021-07-01",,"61","53"

Деректер жол ретінде оқылады, сондықтан бізге "2021-07-01" жолын осы күнді көрсететін нысанға түрлендіру жолы қажет. datetime модулінен strptime() әдісін пайдаланып, 2021 жылдың 1 шілдесіндегі нысанды құра аламыз. strptime() терминал сеансында қалай жұмыс істейтінін көрейік:

>>> from datetime import datetime
        >>> first_date = datetime.strptime('2021-07-01', '%Y-%m-%d')
        >>> print(first_date)
        2021-07-01 00:00:00

Алдымен datetime класын datetime модулінен импорттаймыз. Содан кейін біз бірінші аргумент ретінде өңдегіміз келетін күнді қамтитын жолмен strptime() әдісін шақырамыз. Екінші аргумент Python-ға күннің қалай пішімделгенін айтады. Бұл мысалда '%Y-' Python-ға бірінші сызықшадан бұрын төрт сандық жылды іздеуді айтады; '%m-' екінші сызықша алдындағы екі таңбалы айды көрсетеді; және '%d' Тіркестің соңғы бөлігі 1-ден 31-ге дейінгі ай күнін білдіреді.

strptime() әдісі күнді қалай түсіндіру керектігін анықтау үшін әртүрлі аргументтерді қабылдауы мүмкін. 16-1-кесте осы аргументтердің кейбірін көрсетеді.

16-1-кесте: datetime модуліндегі күн мен уақытты пішімдеу аргументтері

Argument Meaning
%A Weekday name, such as Monday
%B Month name, such as January
%m Month, as a number (01 to 12)
%d Day of the month, as a number (01 to 31)
%Y Four-digit year, such as 2019
%y Two-digit year, such as 19
%H Hour, in 24-hour format (00 to 23)
%I Hour, in 12-hour format (01 to 12)
%p AM or PM
%M Minutes (00 to 59)
%S Seconds (00 to 61)

Графиктік күндер

Күнделікті жоғары температура көрсеткіштері үшін күндерді алу және осы күндерді x осінде пайдалану арқылы сызбаны жақсарта аламыз:

sitka_highs.py

from pathlib import Path
        import csv
        from datetime import datetime
        
        import matplotlib.pyplot as plt
        
        path = Path('weather_data/sitka_weather_07-2021_simple.csv')
        lines = path.read_text().splitlines()
        
        reader = csv.reader(lines)
        header_row = next(reader)
        
        # Extract dates and high temperatures.
         dates, highs = [], []
        for row in reader:
             current_date = datetime.strptime(row[2], '%Y-%m-%d')
            high = int(row[4])
            dates.append(current_date)
            highs.append(high)
        
        # Plot the high temperatures.
        plt.style.use('seaborn')
        fig, ax = plt.subplots()
         ax.plot(dates, highs, color='red')
        
        # Format plot.
        ax.set_title("Daily High Temperatures, July 2021", fontsize=24)
        ax.set_xlabel('', fontsize=16)
         fig.autofmt_xdate()
        ax.set_ylabel("Temperature (F)", fontsize=16)
        ax.tick_params(labelsize=16)
        
        plt.show()

Біз файлдағы күндер мен жоғары температураларды сақтау үшін екі бос тізім жасаймыз ❶. Содан кейін күн ақпараты бар деректерді (row[2]) datetime нысанына түрлендіреміз.❷ және оны күндерге қосыңыз. Күндер мен жоғары температура мәндерін plot()-ге береміз❸. fig.autofmt_xdate() шақыру ❹ күн белгілерін олардың қабаттасуына жол бермеу үшін диагональ бойынша салады. 16-2суретте жақсартылған график көрсетілген.

16-2-сурет: График енді x осінде күндер болғандықтан, мағыналырақ.

Ұзақ уақыт аралығын сызу

Графигімізді орнату арқылы Ситкадағы ауа райының толық бейнесін алу үшін қосымша деректерді қосамыз. Ситка үшін толық жылдық ауа райы деректерін қамтитын sitka_weather_2021_simple.csv файлын осы тарау бағдарламаларының деректерін сақтайтын каталогқа көшіріңіз.

Енді біз жыл бойы ауа райының графигін жасай аламыз:

sitka_highs.py

--snip/код үзіндісі--
        path = Path('weather_data/sitka_weather_2021_simple.csv')
        lines = path.read_text().splitlines()
        --snip/код үзіндісі--
        # Format plot.
        ax.set_title("Daily High Temperatures, 2021", fontsize=24)
        ax.set_xlabel('', fontsize=16)
        --snip/код үзіндісі--

Біз файл атауын sitka_weather_2021_simple.csv жаңа деректер файлын пайдалану үшін өзгертеміз және оның мазмұнындағы өзгерісті көрсету үшін сызбаларымыздың тақырыбын жаңартамыз.16-3суретте алынған сызба көрсетілген.

Сурет 16-3: Бір жылдық деректер

Екінші деректер сериясын құру

Төмен температураны қосу арқылы біз графикті одан да пайдалы ете аламыз. Деректер файлынан төмен температураларды шығарып, оларды мына жерде көрсетілгендей графикке қосуымыз керек:

sitka_highs_lows.py

--snip/код үзіндісі--
        reader = csv.reader(lines)
        header_row = next(reader)
        
        # Extract dates, and high and low temperatures.
         dates, highs, lows = [], [], []
        for row in reader:
            current_date = datetime.strptime(row[2], '%Y-%m-%d')
            high = int(row[4])
             low = int(row[5])
            dates.append(current_date)
            highs.append(high)
            lows.append(low)
        
        # Plot the high and low temperatures.
        plt.style.use('seaborn')
        fig, ax = plt.subplots()
        ax.plot(dates, highs, color='red')
         ax.plot(dates, lows, color='blue')
        
        # Format plot.
         ax.set_title("Daily High and Low Temperatures, 2021", fontsize=24)
        --snip/код үзіндісі--

Төмен температураларды ұстап тұру үшін lows бос тізімді қосамыз❶, содан кейін біз әр Тіркестегі алтыншы позициядан әрбір күн үшін төмен температураны шығарып, сақтаймыз (row[5]) ❷. Төмен температуралар үшін plot() шақыруды қосамыз және бұл мәндерді көк түске бояймыз ❸. Соңында біз тақырыпты жаңартамыз ❹. 16-4суретте алынған диаграмма көрсетілген.

16-4-сурет: Бір сызбадағы екі деректер қатары

Диаграммадағы аумақты көлеңкелеу

Екі деректер сериясын қосқаннан кейін біз енді әр күн үшін температура ауқымын тексере аламыз. Күнделікті жоғары және төмен температуралар арасындағы диапазонды көрсету үшін көлеңкелеуді пайдалану арқылы графикті аяқтаймыз. Ол үшін x-мәндер қатарын және y мәндерінің екі қатарын алатын fill_between() әдісін қолданамыз. және yмәндердің екі қатары арасындағы бос орынды толтырады:

sitka_highs_lows.py

--snip/код үзіндісі--
        # Plot the high and low temperatures.
        plt.style.use('seaborn')
        fig, ax = plt.subplots()
         ax.plot(dates, highs, color='red', alpha=0.5)
        ax.plot(dates, lows, color='blue', alpha=0.5)
         ax.fill_between(dates, highs, lows, facecolor='blue', alpha=0.1)
        --snip/код үзіндісі--

The alpha argument controls a color’s transparency ❶. An alpha value of 0 is completely transparent, and a value of 1 (the default) is completely opaque. By setting alpha to 0.5, we make the red and blue plot lines appear lighter.

Біз x-мәндері үшін fill_between() күндер тізімін, содан кейін yмәндік қатарын < жібереміз. code>жоғары және төмен ❷. facecolor аргументі көлеңкеленген аймақтың түсін анықтайды; біз оған 0,1 төмен alpha мәнін береміз, осылайша толтырылған аймақ екі деректер қатарын олар көрсететін ақпараттан алаңдатпай қосады. 16-5суретте биіктіктер мен ең төменгілер арасындағы көлеңкеленген аймақ бар сызба көрсетілген.

16-5-сурет: Екі деректер-жиынының арасындағы аймақ көлеңкеленген.

Көлеңкелеу екі деректер жиыны арасындағы ауқымды бірден көрсетуге көмектеседі.

Тексеру қатесі

кез-келген орын деректерін пайдаланып, sitka_highs_lows.py кодын іске қоса алуымыз керек. Бірақ кейбір метеостанциялар басқаларға қарағанда әртүрлі деректерді жинайды, ал кейбіреулері анда-санда дұрыс жұмыс істемейді және кейбір деректерін жинай алмайды. Жетіспейтін деректер, егер біз оларды дұрыс өңдемейінше, бағдарламаларды бұзатын ерекше жағдайларға әкелуі мүмкін.

Мысалы, Өлім алқабы, Калифорния үшін температура графигін жасауға әрекеттенгенде не болатынын көрейік. death_valley_2021_simple.csv файлын осы тарау бағдарламаларының деректерін сақтайтын каталогқа көшіріңіз.

Алдымен осы деректер файлында қамтылған тақырыптарды көру үшін кодты іске қосайық:

death_valley_highs_lows.py

from pathlib import Path
        import csv
        
        path = Path('weather_data/death_valley_2021_simple.csv')
        lines = path.read_text().splitlines()
        
        reader = csv.reader(lines)
        header_row = next(reader)
        
        for index, column_header in enumerate(header_row):
            print(index, column_header)

Here’s the output:

0 STATION
        1 NAME
        2 DATE
        3 TMAX
        4 TMIN
        5 TOBS

Күн бірдей күйде, 2-индексте. Бірақ жоғары және төмен температуралар 3 және 4 индекстерінде, сондықтан осы жаңа позицияларды көрсету үшін кодымыздағы индекстерді өзгертуіміз керек. Тәулік бойына орташа температура көрсеткішін қосудың орнына бұл станцияда белгілі бір бақылау уақытының көрсеткіші TOBS бар.

Біз жаңа ғана атап өткен индекстерді пайдаланып Өлім алқабының графигін жасау үшін sitka_highs_lows.py файлын өзгертіңіз және не болатынын көріңіз:

death_valley_highs_lows.py

--snip/код үзіндісі--
        path = Path('weather_data/death_valley_2021_simple.csv')
        lines = path.read_text().splitlines()
            --snip/код үзіндісі--
        # Extract dates, and high and low temperatures.
        dates, highs, lows = [], [], []
        for row in reader:
            current_date = datetime.strptime(row[2], '%Y-%m-%d')
            high = int(row[3])
            low = int(row[4])
            dates.append(current_date)
        --snip/код үзіндісі--

Біз бағдарламаны Өлім алқабының деректер файлынан оқу үшін жаңартамыз және индекстерді осы файлдың TMAX және TMIN орындарына сәйкес келетіндей етіп өзгертеміз.

Бағдарламаны іске қосқан кезде қате пайда болады:

Traceback (most recent call last):
          File "death_valley_highs_lows.py", line 17, in <module>
            high = int(row[3])
         ValueError: invalid literal for int() with base 10: ''

Бақылау бізге Python бір күн үшін жоғары температураны өңдей алмайтынын айтады, себебі ол бос Тіркесті ('') бүтін санға айналдыра алмайды. ❶. Қай оқудың жоқ екенін анықтау үшін деректерді қарап шығудың орнына, біз деректердің жетіспейтін жағдайларын тікелей өңдейміз.

Мәндер CSV файлынан оқылып жатқанда, туындауы мүмкін ерекшеліктерді өңдеу үшін қателерді тексеру кодын іске қосамыз. Мұны істеу жолы:

death_valley_highs_lows.py

--snip/код үзіндісі--
        for row in reader:
            current_date = datetime.strptime(row[2], '%Y-%m-%d')
             try:
                high = int(row[3])
                low = int(row[4])
            except ValueError:
                 print(f"Missing data for {current_date}")
             else:
                dates.append(current_date)
                highs.append(high)
                lows.append(low)
        
        # Plot the high and low temperatures.
        --snip/код үзіндісі--
        
        # Format plot.
         title = "Daily High and Low Temperatures, 2021\nDeath Valley, CA"
        ax.set_title(title, fontsize=20)
        ax.set_xlabel('', fontsize=16)
        --snip/код үзіндісі--

Біз Тіркесті тексерген сайын күн мен жоғары және төмен температураны алуға тырысамыз ❶. кез-келген деректер жетіспейтін болса, Python ValueError шығарады және біз оны жетіспейтін деректер күнін қамтитын қате туралы хабарды басып шығару арқылы өңдейміз. ❷. Қатені басып шығарғаннан кейін цикл келесі Тіркесті өңдеуді жалғастырады. Егер күннің барлық деректері қатесіз алынса, else блогы іске қосылады және деректер сәйкес тізімдерге қосылады. ❸. Біз жаңа орынға арналған ақпаратты сызып жатқандықтан, тақырыпты сызбадағы орынды қосу үшін жаңартамыз және ұзынырақ тақырыпты орналастыру үшін қаріптің кішірек өлшемін қолданамыз. ❹.

Қазір death_valley_highs_lows.py қолданбасын іске қосқанда, тек бір күннің деректері жоқ екенін көресіз:

Missing data for 2021-05-04 00:00:00

Қате дұрыс өңделгендіктен, біздің код жетіспейтін деректерді өткізіп жіберетін сызбаны құра алады. 16-6-сурет нәтиже сызбасын көрсетеді.

Осы графикті Ситка графигімен салыстыра отырып, біз күткендей, Өлім алқабының оңтүстік-шығыс Аляскаға қарағанда жылырақ екенін көреміз. Сондай-ақ, күн сайынғы температура диапазоны шөлде көбірек. Көлеңкеленген аймақтың биіктігі мұны анық көрсетеді.

16-6-сурет: Өлім алқабындағы күнделікті жоғары және төмен температура

Сіз жұмыс істейтін көптеген деректер-жиынында жоқ, дұрыс пішімделген немесе қате деректер болады. Осы жағдайларды шешу үшін осы кітаптың бірінші жартысында үйренген құралдарды пайдалана аласыз. Мұнда жетіспейтін деректерді өңдеу үшін try-except-else блогын қолдандық. Кейде кейбір деректерді өткізіп жіберу үшін continue немесе кейбір деректерді шығарып алғаннан кейін жою үшін remove() немесе del пайдаланыңыз. Нәтиже мағыналы, дәл визуализация болған кезде жұмыс істейтін кез-келген тәсілді пайдаланыңыз.

Жеке деректеріңізді жүктеп алу

Жеке ауа райы деректерін жүктеп алу үшін мына қадамдарды орындаңыз:

  1. Visit the NOAA Climate Data Online site at https://www.ncdc.noaa.gov/cdo-web. In the Discover Data By section, click Search Tool. In the Select a Dataset box, choose Daily Summaries.
  2. Select a date range, and in the Search For section, choose ZIP Codes. Enter the ZIP code you’re interested in and click Search.
  3. On the next page, you’ll see a map and some information about the area you’re focusing on. Below the location name, click View Full Details, or click the map and then click Full Details.
  4. Scroll down and click Station List to see the weather stations that are available in this area. Click one of the station names and then click Add to Cart. This data is free, even though the site uses a shopping cart icon. In the upper-right corner, click the cart.
  5. In Select the Output Format, choose Custom GHCN-Daily CSV. Make sure the date range is correct and click Continue.
  6. On the next page, you can select the kinds of data you want. You can download one kind of data (for example, focusing on air temperature) or you can download all the data available from this station. Make your choices and then click Continue.
  7. On the last page, you’ll see a summary of your order. Enter your email address and click Submit Order. You’ll receive a confirmation that your order was received, and in a few minutes, you should receive another email with a link to download your data.

Сіз жүктеп алған деректер осы бөлімде біз жұмыс істеген деректер сияқты құрылымдалған болуы керек. Оның тақырыптары осы бөлімде көргендерден басқаша болуы мүмкін, бірақ егер сіз осы жерде қолданылған қадамдарды орындасаңыз, сізді қызықтыратын деректердің визуализациясын жасай алуыңыз керек.

Жаһандық деректер-жиынын салыстыру: GeoJSON пішімі

Бұл бөлімде сіз өткен айда әлемде болған барлық жер сілкіністерін көрсететін деректер жинағын жүктейсіз. Содан кейін сіз осы жер сілкінісінің орнын және олардың әрқайсысының қаншалықты маңызды екенін көрсететін карта жасайсыз. Деректер GeoJSON пішімінде сақталғандықтан, біз онымен json модулі арқылы жұмыс істейміз. Plotly компаниясының scatter_geo() сызбасын пайдалана отырып, жер сілкінісінің жаһандық таралуын анық көрсететін визуализациялар жасайсыз.

Жер сілкінісі деректерін жүктеп алу

Осы тараудың бағдарламаларын сақтайтын каталог ішінде eq_data деп аталатын каталогты жасаңыз. eq_1_day_m1.geojson файлын осы жаңа каталогқа көшіріңіз. Жер сілкіністері Рихтер шкаласы бойынша магнитудасы бойынша жіктеледі. Бұл файл соңғы 24 сағат ішінде (осы жазу кезінде) магнитудасы M1 немесе одан жоғары барлық жер сілкіністерінің деректерін қамтиды. Бұл деректер https://earthquake.usgs.gov мекенжайындағы Америка Құрама Штаттарының геологиялық қызметінің жер сілкінісі туралы деректер арналарының бірінен алынған. /жер сілкінісі/жемі.

GeoJSON деректерін тексеру

eq_1_day_m1.geojson ашқанда, оның өте тығыз және оқу қиын екенін көресіз:

{"type":"FeatureCollection","metadata":{"generated":1649052296000,...
        {"type":"Feature","properties":{"mag":1.6,"place":"63 km SE of Ped...
        {"type":"Feature","properties":{"mag":2.2,"place":"27 km SSE of Ca...
        {"type":"Feature","properties":{"mag":3.7,"place":"102 km SSE of S...
        {"type":"Feature","properties":{"mag":2.92000008,"place":"49 km SE...
        {"type":"Feature","properties":{"mag":1.4,"place":"44 km NE of Sus...
        --snip/код үзіндісі--

Бұл файл адамдарға қарағанда машиналар үшін көбірек пішімделген. Бірақ біз бұл файлда кейбір сөздіктер, сондай-ақ жер сілкінісінің магнитудасы мен орны сияқты бізді қызықтыратын ақпарат бар екенін көреміз.

json модулі JSON деректерін зерттеуге және олармен жұмыс істеуге арналған әртүрлі құралдарды ұсынады. Осы құралдардың кейбірі файлды қайта пішімдеуге көмектеседі, осылайша біз онымен бағдарламалық түрде жұмыс жасамас бұрын бастапқы деректерді оңайырақ қарай аламыз.

Деректерді жүктеп, оны оқуға оңай пішімде көрсетуден бастайық. Бұл ұзақ деректер файлы, сондықтан оны басып шығарудың орнына деректерді жаңа файлға қайта жазамыз. Содан кейін біз бұл файлды ашып, деректерді алға және артқа оңай айналдыра аламыз:

eq_explore_data.py

from pathlib import Path
        import json
        
        # Read data as a string and convert to a Python object.
        path = Path('eq_data/eq_data_1_day_m1.geojson')
        contents = path.read_text()
         all_eq_data = json.loads(contents)
        
        # Create a more readable version of the data file.
         path = Path('eq_data/readable_eq_data.geojson')
         readable_contents = json.dumps(all_eq_data, indent=4)
        path.write_text(readable_contents)

Дерек файлын жол ретінде оқимыз және файлдың жол көрінісін Python нысанына түрлендіру үшін json.loads() қолданамыз.❶. Бұл біз 10-тарауда қолданған тәсіл. Бұл жағдайда бүкіл деректер жинағы бір сөздікке түрлендіріледі, оны біз all_eq_data тағайындаймыз. Содан кейін біз дәл сол деректерді оқылатын пішімде жаза алатын жаңа жол анықтаймыз ❷. Сіз көрген json.dumps() функциясы қосымша indent аргументін қабылдай алады ❸, ол деректер құрылымындағы кірістірілген элементтерді қанша шегініске салу керектігін айтады.

eq_data каталогын қарап, readable_eq_data.json файлын ашқанда, мына жерде көретін нәрсенің бірінші бөлігі:

readable_eq_data.json

{
            "type": "FeatureCollection",
             "metadata": {
                "generated": 1649052296000,
                "url": "https://earthquake.usgs.gov/earthquakes/.../1.0_day.geojson",
                "title": "USGS Magnitude 1.0+ Earthquakes, Past Day",
                "status": 200,
                "api": "1.10.3",
                "count": 160
            },
             "features": [
            --snip/код үзіндісі--

Файлдың бірінші бөлігінде "metadata"❶ кілті бар бөлім бар. Бұл деректер файлының қашан жасалғанын және деректерді желіде қайдан табуға болатынын көрсетеді. Сондай-ақ ол бізге адам оқи алатын тақырыпты және осы файлға енгізілген жер сілкіністерінің санын береді. Осы 24 сағаттық кезеңде 160 жер сілкінісі тіркелді.

Бұл GeoJSON файлында орынға негізделген деректер үшін пайдалы құрылым бар. Ақпарат "мүмкіндіктер" ❷ кілтімен байланысты тізімде сақталады. Бұл файлда жер сілкінісі деректері бар болғандықтан, деректер тізімдегі әрбір элемент бір жер сілкінісіне сәйкес келетін тізім түрінде болады. Бұл құрылым түсініксіз болып көрінуі мүмкін, бірақ ол өте күшті. Ол геологтарға әр жер сілкінісі туралы сөздікте қажетінше ақпаратты сақтауға, содан кейін барлық сөздіктерді бір үлкен тізімге толтыруға мүмкіндік береді.

Бір жер сілкінісін білдіретін сөздікті қарастырайық:

readable_eq_data.json

    --snip/код үзіндісі--
                {
                    "type": "Feature",
                     "properties": {
                        "mag": 1.6,
                        --snip/код үзіндісі--
                         "title": "M 1.6 - 27 km NNW of Susitna, Alaska"
                    },
                     "geometry": {
                        "type": "Point",
                        "coordinates": [
                             -150.7585,
                             61.7591,
                            56.3
                        ]
                    },
                    "id": "ak0224bju1jx"
                },

"қасиеттер" кілті әрбір жер сілкінісі туралы ❶ туралы көптеген ақпаратты қамтиды. Бізді негізінен "mag" кілтімен байланысты әрбір жер сілкінісінің магнитудасы қызықтырады. Бізді сондай-ақ әрбір оқиғаның "атауы" қызықтырады, ол оның шамасы мен орны туралы жақсы қорытынды береді ❷.

"геометрия" кілті жер сілкінісінің қай жерде болғанын түсінуге көмектеседі ❸. Әрбір оқиғаны картаға түсіру үшін бізге бұл ақпарат қажет. Біз әрқайсысы үшін ❹ және ендік ❺ таба аламыз. "координаттар" кілтімен байланысты тізімдегі жер сілкінісі.

Бұл файлда біз жазатын кодта қолданатынымыздан әлдеқайда көбірек ұяшықтар бар, сондықтан түсініксіз болып көрінсе, алаңдамаңыз: Python күрделіліктің көп бөлігін шешеді. Біз бір уақытта тек бір немесе екі ұя салу деңгейімен жұмыс істейміз. Біз 24 сағаттық уақыт аралығында тіркелген әрбір жер сілкінісі үшін сөздікті шығарудан бастаймыз.

Барлық жер сілкіністерінің тізімін жасау

Біріншіден, біз әрбір орын алған жер сілкінісі туралы барлық ақпаратты қамтитын тізім жасаймыз.

eq_explore_data.py

from pathlib import Path
        import json
        
        # Read data as a string and convert to a Python object.
        path = Path('eq_data/eq_data_1_day_m1.geojson')
        contents = path.read_text()
        all_eq_data = json.loads(contents)
        
        # Examine all earthquakes in the dataset.
        all_eq_dicts = all_eq_data['features']
        print(len(all_eq_dicts))

Біз all_eq_data сөздігіндегі 'features' кілтімен байланысты деректерді аламыз және оны all_eq_dicts қызметіне тағайындаймыз. Бұл файлда 160 жер сілкінісінің жазбалары бар екенін білеміз және нәтиже файлдағы барлық жер сілкіністерін түсіргенімізді растайды:

160

Бұл кодтың қаншалықты қысқа екеніне назар аударыңыз. Дұрыс пішімделген readable_eq_data.json файлында 6000-нан астам жол бар. Бірақ бірнеше жолда біз барлық деректерді оқып, оны Python тізімінде сақтай аламыз. Әрі қарай әрбір жер сілкінісінің магнитудасын шығарамыз.

Магнитудаларды алу

Біз әрбір жер сілкінісі туралы деректерді қамтитын тізімді айналдыра аламыз және қалаған кез-келген ақпаратты шығара аламыз. Әрбір жер сілкінісінің магнитудасын шығарайық:

eq_explore_data.py

--snip/код үзіндісі--
        all_eq_dicts = all_eq_data['features']
        
         mags = []
        for eq_dict in all_eq_dicts:
             mag = eq_dict['properties']['mag']
            mags.append(mag)
        
        print(mags[:10])

Біз шамаларды сақтау үшін бос тізім жасаймыз, содан кейін all_eq_dicts тізімін айналдырамыз. ❶. Бұл цикл ішінде әрбір жер сілкінісі eq_dict сөздігімен берілген. Әрбір жер сілкінісінің магнитудасы осы сөздіктің 'қасиеттер' бөлімінде 'mag' кілтінің астында сақталады. ❷. Біз әрбір шаманы mag айнымалысында сақтаймыз, содан кейін оны mags тізіміне қосамыз.

Біз бірінші 10 магнитудасын басып шығарамыз, осылайша біз дұрыс деректерді алып жатқанымызды көре аламыз:

[1.6, 1.6, 2.2, 3.7, 2.92000008, 1.4, 4.6, 4.5, 1.9, 1.8]

Кейін әр жер сілкінісі үшін орын деректерін аламыз, содан кейін жер сілкінісінің картасын жасай аламыз.

Орын деректерін шығару

Әр жер сілкінісінің орын деректері "геометрия" кілтінің астында сақталады. Геометрия сөздігінің ішінде "координаттар" пернесі бар және бұл тізімдегі алғашқы екі мән - бойлық пен ендік. Бұл деректерді қалай аламыз:

eq_explore_data.py

--snip/код үзіндісі--
        all_eq_dicts = all_eq_data['features']
        
        mags, lons, lats = [], [], []
        for eq_dict in all_eq_dicts:
            mag = eq_dict['properties']['mag']
             lon = eq_dict['geometry']['coordinates'][0]
            lat = eq_dict['geometry']['coordinates'][1]
            mags.append(mag)
            lons.append(lon)
            lats.append(lat)
        
        print(mags[:10])
        print(lons[:5])
        print(lats[:5])

Біз бойлық пен ендік үшін бос тізімдер жасаймыз. eq_dict['geometry'] коды жер сілкінісі ❶ геометрия элементін білдіретін сөздікке қатынасады. Екінші кілт, 'coordinates', 'coordinates'-мен байланысты мәндер тізімін шығарады. Соңында, 0 индексі жер сілкінісінің бойлығына сәйкес келетін координаттар тізіміндегі бірінші мәнді сұрайды.

Бірінші 5 бойлық пен ендіктерді басып шығарған кезде, нәтиже дұрыс деректерді алып жатқанымызды көрсетеді:

[1.6, 1.6, 2.2, 3.7, 2.92000008, 1.4, 4.6, 4.5, 1.9, 1.8]
        [-150.7585, -153.4716, -148.7531, -159.6267, -155.248336791992]
        [61.7591, 59.3152, 63.1633, 54.5612, 18.7551670074463]

Осы деректер арқылы біз әрбір жер сілкінісінің картасын жасауға көшеміз.

Әлем картасын құру

Осы уақытқа дейін алынған ақпаратты пайдалана отырып, біз қарапайым әлем картасын жасай аламыз. Ол әлі көрінбейтін болса да, стиль мен көрсетілім мәселелеріне назар аудармас бұрын ақпараттың дұрыс көрсетілгеніне көз жеткізгіміз келеді. Міне, бастапқы карта:

eq_world_map.py

from pathlib import Path
        import json
        
        import plotly.express as px
        
        --snip/код үзіндісі--
        for eq_dict in all_eq_dicts:
            --snip/код үзіндісі--
        
        title = 'Global Earthquakes'
         fig = px.scatter_geo(lat=lats, lon=lons, title=title)
        fig.show()

Біз 15-тарауда жасағандай, plotly.express бүркеншік атымен px импорттаймыз. аралығы>. scatter_geo() функциясы ❶ картадағы географиялық деректердің шашыраңқы сызбасын қабаттастыруға мүмкіндік береді. Диаграмманың осы түрін қарапайым пайдалану кезінде тек ендіктер мен бойлықтардың тізімін беру қажет. lats тізімін lat аргументіне, ал lons - lon аргументіне

береміз.

Бұл файлды іске қосқан кезде, сіз 16-7-сурет-дегі картаға ұқсайтын картаны көресіз. Бұл тағы да Plotly Express кітапханасының күшін көрсетеді; Тек үш код жолында бізде жаһандық жер сілкінісі белсенділігінің картасы бар.

16-7-сурет: соңғы 24 сағаттағы барлық жер сілкіністерінің қай жерде болғанын көрсететін қарапайым карта

Деректер жинағымыздағы ақпарат дұрыс сызылып жатқанын білетіндіктен, картаны мағыналы және оқуды жеңілдету үшін бірнеше өзгертулер енгізе аламыз.

Мөлшерін білдіру

Жер сілкінісінің белсенділігінің картасы әрбір жер сілкінісінің магнитудасын көрсетуі керек. Деректердің дұрыс сызылып жатқанын білетіндіктен, біз қосымша деректерді де қоса аламыз.

--snip/код үзіндісі--
        # Read data as a string and convert to a Python object.
        path = Path('eq_data/eq_data_30_day_m1.geojson')
        contents = path.read_text()
        --snip/код үзіндісі--
        
        title = 'Global Earthquakes'
        fig = px.scatter_geo(lat=lats, lon=lons, size=mags, title=title)
        fig.show()

Толық 30 күндік жер сілкінісі әрекетін қамту үшін eq_data_30_day_m1.geojson файлын жүктейміз. Картадағы нүктелердің өлшемі қалай болатынын көрсететін px.scatter_geo() шақыруында өлшем аргументін де қолданамыз. Біз mags тізімін size-ге береміз, сондықтан магнитудасы жоғары жер сілкіністері картада үлкенірек нүктелер ретінде көрсетіледі.

Нәтижедегі карта 16-8-суретте көрсетілген. Жер сілкінісі әдетте тектоникалық плиталар шекараларына жақын жерде болады және осы картаға енгізілген жер сілкінісі белсенділігінің ұзағырақ кезеңі бұл шекаралардың нақты орындарын көрсетеді.

16-8-сурет: карта енді соңғы 30 күндегі барлық жер сілкінісінің магнитудасын көрсетеді.

Бұл карта жақсырақ, бірақ ең маңызды жер сілкіністерін көрсететін нүктелерді таңдау әлі де қиын. Мұны шамаларды көрсету үшін түстерді пайдалану арқылы одан әрі жақсартуға болады.

Маркер түстерін теңшеу

Сәйкес жер сілкінісінің ауырлығына сәйкес әр маркердің түсін теңшеу үшін Plotly түс шкалаларын пайдалана аламыз. Негізгі карта үшін басқа проекцияны да қолданамыз.

eq_world_map.py

--snip/код үзіндісі--
        fig = px.scatter_geo(lat=lats, lon=lons, size=mags, title=title,
                 color=mags,
                 color_continuous_scale='Viridis',
                 labels={'color':'Magnitude'},
                 projection='natural earth',
            )
        fig.show()

Мұндағы барлық маңызды өзгерістер px.scatter_geo() функция шақыруында орын алады. color аргументі Plotly-ге әр маркер ❶ түс шкаласының қай жерге түсетінін анықтау үшін қандай мәндерді пайдалану керектігін айтады. Әрбір нүктенің түсін анықтау үшін mags тізімін пайдаланамыз, дәл солай size аргументімен істегендей.

color_continuous_scale аргументі Плотлиге қай түс шкаласын қолдану керектігін айтады ❷. Viridis – қою көктен ашық сарыға дейінгі аралықтағы түс шкаласы және ол осы деректер жинағы үшін жақсы жұмыс істейді. Әдепкі бойынша, картаның оң жағындағы түс масштабы түс деп белгіленеді; бұл түстердің шын мәнінде нені білдіретінін білдірмейді. белгілер аргументі, көрсетілген Chapter 15, мән ретінде сөздікті қабылдайды ❸. Түс шкаласының түс орнына Магнитуда деп белгіленгеніне көз жеткізіп, осы диаграммада тек бір реттелетін белгіні орнатуымыз керек.

Жер сілкіністері белгіленген негізгі картаны өзгерту үшін тағы бір аргумент қосамыз. проекция аргументі бірнеше жалпы карта проекцияларын қабылдайды ❹. Мұнда картаның шеттерін дөңгелектейтін 'табиғи жер' проекциясын қолданамыз. Сондай-ақ, осы соңғы аргументтен кейінгі үтірге назар аударыңыз. Функция шақыруында осындай бірнеше Тіркесті қамтитын аргументтердің ұзын тізімі болған кезде, келесі жолға басқа аргумент қосуға әрқашан дайын болу үшін соңына үтір қосу әдеттегі тәжірибе болып табылады.

Бағдарламаны қазір іске қосқанда, әлдеқайда әдемі көрінетін картаны көресіз. 16-9-суретте түс шкаласы жеке жер сілкіністерінің ауырлығын көрсетеді; ең күшті жер сілкіністері көптеген қараңғы нүктелерден айырмашылығы ашық-сары нүктелермен ерекшеленеді. Сондай-ақ, жер сілкінісінің қай аймақтарында маңыздырақ екенін анықтауға болады.

16-9-сурет: 30 күндік жер сілкінісі кезінде әр жер сілкінісінің магнитудасын көрсету үшін түсі мен өлшемі пайдаланылады.

Басқа түс шкалалары

Басқа түс шкалаларының қатарын таңдауға болады. Қол жетімді түс шкалаларын көру үшін Python терминал сеансына келесі екі Тіркесті енгізіңіз:

>>> import plotly.express as px
        >>> px.colors.named_colorscales()
        ['aggrnyl', 'agsunset', 'blackbody', ..., 'mygbm']

Бұл түс шкалаларын жер сілкінісі картасында немесе үздіксіз өзгеріп тұратын түстер деректердегі үлгілерді көрсетуге көмектесетін кез-келген деректер жиынтығымен байқап көріңіз.

Меңзерді жылжыту мәтінін қосу

Осы картаны аяқтау үшін меңзерді жер сілкінісін білдіретін маркердің үстіне апарған кезде пайда болатын кейбір ақпараттық мәтінді қосамыз. Әдепкі бойынша пайда болатын бойлық пен ендікті көрсетумен қатар, біз шаманы көрсетіп, шамамен орналасқан жердің сипаттамасын да береміз.

Бұл өзгерісті енгізу үшін файлдан тағы біраз деректерді алу керек:

eq_world_map.py

--snip/код үзіндісі--
         mags, lons, lats, eq_titles = [], [], [], []
            mag = eq_dict['properties']['mag']
            lon = eq_dict['geometry']['coordinates'][0]
            lat = eq_dict['geometry']['coordinates'][1]
             eq_title = eq_dict['properties']['title']
            mags.append(mag)
            lons.append(lon)
            lats.append(lat)
            eq_titles.append(eq_title)
        
        title = 'Global Earthquakes'
        fig = px.scatter_geo(lat=lats, lon=lons, size=mags, title=title,
                --snip/код үзіндісі--
                projection='natural earth',
                 hover_name=eq_titles,
            )
        fig.show()

Әрбір жер сілкінісінің тақырыбын сақтау үшін алдымен eq_titles деп аталатын тізім жасаймыз. ❶. Деректердің 'title' бөлімінде бойлық пен ендікке қосымша әрбір жер сілкінісінің магнитудасы мен орнының сипаттамалық атауы бар. Біз бұл ақпаратты алып, оны айнымалыға тағайындаймыз eq_title ❷, содан кейін оны eq_titles тізіміне қосыңыз.

px.scatter_geo() шақыруында біз eq_titles мәнін hover_name аргументіне береміз. ❸. Енді Плотли әрбір жер сілкінісінің атауынан бастап әрбір нүктедегі меңзердегі мәтінге ақпаратты қосады. Бұл бағдарламаны іске қосқан кезде меңзерді кез-келген маркердің үстіне апарып, сол жер сілкінісі болған жердің сипаттамасын көріп, оның нақты магнитудасын оқи алуыңыз керек. Бұл ақпараттың мысалы көрсетілген16-10 сурет.

16-10-сурет: меңзердегі мәтін енді әрбір жер сілкінісінің қысқаша мазмұнын қамтиды.

Бұл әсерлі! 30 жолдан аз кодта біз ғаламдық жер сілкінісі белсенділігінің көрнекі және мағыналы картасын жасадық, ол сонымен қатар планетаның геологиялық құрылымын суреттейді. Plotly визуализацияларыңыздың сыртқы түрі мен әрекетін реттеуге болатын Тіркестердің кең ауқымын ұсынады. Plotly қолданбасының көптеген опцияларын пайдалана отырып, сіз өзіңіз қалаған нәрсені нақты көрсететін диаграммалар мен карталар жасай аласыз.

Қорытынды

Бұл тарауда сіз нақты деректер жиындарымен жұмыс істеуді үйрендіңіз. Сіз CSV және GeoJSON файлдарын өңдедіңіз және назар аударғыңыз келетін деректерді шығардыңыз. Тарихи ауа-райы деректерін пайдалана отырып, сіз Matplotlib бағдарламасымен жұмыс істеу, оның ішінде datetime модулін пайдалану және бір диаграммада бірнеше деректер қатарын салу әдісі туралы көбірек білдіңіз. Сіз Plotly қолданбасында дүниежүзілік картада географиялық деректерді құрастырдыңыз және карта стилін реттеуді үйрендіңіз.

Сіз CSV және JSON файлдарымен жұмыс істеу тәжірибесін жинақтай отырып, талдағыңыз келетін дерлік кез-келген деректерді өңдей аласыз. Көптеген онлайн деректер-жиынын осы пішімдердің бірінде немесе екеуінде жүктеп алуға болады. Осы пішімдермен жұмыс істеу арқылы сіз басқа деректер пішімдерімен де оңай жұмыс істеуді үйренесіз.

Келесі тарауда онлайн көздерден өз деректерін автоматты түрде жинайтын бағдарламаларды жазасыз, содан кейін сол деректердің визуализациясын жасайсыз. Егер сіз хобби ретінде бағдарламалағыңыз келсе, бұл қызықты дағдылар және кәсіби бағдарламалауға қызығушылық танытсаңыз, маңызды дағдылар.

API интерфейстерімен жұмыс істеу

ITUniver

17
API интерфейстерімен жұмыс істеу

Бұл тарауда сіз шығарып алатын деректер негізінде визуализация жасайтын дербес бағдарламаны жазу жолын үйренесіз. Сіздің бағдарламаңыз веб-сайттан нақты ақпаратты автоматты түрде сұрау үшін қолданбалы бағдарламалау интерфейсін (API) пайдаланады, содан кейін визуализацияны жасау үшін сол ақпаратты пайдаланады. Осы сияқты жазылған бағдарламалар визуализация жасау үшін әрқашан ағымдағы деректерді пайдаланатындықтан, тіпті бұл деректер жылдам өзгеретін болса да, визуализация әрқашан жаңартылған болады.

API пайдалану

API — бағдарламалармен әрекеттесу үшін жасалған веб-сайттың бөлігі. Бұл бағдарламалар белгілі бір ақпаратты сұрау үшін өте нақты URL мекенжайларын пайдаланады. Мұндай сұрау API қоңырауы деп аталады. Сұралған деректер JSON немесе CSV сияқты оңай өңделетін пішімде қайтарылады. Әлеуметтік медиа сайттарымен біріктірілген қолданбалар сияқты сыртқы деректер көздерін пайдаланатын қолданбалардың көпшілігі API қоңырауларына сүйенеді.

Git және GitHub

Біз визуализацияны GitHub ақпаратына негіздейміз (https://github.com), бағдарламашыларға кодтау жобаларында бірлесіп жұмыс істеуге мүмкіндік беретін сайт. Біз GitHub API интерфейсін сайттағы Python жобалары туралы ақпаратты сұрау үшін пайдаланамыз, содан кейін Plotly арқылы осы жобалардың салыстырмалы танымалдылығының интерактивті визуализациясын жасаймыз.

GitHub өз атауын Git, таратылған нұсқаларды басқару жүйесінен алады. Git адамдарға бір адам жасаған өзгерістердің басқа адамдар жасап жатқан өзгерістерге кедергі келтірмейтіндей етіп жобадағы жұмысын басқаруға көмектеседі. Жобада жаңа мүмкіндікті енгізген кезде, Git әр файлға енгізілген өзгерістерді қадағалайды. Жаңа кодыңыз жұмыс істегенде, сіз енгізген өзгерістерді міндеттейсіз және Git жобаңыздың жаңа күйін жазады. Қате жасасаңыз және өзгертулеріңізді қайтарғыңыз келсе, кез-келген бұрынғы жұмыс күйіне оңай оралуға болады. (Git арқылы нұсқаларды басқару туралы қосымша ақпарат алу үшін D қосымшасын қараңыз.) GitHub жобалары репозиторийлерде сақталады, оларда жобаға қатысты барлық нәрсе: оның коды, серіктестері туралы ақпарат, кез-келген мәселелер немесе қате туралы есептер, т.б..

GitHub пайдаланушыларына жоба ұнаса, олар қолдау көрсету және пайдаланғысы келетін жобаларды қадағалап отыру үшін оған «жұлдызша» қоя алады. Бұл тарауда GitHub жүйесіндегі ең көп жұлдызды Python жобалары туралы ақпаратты автоматты түрде жүктеп алу үшін бағдарлама жазамыз, содан кейін осы жобалардың ақпараттық визуализациясын жасаймыз.

API қоңырауы арқылы деректерді сұрау

GitHub API интерфейсі API қоңыраулары арқылы ақпараттың кең ауқымын сұрауға мүмкіндік береді. API қоңырауы қалай көрінетінін көру үшін браузердің мекенжай жолағына келесіні енгізіп, ENTER пернесін басыңыз:

https://api.github.com/search/repositories?q=language:python+sort:stars

Бұл қоңырау қазіргі уақытта GitHub жүйесінде орналастырылған Python жобаларының санын, сондай-ақ ең танымал Python репозиторийлері туралы ақпаратты қайтарады. Қоңырауды қарастырайық. Бірінші бөлім https://api.github.com/ сұрауды API қоңырауларына жауап беретін GitHub бөлігіне бағыттайды. Келесі бөлім, search/repositories, API-ге GitHub-тағы барлық репозиторийлер арқылы іздеу жүргізу керектігін айтады.

репозиторийлерден кейінгі сұрақ белгісі аргументті өткізгелі тұрғанымызды білдіреді. q query дегенді білдіреді және теңдік белгісі (=) сұрауды (q=) көрсетуді бастауға мүмкіндік береді. language:python пайдалану арқылы біз негізгі тіл ретінде Python бар репозиторийлер туралы ақпарат алғымыз келетінін көрсетеміз. Соңғы бөлім, +sort:stars, жобаларды берілген жұлдыздар саны бойынша сұрыптайды.

Келесі үзінді жауаптың алғашқы бірнеше жолын көрсетеді:

{
           "total_count": 8961993,
           "incomplete_results": true,
           "items": [
            {
              "id": 54346799,
              "node_id": "MDEwOlJlcG9zaXRvcnk1NDM0Njc5OQ==",
              "name": "public-apis",
              "full_name": "public-apis/public-apis",
              --snip/код үзіндісі--

Жауаптан бұл URL мекенжайын негізінен адамдар енгізуге арналмағанын көруге болады, себебі ол бағдарламамен өңделетін пішімде. GitHub осы жазу кезінде тоғыз миллионнан аз Python жобаларын тапты ❶. "incomplete_results" мәні true болып табылады, бұл GitHub сұрауды толық өңдемегенін көрсетеді ❷. GitHub барлық пайдаланушылар үшін API жауап беруін сақтау үшін әрбір сұраудың қанша уақыт орындалатынын шектейді. Бұл жағдайда ол ең танымал Python репозиторийлерінің кейбірін тапты, бірақ олардың барлығын табуға уақыты болмады; біз оны бір сәтте түзетеміз. Қайтарылған "элементтер" келесі тізімде көрсетіледі, онда GitHub-тағы ең танымал Python жобалары туралы мәліметтер бар ❸.

Сұрауларды орнату

Сұраулар бумасы Python бағдарламасына веб-сайттан ақпаратты оңай сұрауға және жауапты тексеруге мүмкіндік береді. Сұраныстарды орнату үшін pip пайдаланыңыз:

$ python -m pip install --user requests

Бағдарламаларды іске қосу немесе терминал сеансын бастау үшін python пәрменінен басқа пәрменді пайдалансаңыз, мысалы, python3, сіздің пәрменіңіз келесідей болады:

$ python3 -m pip install --user requests

API жауабын өңдеу

Енді API қоңырауын автоматты түрде шығару және нәтижелерді өңдеу үшін бағдарлама жазамыз:

python_repos.py

import requests
        
        # Make an API call and check the response.
         url = "https://api.github.com/search/repositories"
        url += "?q=language:python+sort:stars+stars:>10000"
        
         headers = {"Accept": "application/vnd.github.v3+json"}
         r = requests.get(url, headers=headers)
         print(f"Status code: {r.status_code}")
        
        # Convert the response object to a dictionary.
         response_dict = r.json()
        
        # Process results.
        print(response_dict.keys())

Алдымен сұраулар модулін импорттаймыз. Содан кейін API шақыруының URL мекенжайын url айнымалысына ❶ тағайындаймыз. Бұл ұзын URL, сондықтан біз оны екі жолға бөлеміз. Бірінші жол URL мекенжайының негізгі бөлігі, ал екінші жол сұрау жолы болып табылады. Біз бастапқы сұрау жолына тағы бір шарт қостық: stars:>10000, ол GitHub-қа тек 10 000 жұлдызы бар Python репозитарийлерін іздеуді ұсынады. Бұл GitHub-қа нәтижелердің толық, дәйекті жинағын қайтаруға мүмкіндік береді.

GitHub қазір API-нің үшінші нұсқасында, сондықтан API-нің осы нұсқасын пайдалануды нақты сұрайтын API қоңырауы үшін тақырыптарды анықтаймыз және нәтижелерді JSON пішімінде қайтарамыз❷. Содан кейін API-ге қоңырау шалу үшін сұраулар қолданамыз ❸.Біз get() шақырамыз және оған URL мекенжайын және біз анықтаған тақырыпты береміз және жауап нысанын r айнымалысына тағайындаймыз.

Жауап нысанында status_code деп аталатын атрибут бар, ол бізге сұраудың сәтті болған-болмағанын көрсетеді. (200 күй коды сәтті жауапты көрсетеді.) Қоңыраудың сәтті өткеніне көз жеткізу үшін status_code мәнін басып шығарамыз. ❹. Біз API-ден ақпаратты JSON пішімінде қайтаруды сұрадық, сондықтан ақпаратты Python сөздігіне түрлендіру үшін json() әдісін қолданамыз. ❺. Алынған сөздікті response_dict-ге тағайындаймыз.

Соңында, response_dict ішінен кілттерді басып шығарамыз және келесі нәтижені көреміз:

Status code: 200
        dict_keys(['total_count', 'incomplete_results', 'items'])

Күй коды 200 болғандықтан, сұрау сәтті болғанын білеміз. Жауап сөздігінде тек үш кілт бар: 'total_count', 'incomplete_results' және 'items'. Жауап сөздігінің ішін қарастырайық.

Жауап сөздігімен жұмыс істеу

Сөздік ретінде ұсынылған API шақыруынан алынған ақпаратпен біз онда сақталған деректермен жұмыс істей аламыз. Ақпаратты қорытындылайтын кейбір нәтижелерді шығарайық. Бұл біз күткен ақпаратты алғанымызға көз жеткізудің және бізді қызықтыратын ақпаратты тексерудің жақсы жолы:

python_repos.py

import requests
        
        # Make an API call and store the response.
        --snip/код үзіндісі--
        
        # Convert the response object to a dictionary.
        response_dict = r.json()
         print(f"Total repositories: {response_dict['total_count']}")
        print(f"Complete results: {not response_dict['incomplete_results']}")
        
        # Explore information about the repositories.
         repo_dicts = response_dict['items']
        print(f"Repositories returned: {len(repo_dicts)}")
        
        # Examine the first repository.
         repo_dict = repo_dicts[0]
         print(f"\nKeys: {len(repo_dict)}")
         for key in sorted(repo_dict.keys()):
            print(key)

Жауап сөздігін зерттеуді осы API шақыруымен қайтарылған Python репозитарийлерінің жалпы санын білдіретін 'total_count' мәнімен байланысты мәнді басып шығару арқылы бастаймыз . Біз сондай-ақ 'incomplete_results'мен байланысты мәнді пайдаланамыз, сондықтан GitHub сұрауды толығымен өңдей алғанын білеміз. Бұл мәнді тікелей басып шығарудың орнына, біз оның қарама-қарсысын басып шығарамыз: True мәні нәтижелердің толық жинағын алғанымызды көрсетеді.

'items'-мен байланысты мән - әрқайсысы жеке Python репозиторийі туралы деректерді қамтитын бірнеше сөздіктерді қамтитын тізім. Біз бұл сөздіктер тізімін repo_dicts ❷ ішіне тағайындаймыз. Содан кейін бізде қанша репозиторийге арналған ақпарат бар екенін көру үшін repo_dicts ұзындығын басып шығарамыз.

Әрбір репозиторий туралы қайтарылған ақпаратты мұқият қарау үшін біз repo_dicts ішінен бірінші элементті шығарып, оны repo_dict-ға тағайындаймыз.❸. Содан кейін бізде қанша ақпарат бар екенін көру үшін сөздіктегі пернелердің санын басып шығарамыз ❹. Соңында, қандай ақпарат бар екенін көру үшін сөздіктің барлық кілттерін басып шығарамыз ❺.

Нәтижелер бізге нақты деректердің нақты бейнесін береді:

Status code: 200
         Total repositories: 248
         Complete results: True
        Repositories returned: 30
        
         Keys: 78
        allow_forking
        archive_url
        archived
        --snip/код үзіндісі--
        url
        visiblity
        watchers
        watchers_count

Осы жазу кезінде 10 000-нан астам жұлдыздары бар тек 248 Python репозиторийлері бар.❶. GitHub API қоңырауын толығымен өңдей алғанын көреміз ❷. Бұл жауапта GitHub сұрауымыздың шарттарына сәйкес келетін бірінші 30 репозиторийлері туралы ақпаратты қайтарды. Көбірек репозиторийлер қажет болса, деректердің қосымша беттерін сұрай аламыз.

GitHub API интерфейсі әрбір репозиторий туралы көптеген ақпаратты қайтарады: repo_dict ішінде 78 кілттері бар. ❸.Осы кілттерді қарап шыққанда, сіз жоба туралы қандай ақпарат алуға болатынын түсінесіз. (API арқылы қандай ақпарат қолжетімді екенін білудің жалғыз жолы - құжаттаманы оқу немесе ақпаратты код арқылы тексеру, біз осы жерде істеп жатырмыз.)

Келіңіз, repo_dict ішіндегі кейбір кілттердің мәндерін шығарып көрейік:

python_repos.py

--snip/код үзіндісі--
        # Examine the first repository.
        repo_dict = repo_dicts[0]
        
        print("\nSelected information about first repository:")
         print(f"Name: {repo_dict['name']}")
         print(f"Owner: {repo_dict['owner']['login']}")
         print(f"Stars: {repo_dict['stargazers_count']}")
        print(f"Repository: {repo_dict['html_url']}")
         print(f"Created: {repo_dict['created_at']}")
         print(f"Updated: {repo_dict['updated_at']}")
        print(f"Description: {repo_dict['description']}")

Мұнда біз бірінші репозиторий сөздігіндегі бірнеше кілттердің мәндерін басып шығарамыз. Біз жобаның атауынан бастаймыз ❶. Бүкіл сөздік жобаның иесін білдіреді, сондықтан біз иесін білдіретін сөздікке кіру үшін owner пернесін пайдаланамыз, содан кейін иесінің логин атын алу үшін login пернесін пайдаланамыз. ❷. Әрі қарай, жоба қанша жұлдыз жинағанын басып шығарамыз❸ және жобаның GitHub репозиторийінің URL мекенжайы. Содан кейін оның қашан құрылғанын көрсетеміз ❹ және ол соңғы рет қашан жаңартылды ❺. Соңында біз репозиторийдің сипаттамасын басып шығарамыз.

Шығыс келесідей болуы керек:

Status code: 200
        Total repositories: 248
        Complete results: True
        Repositories returned: 30
        
        Selected information about first repository:
        Name: public-apis
        Owner: public-apis
        Stars: 191493
        Repository: https://github.com/public-apis/public-apis
        Created: 2016-03-20T23:49:42Z
        Updated: 2022-05-12T06:37:11Z
        Description: A collective list of free APIs

Осы жазу кезінде GitHub-тағы ең көп жұлдызды Python жобасы public-apis екенін көреміз. Оның иесі - аттас ұйым және оған 200 000-ға жуық GitHub пайдаланушысы жұлдызды. Біз жоба репозиторийінің URL мекенжайын, оның 2016 жылдың наурызында жасалған күнін және жақында жаңартылғанын көре аламыз. Сонымен қатар, сипаттамада public-apis құрамында бағдарламашыларды қызықтыруы мүмкін тегін API тізімі бар екені айтылады.

Үздік репозиторийлерді қорытындылау

Осы деректер үшін визуализация жасағанда, біз бірнеше репозиторийлерді қосқымыз келеді. API шақыруы қайтаратын әрбір репозиторий туралы таңдалған ақпаратты басып шығару үшін цикл жазайық, осылайша олардың барлығын визуализацияға қоса аламыз:

python_repos.py

--snip/код үзіндісі--
        # Explore information about the repositories.
        repo_dicts = response_dict['items']
        print(f"Repositories returned: {len(repo_dicts)}")
        
         print("\nSelected information about each repository:")
         for repo_dict in repo_dicts:
            print(f"\nName: {repo_dict['name']}")
            print(f"Owner: {repo_dict['owner']['login']}")
            print(f"Stars: {repo_dict['stargazers_count']}")
            print(f"Repository: {repo_dict['html_url']}")
            print(f"Description: {repo_dict['description']}")

Алдымен ❶ кіріспе хабарын басып шығарамыз. Содан кейін repo_dicts ❷ ішіндегі барлық сөздіктерді айналдырамыз. Цикл ішінде біз әрбір жобаның атын, оның иесін, оның қанша жұлдызы барын, GitHub сайтындағы URL мекенжайын және жобаның сипаттамасын басып шығарамыз:

Status code: 200
        Total repositories: 248
        Complete results: True
        Repositories returned: 30
        
        Selected information about each repository:
        
        Name: public-apis
        Owner: public-apis
        Stars: 191494
        Repository: https://github.com/public-apis/public-apis
        Description: A collective list of free APIs
        
        Name: system-design-primer
        Owner: donnemartin
        Stars: 179952
        Repository: https://github.com/donnemartin/system-design-primer
        Description: Learn how to design large-scale systems. Prep for the system
          design interview.  Includes Anki flashcards.
        --snip/код үзіндісі--
        
        Name: PayloadsAllTheThings
        Owner: swisskyrepo
        Stars: 37227
        Repository: https://github.com/swisskyrepo/PayloadsAllTheThings
        Description: A list of useful payloads and bypass for Web Application Security
          and Pentest/CTF

Бұл нәтижелерде кейбір қызықты жобалар пайда болады және олардың кейбірін қарастырған жөн. Бірақ мұнда тым көп уақыт жұмсамаңыз, өйткені біз нәтижелерді оқуды жеңілдететін визуализация жасағалы жатырмыз.

API жылдамдығы шектеулерін бақылау

Көптеген API интерфейстерінде тариф шектеулері бар, яғни белгілі бір уақыт ішінде қанша сұрау жасауға болатынына шектеу бар. GitHub шектеулеріне жақындағаныңызды көру үшін https://api.github.com/rate_limit веб-шолғышқа. Сіз келесідей басталатын жауапты көруіңіз керек:

{
          "resources": {
            --snip/код үзіндісі--
             "search": {
               "limit": 10,
               "remaining": 9,
               "reset": 1652338832,
              "used": 1,
              "resource": "search"
            },
            --snip/код үзіндісі--

Бізді қызықтыратын ақпарат - іздеу API үшін жылдамдық шегі ❶. Шектеу минутына 10 сұраныс екенін көреміз ❷ және бізде ағымдағы минутқа 9 сұрау қалды ❸. "reset" кілтімен байланысты мән Unix немесе epoch time (1970 жылдың 1 қаңтарындағы түн ортасынан бергі секундтар саны) уақытын білдіреді ) біздің квота қашан қалпына келтіріледі ❹. Квотаңызға жетсеңіз, API шегіне жеткеніңізді білуге мүмкіндік беретін қысқа жауап аласыз. Егер шектеуге жетсеңіз, квота қалпына келтірілгенше күтіңіз.

Plotly көмегімен репозиторийлерді визуализациялау

GitHub-тағы Python жобаларының салыстырмалы танымалдылығын көрсету үшін жиналған деректерді пайдаланып визуализация жасайық. Интерактивті жолақ диаграммасын жасаймыз: әр жолақтың биіктігі жоба алған жұлдыздар санын көрсетеді және GitHub сайтындағы жобаның үйіне өту үшін жолақ белгісін баса аласыз.

Біз жұмыс істеп жатқан бағдарламаның көшірмесін python_repos_visual.py ретінде сақтаңыз, содан кейін оны келесідей оқылатындай етіп өзгертіңіз:

python_repos_visual.py

import requests
        import plotly.express as px
        
        # Make an API call and check the response.
        url = "https://api.github.com/search/repositories"
        url += "?q=language:python+sort:stars+stars:>10000"
        
        headers = {"Accept": "application/vnd.github.v3+json"}
        r = requests.get(url, headers=headers)
         print(f"Status code: {r.status_code}")
        
        # Process overall results.
        response_dict = r.json()
         print(f"Complete results: {not response_dict['incomplete_results']}")
        
        # Process repository information.
        repo_dicts = response_dict['items']
         repo_names, stars = [], []
        for repo_dict in repo_dicts:
            repo_names.append(repo_dict['name'])
            stars.append(repo_dict['stargazers_count'])
        
        # Make visualization.
         fig = px.bar(x=repo_names, y=stars)
        fig.show()

Біз Plotly Express импорттаймыз, содан кейін біз жасағандай API қоңырауын жасаймыз. ❶ ақауының бар-жоғын білу үшін API қоңырауына жауап күйін басып шығаруды жалғастырамыз. Жалпы нәтижелерді өңдеген кезде біз нәтижелердің толық жинағын алғанымызды растайтын хабарды басып шығаруды жалғастырамыз ❷. Қалған print() шақыруларын алып тастаймыз, себебі біз енді зерттеу кезеңінде емеспіз; бізде қажетті деректер бар екенін білеміз.

Содан кейін бастапқы диаграммаға қосатын деректерді сақтау үшін ❸ екі бос тізім жасаймыз. Жолақтарды (repo_names) белгілеу үшін бізге әр жобаның атауы және жолақтардың биіктігін анықтау үшін (жұлдыздар) жұлдыздар саны қажет болады. Циклда біз әрбір жобаның атын және ондағы жұлдыздар санын осы тізімдерге қосамыз.

Біз бастапқы визуализацияны тек екі жол кодымен жасаймыз ❹. Бұл Plotly Express философиясына сәйкес келеді, оның сыртқы түрін нақтылаудан бұрын визуализацияңызды мүмкіндігінше тезірек көре аласыз. Мұнда жолақты диаграмма құру үшін px.bar() функциясын қолданамыз. Біз repo_names тізімін x аргументі ретінде және жұлдызша -ды y аргументі ретінде береміз.

17-1-сурет нәтиже диаграммасын көрсетеді. Алғашқы бірнеше жобалар қалғандарына қарағанда әлдеқайда танымал екенін көреміз, бірақ олардың барлығы Python экожүйесіндегі маңызды жобалар.

17-1-сурет: GitHub-тағы ең көп жұлдызды Python жобалары

Диаграмманы сәндеу

Сызбада ақпараттың дұрыс екенін білгеннен кейін, Plotly сызбаларды стильдеу және теңшеудің бірқатар жолдарын қолдайды. Біз бастапқы px.bar() қоңырауына кейбір өзгерістер енгіземіз, содан кейін ол жасалғаннан кейін fig нысанына қосымша түзетулер енгіземіз.

Әр ось үшін тақырып пен белгілерді қосу арқылы диаграмманы сәндеуді бастаймыз:

python_repos_visual.py

--snip/код үзіндісі--
        # Make visualization.
        title = "Most-Starred Python Projects on GitHub"
        labels = {'x': 'Repository', 'y': 'Stars'}
        fig = px.bar(x=repo_names, y=stars, title=title, labels=labels)
        
         fig.update_layout(title_font_size=28, xaxis_title_font_size=20,
                yaxis_title_font_size=20)
        
        fig.show()

Алдымен 15 және 16 тараулардағыдай әрбір ось үшін тақырып пен белгілерді қосамыз. Содан кейін диаграмманың нақты элементтерін өзгерту үшін fig.update_layout() әдісін қолданамыз. ❶. Plotly диаграмма элементінің аспектілері астын сызу арқылы қосылған шартты пайдаланады. Plotly құжаттамасымен танысқан сайын, диаграмманың әртүрлі элементтері қалай аталатыны және өзгертілгені туралы дәйекті үлгілерді көре бастайсыз. Мұнда тақырып қаріпінің өлшемін 28, ал әрбір ось тақырыбы үшін қаріп өлшемін 20 етіп орнатамыз. Нәтиже 17-2-суретте көрсетілген.

17-2-сурет: Негізгі диаграммаға және әрбір оське тақырып қосылды.

Арнаулы құралдар кеңестерін қосу

Plotly бағдарламасында жолақ көрсететін ақпаратты көрсету үшін курсорды жеке жолақтың үстіне апаруға болады. Бұл әдетте құралдар кеңесідеп аталады және бұл жағдайда ол қазіргі уақытта жобадағы жұлдыздар санын көрсетеді. Әр жобаның сипаттамасын, сондай-ақ жоба иесін көрсету үшін реттелетін құралдар кеңесін жасайық.

Кеңестерді жасау үшін бізге қосымша деректерді алу керек:

python_repos_visual.py

--snip/код үзіндісі--
        # Process repository information.
        repo_dicts = response_dict['items']
         repo_names, stars, hover_texts = [], [], []
        for repo_dict in repo_dicts:
            repo_names.append(repo_dict['name'])
            stars.append(repo_dict['stargazers_count'])
        
            # Build hover texts.
             owner = repo_dict['owner']['login']
            description = repo_dict['description']
             hover_text = f"{owner}<br />{description}"
            hover_texts.append(hover_text)
        
        # Make visualization.
        title = "Most-Starred Python Projects on GitHub"
        labels = {'x': 'Repository', 'y': 'Stars'}
         fig = px.bar(x=repo_names, y=stars, title=title, labels=labels,
                hover_name=hover_texts)
        
        fig.update_layout(title_font_size=28, xaxis_title_font_size=20,
                yaxis_title_font_size=20)
        
        fig.show()

Әрбір жоба үшін көрсеткіміз келетін мәтінді сақтау үшін алдымен жаңа бос тізімді анықтаймыз, hover_texts ❶. Деректерді өңдейтін циклде біз әрбір жобаның иесі мен сипаттамасын тартамыз ❷. Plotly мәтіндік элементтер ішінде HTML кодын пайдалануға мүмкіндік береді, сондықтан жоба иесінің пайдаланушы аты мен сипаттама арасында жол үзілімі (<br />) бар белгі үшін Тіркесті жасаймыз. ❸. Содан кейін бұл белгіні hover_texts тізіміне қосамыз.

px.bar() шақыруында hover_name аргументін қосамыз және оны hover_texts жібереміз. ❹. Бұл жаһандық жер сілкінісі әрекетінің картасындағы әрбір нүктенің белгісін теңшеу үшін қолданған тәсіл. Plotly әрбір жолақты жасағанда, ол осы тізімнен белгілерді алып тастайды және оларды көруші меңзерді жолақтың үстіне апарған кезде ғана көрсетеді. 17-3-сурет осы реттелетін құралдар кеңестерінің бірін көрсетеді.

17-3-сурет: меңзерді жолақтың үстіне апару жобаның иесі мен сипаттамасын көрсетеді.

Басуға болатын сілтемелерді қосу

Plotly мәтіндік элементтерде HTML пайдалануға мүмкіндік беретіндіктен, біз диаграммаға сілтемелерді оңай қоса аламыз. Көрерменге GitHub-тағы кез-келген жобаның басты бетіне кіруге мүмкіндік беру тәсілі ретінде x-осьтік белгілерді қолданайық. URL мекенжайларын деректерден алып, оларды x осі белгілерін жасау кезінде пайдалану керек:

python_repos_visual.py

--snip/код үзіндісі--
        # Process repository information.
        repo_dicts = response_dict['items']
         repo_links, stars, hover_texts = [], [], []
        for repo_dict in repo_dicts:
            # Turn repo names into active links.
            repo_name = repo_dict['name']
             repo_url = repo_dict['html_url']
             repo_link = f"<a href='{repo_url}'>{repo_name}</a>"
            repo_links.append(repo_link)
        
            stars.append(repo_dict['stargazers_count'])
            --snip/код үзіндісі--
        
        # Make visualization.
        title = "Most-Starred Python Projects on GitHub"
        labels = {'x': 'Repository', 'y': 'Stars'}
        fig = px.bar(x=repo_links, y=stars, title=title, labels=labels,
                hover_name=hover_texts)
        
        fig.update_layout(title_font_size=28, xaxis_title_font_size=20,
                yaxis_title_font_size=20)
        
        fig.show()

Диаграмма үшін жинайтын ақпарат түрін дәлірек жеткізу үшін біз жасап жатқан тізімнің атауын repo_names-дан repo_links-ға жаңартамыз. ❶. Содан кейін жобаның URL мекенжайын repo_dict ішінен алып, оны repo_url уақытша айнымалысына тағайындаймыз.❷. Әрі қарай, біз жобаға сілтеме жасаймыз ❸. Сілтемені жасау үшін <a href='URL'>link text</a> пішімі бар HTML анкерлік тегін қолданамыз. Содан кейін бұл сілтемені repo_links-ға қосамыз.

Біз px.bar() деп атаған кезде, диаграммадағы xмәндері үшін repo_links пайдаланамыз. Нәтиже бұрынғыдай көрінеді, бірақ енді көрермен GitHub-тағы жобаның басты бетіне кіру үшін диаграмманың төменгі жағындағы кез-келген жоба атауын баса алады. Енді бізде API арқылы алынған деректердің интерактивті, ақпараттық визуализациясы бар!

Маркер түстерін теңшеу

Диаграмма жасалғаннан кейін диаграмманың кез-келген дерлік аспектісін жаңарту әдісі арқылы теңшеуге болады. Біз бұрын update_layout() әдісін қолдандық. Басқа әдіс, update_traces(), диаграммада көрсетілген деректерді теңшеу үшін пайдаланылуы мүмкін.

Келіңіз, жолақтарды сәл мөлдір етіп қою көк түске өзгертейік:

--snip/код үзіндісі--
        fig.update_layout(title_font_size=28, xaxis_title_font_size=20,
                yaxis_title_font_size=20)
        
        fig.update_traces(marker_color='SteelBlue', marker_opacity=0.6)
        
        fig.show()

Плотлиде із диаграммадағы деректер-жиынын білдіреді. update_traces() әдісі әртүрлі аргументтердің санын қабылдауы мүмкін; marker_ деп басталатын кез-келген аргумент диаграммадағы маркерлерге әсер етеді. Мұнда біз әрбір маркердің түсін 'SteelBlue' етіп орнатамыз; кез-келген аталған CSS түсі осында жұмыс істейді. Сондай-ақ әрбір маркердің мөлдірлігін 0,6 мәніне орнаттық. 1,0 мөлдірлік толығымен мөлдір емес, ал 0 мөлдірлік мүлдем көрінбейтін болады.

Plotly және GitHub API туралы толығырақ

Плотлидің құжаттамасы кең және жақсы ұйымдастырылған; дегенмен, оқуды неден бастау керектігін білу қиын болуы мүмкін. https://plotly.com/ сайтындағы "Plotly Express in Python" мақаласынан бастау үшін жақсы орын. python/plotly-express. Бұл Plotly Express көмегімен жасауға болатын барлық сызбаларға шолу және әрбір жеке диаграмма түрі туралы ұзағырақ мақалаларға сілтемелерді таба аласыз.

Егер Plotly диаграммаларын қалай жақсырақ теңшеу керектігін түсінгіңіз келсе, «Python-да Plotly Express фигураларын сәндеу» мақаласы 15-тарауда көргендеріңізді кеңейтеді. 17. Бұл мақаланы https://plotly.com/python/styling-plotly-express сайтынан таба аласыз. a>.

GitHub API туралы қосымша ақпарат алу үшін https://docs.github.com/ сайтындағы оның құжаттамасын қараңыз. kk/ демалу. Мұнда сіз GitHub-тен алуан түрлі ақпаратты алуды үйренесіз. Осы жобада көргендеріңізді кеңейту үшін бүйірлік тақтадағы сілтеменің Іздеу бөлімін іздеңіз. GitHub тіркелгіңіз болса, өзіңіздің деректеріңізбен, сондай-ақ басқа пайдаланушылардың репозитарийлеріндегі жалпыға қолжетімді деректермен жұмыс істей аласыз.

Hacker News API

Басқа сайттарда API қоңырауларын пайдалану жолын зерттеу үшін Hacker News (https) жылдам қарап көрейік. ://news.ycombinator.com). Hacker News сайтында адамдар бағдарламалау және технология туралы мақалалармен бөліседі және сол мақалалар туралы қызу пікірталастарға қатысады. Hacker News API сайттағы барлық жіберулер мен түсініктемелер туралы деректерге қол жеткізуді қамтамасыз етеді және API интерфейсін кілтті тіркеусіз пайдалана аласыз.

Келесі қоңырау осы жазбадағы ағымдағы басты мақала туралы ақпаратты қайтарады:

https://hacker-news.firebaseio.com/v0/item/31353677.json

Осы URL мекенжайын шолғышқа енгізген кезде беттегі мәтін жақшалармен қоршалғанын, яғни сөздік екенін көресіз. Бірақ жауапты жақсырақ пішімдеусіз тексеру қиын. Осы URL мекенжайын 16-тараудағы жер сілкінісі жобасындағыдай json.dumps() әдісі арқылы іске қосайық. мақала туралы қайтарылатын ақпарат түрін зерттей аламыз:

hn_article.py

import requests
        import json
        
        # Make an API call, and store the response.
        url = "https://hacker-news.firebaseio.com/v0/item/31353677.json"
        r = requests.get(url)
        print(f"Status code: {r.status_code}")
        
        # Explore the structure of the data.
        response_dict = r.json()
        response_string = json.dumps(response_dict, indent=4)
         print(response_string)

Бұл бағдарламадағы барлығы таныс болып көрінуі керек, өйткені біз мұның барлығын алдыңғы екі тарауда қолдандық. Мұндағы басты айырмашылық мынада, біз оны файлға жазудың орнына ❶ пішімделген жауап жолын басып шығара аламыз, себебі шығыс өте ұзақ емес.

Шығарылым 31353677 идентификаторы бар мақала туралы ақпарат сөздігі:

{
            "by": "sohkamyung",
             "descendants": 302,
            "id": 31353677,
             "kids": [
                31354987,
                31354235,
                --snip/код үзіндісі--
            ],
            "score": 785,
            "time": 1652361401,
             "title": "Astronomers reveal first image of the black hole
                at the heart of our galaxy",
            "type": "story",
             "url": "https://public.nrao.edu/news/.../"
        }

Сөздікте біз жұмыс істей алатын бірнеше кілттер бар. "ұрпақтары" кілті мақалаға алынған түсініктемелердің санын көрсетеді. ❶. "балалар" кілті осы жіберуге тікелей жауап ретінде жасалған барлық түсініктемелердің идентификаторларын береді. ❷. Бұл түсініктемелердің әрқайсысының өз түсініктемелері болуы мүмкін, сондықтан жіберілімдегі ұрпақтар саны әдетте балалар санынан көп болады. Талқыланып жатқан мақаланың тақырыбын көре аламыз ❸ және талқыланатын мақаланың URL мекенжайы ❹.

Келесі URL Hacker News сайтындағы ағымдағы басты мақалалардың барлық идентификаторларының қарапайым тізімін береді:

https://hacker-news.firebaseio.com/v0/topstories.json

Біз бұл қоңырауды дәл қазір басты бетте қай мақалалар бар екенін білу үшін пайдалана аламыз, содан кейін біз жаңа ғана қарастырғанға ұқсас API қоңырауларының сериясын жасай аламыз. Осы тәсілмен біз Hacker News бірінші бетіндегі барлық мақалалардың қысқаша мазмұнын қазіргі уақытта басып шығара аламыз:

hn_submissions.py

from operator import itemgetter
        
        import requests
        
        # Make an API call and check the response.
         url = "https://hacker-news.firebaseio.com/v0/topstories.json"
        r = requests.get(url)
        print(f"Status code: {r.status_code}")
        
        # Process information about each submission.
         submission_ids = r.json()
         submission_dicts = []
        for submission_id in submission_ids[:5]:
            # Make a new API call for each submission.
             url = f"https://hacker-news.firebaseio.com/v0/item/{submission_id}.json"
            r = requests.get(url)
            print(f"id: {submission_id}\tstatus: {r.status_code}")
            response_dict = r.json()
        
            # Build a dictionary for each article.
             submission_dict = {
                'title': response_dict['title'],
                'hn_link': f"https://news.ycombinator.com/item?id={submission_id}",
                'comments': response_dict['descendants'],
            }
             submission_dicts.append(submission_dict)
        
         submission_dicts = sorted(submission_dicts, key=itemgetter('comments'),
                                    reverse=True)
        
         for submission_dict in submission_dicts:
            print(f"\nTitle: {submission_dict['title']}")
            print(f"Discussion link: {submission_dict['hn_link']}")
            print(f"Comments: {submission_dict['comments']}")

Біріншіден, біз API қоңырауын жасаймыз және жауаптың күйін басып шығарамыз❶. Бұл API қоңырауы қоңырау шыққан кездегі Hacker News туралы ең танымал 500 мақаланың идентификаторларын қамтитын тізімді қайтарады. Содан кейін жауап нысанын Python тізіміне түрлендіреміз ❷, оны біз submission_ids тағайындаймыз. Біз бұл идентификаторларды сөздіктер жинағын құру үшін пайдаланамыз, олардың әрқайсысында ағымдағы жіберілімдердің бірі туралы ақпарат бар.

Бұл сөздіктерді сақтау үшін submission_dicts деп аталатын бос тізімді орнаттық. ❸. Содан кейін біз ең жақсы 30 жіберудің идентификаторларын айналдырамыз. submission_id ағымдағы мәнін қамтитын URL мекенжайын жасау арқылы әрбір жіберу үшін жаңа API шақыруын жасаймыз.❹. Біз әрбір сұраудың күйін оның идентификаторымен бірге басып шығарамыз, осылайша оның сәтті болғанын көре аламыз.

Кейін, қазір өңделіп жатқан жіберу үшін ❺ сөздігін жасаймыз. Біз жіберу тақырыбын, сол элементтің талқылау бетіне сілтемесін және мақалаға осы уақытқа дейін алынған түсініктемелер санын сақтаймыз. Содан кейін әрбір submission_dict файлын submission_dicts ❻ тізіміне қосамыз.

Hacker News сайтындағы әрбір жіберілім бірнеше факторларға, соның ішінде оған қанша рет дауыс берілгеніне, қанша түсініктеме алынғанына және қаншалықты жақында жіберілгеніне негізделген жалпы ұпайға сәйкес бағаланады. Біз сөздіктер тізімін түсініктемелер саны бойынша сұрыптағымыз келеді. Бұл әрекетті орындау үшін біз оператор-дан келетін itemgetter() ❼ деп аталатын функцияны қолданамыз. код модуль. Біз бұл функцияға 'comments' пернесін береміз және ол тізімдегі әрбір сөздіктен сол кілтпен байланысты мәнді шығарады. Содан кейін sorted() функциясы осы мәнді тізімді сұрыптау үшін негіз ретінде пайдаланады. Біз тізімді кері ретпен сұрыптаймыз, алдымен ең көп түсініктеме жазылған оқиғаларды орналастырамыз.

Тізім сұрыпталғаннан кейін, біз тізімді ❽ қарап шығамыз және ең жақсы жіберілген әрбір жіберілім туралы ақпараттың үш бөлігін басып шығарамыз: тақырып , талқылау бетіне сілтеме және қазір жіберуде бар түсініктемелер саны:

Status code: 200
        id: 31390506    status: 200
        id: 31389893    status: 200
        id: 31390742    status: 200
        --snip/код үзіндісі--
        
        Title: Fly.io: The reclaimer of Heroku's magic
        Discussion link: https://news.ycombinator.com/item?id=31390506
        Comments: 134
        
        Title: The weird Hewlett Packard FreeDOS option
        Discussion link: https://news.ycombinator.com/item?id=31389893
        Comments: 64
        
        Title: Modern JavaScript Tutorial
        Discussion link: https://news.ycombinator.com/item?id=31390742
        Comments: 20
        --snip/код үзіндісі--

Сіз кез-келген API көмегімен ақпаратқа қол жеткізу және талдау үшін ұқсас процесті қолданасыз. Бұл деректердің көмегімен сіз ең белсенді соңғы талқылауларға қандай жіберулер шабыттандырғанын көрсететін визуализация жасай аласыз. Бұл сондай-ақ Hacker News сияқты сайттар үшін теңшелген оқу тәжірибесін қамтамасыз ететін қолданбалардың негізі болып табылады. Hacker News API арқылы қандай ақпаратқа қол жеткізуге болатынын білу үшін https://github мекенжайындағы құжаттама бетіне кіріңіз. .com/HackerNews/API.

Қорытынды

Бұл тарауда сіз API интерфейстерін өздеріне қажетті деректерді автоматты түрде жинайтын және визуализация жасау үшін пайдаланатын дербес бағдарламаларды жазу үшін қалай пайдалану керектігін үйрендіңіз. GitHub-тағы ең көп жұлдызды Python жобаларын зерттеу үшін GitHub API пайдаландыңыз, сонымен қатар Hacker News API интерфейсін қысқаша қарап шықтыңыз. API қоңырауын автоматты түрде шығару үшін Сұраулар бумасын пайдалануды және сол қоңыраудың нәтижелерін өңдеуді үйрендіңіз. Біз сондай-ақ сіз жасайтын диаграммалардың көрінісін одан әрі теңшейтін кейбір Plotly параметрлерін енгіздік.

Келесі тарауда соңғы жоба ретінде веб-қосымшаны құру үшін Django-ны пайдаланасыз.

Джангомен жұмысты бастау

ITUniver

18
Джангомен жұмысты бастау

Интернет дамыған сайын веб-сайттар мен мобильді қолданбалар арасындағы сызық бұлыңғыр болды. Веб-сайттар мен қолданбалардың екеуі де пайдаланушыларға деректермен әртүрлі Тіркестермен әрекеттесуге көмектеседі. Бақытымызға орай, сіз динамикалық веб-сайтқа, сондай-ақ мобильді қолданбалар жиынтығына қызмет көрсететін жалғыз жобаны құру үшін Django-ны пайдалана аласыз. Django - бұл Python-ның ең танымал веб-құрылымы, интерактивті веб-қосымшаларды құруға арналған құралдар жиынтығы. Бұл тарауда сіз әртүрлі тақырыптар бойынша білген ақпаратты бақылауға мүмкіндік беретін онлайн журнал жүйесі болып табылатын Learning Log деп аталатын жобаны құру үшін Django-ны қалай пайдалану керектігін үйренесіз.

Осы жобаның спецификациясын жазамыз, содан кейін қолданба жұмыс істейтін деректердің үлгілерін анықтаймыз. Біз кейбір бастапқы деректерді енгізу үшін Django әкімші жүйесін пайдаланамыз, содан кейін Джанго сайт беттерін құра алатындай көріністер мен үлгілерді жазамыз.

Django бет сұрауларына жауап бере алады және дерекқорды оқуды және жазуды, пайдаланушыларды басқаруды және т.б. жеңілдетеді. 19-тараулар және 20 бөлімдерінде Оқу журналы жобасын нақтылайсыз, содан кейін сіз (және әлемдегі барлық адамдар) оны пайдалана алатындай етіп оны тірі серверге орналастырыңыз.

Жобаны орнату

Веб қолданбасы сияқты маңызды нәрседе жұмысты бастағанда, алдымен жобаның мақсаттарын спецификацияда немесе спецификацияда сипаттау керек. Нақты мақсаттар жиынтығын алғаннан кейін, сол мақсаттарға жету үшін басқарылатын тапсырмаларды анықтауға кірісуге болады.

Бұл бөлімде біз Learning Log үшін спецификацияны жазып, жобаның бірінші кезеңінде жұмыс істей бастаймыз. Бұл виртуалды ортаны орнатуды және Django жобасының бастапқы аспектілерін құруды қамтиды.

Спектакль жазу

Толық сипаттама жобаның мақсаттарын егжей-тегжейлі сипаттайды, жобаның функционалдығын сипаттайды және оның сыртқы түрі мен пайдаланушы интерфейсін талқылайды. кез-келген жақсы жоба немесе бизнес-жоспар сияқты, спецификация сіздің назарыңызды шоғырландыруы және жобаңызды жолда ұстауға көмектесуі керек. Біз бұл жерде жобаның толық сипаттамасын жазбаймыз, бірақ әзірлеу процесін назарда ұстау үшін бірнеше нақты мақсаттарды белгілейміз. Міне, біз қолданатын спецификация:

Біз қолданушыларға өздерін қызықтыратын тақырыптарды тіркеуге және әрбір тақырып туралы білген сайын журнал жазбаларын жасауға мүмкіндік беретін Learning Log деп аталатын веб-бағдарламаны жазамыз. Оқу журналының басты беті сайтты сипаттайды және пайдаланушыларды тіркелуге немесе жүйеге кіруге шақырады. Жүйеге кіргеннен кейін пайдаланушы жаңа тақырыптар жасай алады, жаңа жазбаларды қоса алады және бар жазбаларды оқи және өңдей алады.

Жаңа тақырыпты зерттеп жатқанда, үйренгендеріңіздің журналын жүргізу жаңа ақпарат пен бұрыннан тапқан ақпаратты қадағалауға көмектеседі. Бұл әсіресе техникалық пәндерді оқығанда дұрыс. Біз жасайтын қолданба сияқты жақсы қолданба бұл процесті тиімдірек етуге көмектеседі.

Виртуалды орта жасау

Джангомен жұмыс істеу үшін алдымен виртуалды ортаны орнатамыз. Виртуалды орта бұл жүйеде бумаларды орнатуға және оларды барлық басқа Python бумаларынан оқшаулауға болатын орын. Бір жобаның кітапханасын басқа жобалардан бөлу тиімді және 20-тарауда серверге Оқу журналын қолданғанда қажет болады.

Жобаңыз үшін learning_log деп аталатын жаңа каталог жасаңыз, терминалда сол каталогқа ауысыңыз және виртуалды орта жасау үшін келесі кодты енгізіңіз:

learning_log$ python -m venv ll_env
        learning_log$

Осы жерде біз venv виртуалды орта модулін іске қосып, оны ll_env деп аталатын ортаны жасау үшін пайдаланамыз (бұл атау екі кіші әріптен басталатынын ескеріңіз L екі емес). Бағдарламаларды іске қосқанда немесе бумаларды орнатқанда python3 сияқты пәрменді пайдалансаңыз, сол пәрменді осы жерде қолданғаныңызға көз жеткізіңіз.

Виртуалды ортаны белсендіру

Енді келесі пәрменді пайдаланып виртуалды ортаны белсендіруіміз керек:

learning_log$ source ll_env/bin/activate
        (ll_env)learning_log$

Бұл пәрмен ll_env/bin/ ішінде activate сценарийін іске қосады. Орта белсенді болғанда, жақша ішінде ортаның атауын көресіз. Бұл ортаға жаңа бумаларды орнатуға және бұрыннан орнатылған бумаларды пайдалануға болатындығын көрсетеді. ll_env ішінде орнатқан бумалар орта белсенді емес кезде қолжетімді болмайды.

Виртуалды ортаны пайдалануды тоқтату үшін deactivate енгізіңіз:

(ll_env)learning_log$ deactivate
        learning_log$

Орта жұмыс істеп тұрған терминалды жапқанда да белсенді емес болады.

Django орнату

Виртуалды орта белсендірілген кезде pip жаңарту және Django орнату үшін келесіні енгізіңіз:

(ll_env)learning_log$ pip install --upgrade pip
        (ll_env)learning_log$ pip install django
        Collecting django
        --snip/код үзіндісі--
        Installing collected packages: sqlparse, asgiref, django
        Successfully installed asgiref-3.5.2 django-4.1 sqlparse-0.4.2
        (ll_env)learning_log$

Ол ресурстарды әртүрлі көздерден жүктеп алатындықтан, pip жиі жаңартылады. Жаңа виртуалды орта жасаған сайын пипті жаңартқан дұрыс.

Біз қазір виртуалды ортада жұмыс істеп жатырмыз, сондықтан Django орнату пәрмені барлық жүйелерде бірдей. python -m pip install package_name сияқты ұзағырақ пәрмендерді пайдаланудың немесе --user жалауын қосудың қажеті жоқ. Django тек ll_env ортасы белсенді болғанда ғана қолжетімді болатынын есте сақтаңыз.

Джангода жоба жасау

Белсенді виртуалды ортадан шықпай (терминал шақыруында жақша ішінде ll_env іздеуді ұмытпаңыз), жаңа жоба жасау үшін келесі пәрмендерді енгізіңіз:

 (ll_env)learning_log$ django-admin startproject ll_project .
         (ll_env)learning_log$ ls
        ll_env ll_project manage.py
         (ll_env)learning_log$ ls ll_project
        __init__.py asgi.py settings.py urls.py wsgi.py

startproject пәрмені ❶ Джангоға ll_project деп аталатын жаңа жобаны орнатуды ұсынады. . Пәрменнің соңындағы нүкте (.) біз оны әзірлеуді аяқтаған кезде қолданбаны серверге орналастыруды жеңілдететін каталог құрылымы бар жаңа жобаны жасайды.

ls пәрменін (Windows жүйесінде dir) іске қосу ❷ Джангода бар екенін көрсетеді. ll_project деп аталатын жаңа каталог жасады. Ол сонымен қатар командаларды қабылдайтын және оларды Django бағдарламасының сәйкес бөлігіне беретін қысқа бағдарлама болып табылатын manage.py файлын жасады. Біз бұл пәрмендерді дерекқорлармен жұмыс істеу және серверлерді іске қосу сияқты тапсырмаларды басқару үшін пайдаланамыз.

ll_project каталогында төрт файл бар ❸; ең маңыздылары settings.py, urls.py және wsgi.py. settings.py файлы Django жүйеңізбен қалай әрекеттесетінін және жобаңызды басқаратынын басқарады. Біз осы параметрлердің бірнешеуін өзгертеміз және жоба дамыған сайын өзіміздің кейбір параметрлерді қосамыз. urls.py файлы Django-ға браузер сұрауларына жауап ретінде қай беттерді құру керектігін айтады. wsgi.py файлы Django-ға өзі жасайтын файлдарға қызмет көрсетуге көмектеседі. Файл атауы «веб-сервер шлюзінің интерфейсі» сөзінің аббревиатурасы.

Дерекқорды жасау

Django жоба ақпаратының көп бөлігін дерекқорда сақтайды, сондықтан келесіде Django жұмыс істей алатын дерекқорды жасауымыз керек. Келесі пәрменді енгізіңіз (әлі белсенді ортада):

(ll_env)learning_log$ python manage.py migrate
         Operations to perform:
          Apply all migrations: admin, auth, contenttypes, sessions
        Running migrations:
          Applying contenttypes.0001_initial... OK
          Applying auth.0001_initial... OK
          --snip/код үзіндісі--
          Applying sessions.0001_initial... OK
         (ll_env)learning_log$ ls
        db.sqlite3 ll_env ll_project manage.py

Дерекқорды өзгерткен кез-келген уақытта, біз дерекқорды тасымалдаймыз дейміз. migrate пәрменін алғаш рет шығару Джангоға дерекқордың жобаның ағымдағы күйіне сәйкес келетініне көз жеткізуін айтады. Бұл пәрменді SQLite арқылы жаңа жобада бірінші рет іске қосқанымызда (SQLite туралы бір сәтте толығырақ), Django біз үшін жаңа дерекқор жасайды. Мұнда Django дерекқорды әкімшілік және аутентификация тапсырмаларын өңдеуге қажетті ақпаратты сақтауға дайындайтынын хабарлайды ❶.

ls пәрменін іске қосу Джангоның db.sqlite3 деп аталатын басқа файл жасағанын көрсетеді. ❷. SQLite - бір файлдан жұмыс істейтін дерекқор; бұл қарапайым қолданбаларды жазу үшін өте қолайлы, себебі дерекқорды басқаруға көп көңіл бөлудің қажеті жоқ.

Жобаны көру

Джанго жобаны дұрыс орнатқанына көз жеткізейік. Жобаны ағымдағы күйінде көру үшін runserver пәрменін енгізіңіз:

(ll_env)learning_log$ python manage.py runserver
        Watching for file changes with StatReloader
        Performing system checks...
        
         System check identified no issues (0 silenced).
        May 19, 2022 - 21:52:35
         Django version 4.1, using settings 'll_project.settings'
         Starting development server at http://127.0.0.1:8000/
        Quit the server with CONTROL-C.

Django әзірлеу сервері деп аталатын серверді іске қосуы керек, осылайша оның қаншалықты жақсы жұмыс істейтінін көру үшін жүйеңіздегі жобаны көре аласыз. Браузерде URL мекенжайын енгізу арқылы бетті сұраған кезде, Django сервері тиісті бетті құру және оны браузерге жіберу арқылы сол сұрауға жауап береді.

Джанго алдымен жобаның дұрыс орнатылғанын тексереді ❶; ол пайдаланылып жатқан Django нұсқасын және пайдаланылатын параметрлер файлының атауын ❷ хабарлайды. Соңында, ол жобаға қызмет көрсетілетін URL мекенжайын хабарлайды ❸. URL http://127.0.0.1:8000/ жобаның жергілікті хост деп аталатын компьютердегі 8000 портындағы сұрауларды тыңдап жатқанын көрсетеді. localhost термині жүйеңіздегі сұрауларды ғана өңдейтін серверді білдіреді; ол сіз жасап жатқан беттерді басқа ешкімге көруге мүмкіндік бермейді.

Веб-шолғышты ашып, URL мекенжайын енгізіңіз http://localhost:8000/ немесе біріншісі болмаса, http://127.0.0.1:8000/ жұмыс істемейді. Сіз 18-1-сурет сияқты нәрсені көруіңіз керек: әзірге барлығы дұрыс жұмыс істеп тұрғанын хабарлау үшін Django жасайтын бет. Әзірге серверді жұмыс істеп тұрыңыз, бірақ серверді тоқтатқыңыз келсе, runserver пәрмені берілген терминалда CTRL-C пернелерін басыңыз.

18-1-сурет: әзірге барлығы жұмыс істеп тұр.

Қолданбаны іске қосу

Django жобасы жобаны тұтастай жұмыс істеу үшін бірге жұмыс істейтін жеке қолданбалар тобы ретінде ұйымдастырылған. Әзірге жоба жұмысының көп бөлігін орындау үшін бір қолданба жасаймыз. Біз пайдаланушы тіркелгілерін басқару үшін 19-тарауда басқа қолданбаны қосамыз.

Сіз бұрын ашқан терминал терезесінде әзірлеу серверін жұмыс істеп тұрған күйде қалдыруыңыз керек. Жаңа терминал терезесін (немесе қойындысын) ашыңыз және manage.py бар каталогқа өтіңіз. Виртуалды ортаны іске қосып, startapp пәрменін іске қосыңыз:

learning_log$ source ll_env/bin/activate
        (ll_env)learning_log$ python manage.py startapp learning_logs
         (ll_env)learning_log$ ls
        db.sqlite3 learning_logs ll_env ll_project manage.py
         (ll_env)learning_log$ ls learning_logs/
        __init__.py admin.py apps.py migrations models.py tests.py views.py

startapp appname пәрмені Django-ға қолданбаны құруға қажетті инфрақұрылымды жасауды ұсынады. Жоба каталогын қазір қараған кезде, learning_logs ❶ деп аталатын жаңа каталогты көресіз. Джангоның ❷ жасағанын көру үшін ls пәрменін пайдаланыңыз. Ең маңызды файлдар models.py, admin.py және views.py болып табылады. Қолданбамызда басқарғымыз келетін деректерді анықтау үшін models.py қолданамыз. Сәл кейінірек admin.py және views.py қарап шығамыз.

Үлгілерді анықтау

Деректеріміз туралы бір сәт ойланып көрейік. Әрбір пайдаланушы оқу журналында бірнеше тақырыптарды жасауы керек. Олар жасаған әрбір жазба тақырыпқа байланысты болады және бұл жазбалар мәтін ретінде көрсетіледі. Сондай-ақ біз әрбір жазбаның уақыт белгісін сақтауымыз керек, осылайша біз пайдаланушыларға олардың әрқайсысын жасаған кезде көрсете аламыз.

models.py файлын ашып, оның бар мазмұнын қараңыз:

models.py

from django.db import models
        
        # Create your models here.

models деп аталатын модуль импортталуда және біз өз үлгілерімізді жасауға шақырылуда. үлгі Django-ға қолданбада сақталатын деректермен қалай жұмыс істеу керектігін айтады. Модель - бұл класс; біз талқылаған әрбір класс сияқты оның атрибуттары мен әдістері бар. Мұнда пайдаланушылар сақтайтын тақырыптардың үлгісі берілген:

from django.db import models
        
        class Topic(models.Model):
            """Пайдаланушы оқып жатқан тақырып."""
             text = models.CharField(max_length=200)
             date_added = models.DateTimeField(auto_now_add=True)
        
             def __str__(self):
                """Модельдің жолдық көрінісін қайтару."""
                return self.text

Біз Тақырып деп аталатын классты жасадық, ол Model-дан мұрагер – модельдің негізгі функционалдығын анықтайтын Django-ға енгізілген ата-аналық класс. Topic классына екі атрибут қосамыз: text және date_added.

text атрибуты CharField болып табылады, ол таңбалардан немесе мәтіннен тұратын деректер бөлігі ❶. Атау, тақырып немесе қала сияқты шағын көлемдегі мәтінді сақтағыңыз келгенде CharField пайдаланасыз. CharField атрибутын анықтаған кезде, біз Джангоға оның дерекқорда қанша орын сақтау керектігін айтуымыз керек. Мұнда біз оған көптеген тақырып атауларын сақтауға жеткілікті болатын 200 таңбадан тұратын max_length береміз.

date_added атрибуты - DateTimeField, күн мен уақытты жазатын деректер бөлігі ❷. Біз auto_now_add=True аргументін береміз, ол Django-ға пайдаланушы жаңа тақырып жасаған сайын осы атрибутты автоматты түрде ағымдағы күн мен уақытқа орнатуды айтады.

Джангоға оның үлгі данасын қалай көрсеткіңіз келетінін айтқаныңыз дұрыс. Модельде __str__() әдісі болса, Django сол үлгінің данасына сілтеме жасай отырып, шығаруды жасау қажет болғанда сол әдісті шақырады. Мұнда біз text атрибутына тағайындалған мәнді қайтаратын __str__() әдісін жаздық ❸.

Үлгіде пайдалануға болатын өрістердің әртүрлі түрлерін көру үшін мына жерден "Үлгі өрісі анықтамасы" бетін қараңыз https://docs.djangoproject.com/en/4.1/ref/models/fields. Сізге дәл қазір барлық ақпарат қажет емес, бірақ бұл сіздің жеке Django жобаларыңызды жасағанда өте пайдалы болады.

Үлгілерді белсендіру

Модельдерімізді пайдалану үшін Django-ға біздің қолданбаны жалпы жобаға қосуды айтуымыз керек. settings.py ашыңыз (ll_project каталогында); сіз Django-ға жобада қандай қолданбалар орнатылғанын көрсететін бөлімді көресіз:

settings.py

--snip/код үзіндісі--
        INSTALLED_APPS = [
            'django.contrib.admin',
            'django.contrib.auth',
            'django.contrib.contenttypes',
            'django.contrib.sessions',
            'django.contrib.messages',
            'django.contrib.staticfiles',
        ]
        --snip/код үзіндісі--

INSTALLED_APPS өзгерту арқылы қолданбамызды осы тізімге қосыңыз, осылайша келесідей болады:

--snip/код үзіндісі--
        INSTALLED_APPS = [
            # My apps.
            'learning_logs',
        
            # Default django apps.
            'django.contrib.admin',
            --snip/код үзіндісі--
        ]
        --snip/код үзіндісі--

Қолданбаларды жобада топтастыру оларды бақылауға көмектеседі, өйткені жоба өскен сайын қосымша қолданбаларды қамтиды. Мұнда біз Менің қолданбаларым деп аталатын бөлімді бастаймыз, оған әзірге тек 'learning_logs' кіреді. Әдепкі қолданбалардың кез-келген әрекетін өзіңіздің реттелетін әрекеттеріңізбен қайта анықтау қажет болған жағдайда, жеке қолданбаларды әдепкі қолданбалардан бұрын орналастыру маңызды.

Кейін, біз Django-ға дерекқорды Тақырып үлгісіне қатысты ақпаратты сақтай алатындай өзгертуін айтуымыз керек. Терминалдан келесі пәрменді орындаңыз:

(ll_env)learning_log$ python manage.py makemigrations learning_logs
        Migrations for 'learning_logs':
          learning_logs/migrations/0001_initial.py
            - Create model Topic
        (ll_env)learning_log$

makemigrations пәрмені Django-ға дерекқорды біз анықтаған кез-келген жаңа үлгілермен байланысты деректерді сақтай алатындай өзгерту жолын анықтауға нұсқайды. Мұндағы нәтиже Django 0001_initial.py деп аталатын тасымалдау файлын жасағанын көрсетеді. Бұл тасымалдау дерекқорда Тақырып үлгісі үшін кесте жасайды.

Енді біз бұл тасымалдауды қолданамыз және Джангоға дерекқорды біз үшін өзгертуін сұраймыз:

(ll_env)learning_log$ python manage.py migrate
        Operations to perform:
          Apply all migrations: admin, auth, contenttypes, learning_logs, sessions
        Running migrations:
          Applying learning_logs.0001_initial... OK

Осы пәрмен шығысының көпшілігі миграция пәрменін бірінші рет шығарған кездегі нәтижемен бірдей. Джанго learning_logs көшіру OK жұмыс істегенін растайтын осы шығыстағы соңғы Тіркесті тексеруіміз керек.

Оқыту журналы басқаратын деректерді өзгерткіміз келгенде, біз мына үш қадамды орындаймыз: models.py өзгерту, learning_logs сайтында makemigrations қызметіне қоңырау шалыңыз. және Джангоға жобаны көшіру айтыңыз.

Django әкімші сайты

Django әкімші сайты арқылы үлгілермен жұмыс істеуді жеңілдетеді. Django-ның әкімші сайты тек сайт әкімшілерімен пайдалануға арналған; ол тұрақты пайдаланушыларға арналмаған. Бұл бөлімде біз әкімші сайтын орнатамыз және оны Тақырып үлгісі арқылы кейбір тақырыптарды қосу үшін пайдаланамыз.

Суперпайдаланушыны орнату

Django сайтта барлық артықшылықтарға ие суперпайдаланушы құруға мүмкіндік береді. Пайдаланушының артықшылықтары орындай алатын әрекеттерді басқарады. Ең шектеулі артықшылық параметрлері пайдаланушыға сайттағы жалпыға ортақ ақпаратты ғана оқуға мүмкіндік береді. Тіркелген пайдаланушылар әдетте өздерінің жеке деректерін және кейбір таңдалған ақпаратты тек мүшелерге қолжетімді оқу артықшылығына ие. Жобаны тиімді басқару үшін сайт иесі әдетте сайтта сақталған барлық ақпаратқа қол жеткізуді қажет етеді. Жақсы әкімші өз пайдаланушыларының құпия ақпаратына мұқият қарайды, себебі пайдаланушылар өздері кіретін қолданбаларға үлкен сенім артады.

Django бағдарламасында суперпайдаланушы жасау үшін келесі пәрменді енгізіңіз және сұрауларға жауап беріңіз:

(ll_env)learning_log$ python manage.py createsuperuser
         Username (leave blank to use 'eric'): ll_admin
         Email address:
         Password:
        Password (again):
        Superuser created successfully.
        (ll_env)learning_log$

createssuperuser пәрменін берген кезде, Django суперпайдаланушыға ❶ пайдаланушы атын енгізуді ұсынады. Мұнда мен ll_admin пайдаланамын, бірақ сіз қалаған пайдаланушы атын енгізе аласыз. Электрондық пошта мекенжайын енгізуге немесе осы өрісті бос қалдыруға болады ❷. Құпия сөзіңізді екі рет ❸ енгізуіңіз керек.

Әкімші сайтында үлгіні тіркеу

Django әкімші сайтындағы кейбір үлгілерді автоматты түрде қамтиды, мысалы, User және Group, бірақ біз жасайтын үлгілерді қолмен қосу керек.

Біз learning_logs қолданбасын іске қосқан кезде, Джанго models.py каталогымен бірдей каталогта admin.py файлын жасады. admin.py файлын ашыңыз:

admin.py

from django.contrib import admin
        
        # Register your models here.

Тақырыпты әкімші сайтында тіркеу үшін келесіні енгізіңіз:

from django.contrib import admin
        
        from .models import Topic
        
        admin.site.register(Topic)

Бұл код алдымен біз тіркегіміз келетін үлгіні импорттайды, Тақырып. models алдындағы нүкте Джангоға models.py файлын admin.py каталогында іздеуге шақырады. admin.site.register() коды Django-ға үлгімізді әкімші сайты арқылы басқаруға нұсқайды.

Енді әкімші сайтына кіру үшін суперпайдаланушы тіркелгісін пайдаланыңыз. http://localhost:8000/admin/ бетіне өтіп, жаңа ғана жасаған суперпайдаланушының пайдаланушы аты мен құпия сөзін енгізіңіз. 18-2-суретте көрсетілгенге ұқсас экранды көруіңіз керек. Бұл бет жаңа пайдаланушылар мен топтар қосуға және бұрыннан барларын өзгертуге мүмкіндік береді. Біз жаңа ғана анықтаған Тақырып үлгісіне қатысты деректермен де жұмыс істей аласыз.

18-2-сурет: Тақырыбы қосылған әкімші сайты

Тақырыптарды қосу

Енді Тақырып әкімші сайтында тіркелгендіктен, бірінші тақырыбымызды қосамыз. Көбінесе бос "Тақырыптар" бетіне өту үшін Тақырыптар түймесін басыңыз, себебі бізде әлі басқарылатын тақырыптар жоқ. Тақырыпты қосу түймесін басыңыз, сонда жаңа тақырып қосу пішіні пайда болады. Бірінші жолаққа Шахмат енгізіп, Сақтау түймесін басыңыз. Тақырыптар әкімшісі бетіне қайта жіберілесіз және жаңа ғана жасаған тақырыпты көресіз.

Екінші тақырыпты ашайық, сонда бізде жұмыс істеу үшін көбірек деректер болады. Тақырыпты қосу түймесін қайтадан басып, Тасқа өрмелеу енгізіңіз. Сақтау түймесін басыңыз, сонда сіз негізгі тақырыптар бетіне қайта жіберілесіз. Енді сіз шахмат пен жартасқа өрмелеуді көресіз.

Жазба үлгісін анықтау

Пайдаланушы шахмат және жартасқа өрмелеу туралы не үйренгенін жазып алуы үшін пайдаланушылар оқу журналдарында жасай алатын жазба түрлерінің үлгісін анықтауымыз керек. Әрбір жазба белгілі бір тақырыппен байланыстырылуы керек. Бұл қатынас көптен-бірге қатынас деп аталады, яғни көптеген жазбаларды бір тақырыппен байланыстыруға болады.

Міне, Entry үлгісінің коды. Оны models.py файлыңызға орналастырыңыз:

models.py

from django.db import models
        
        class Topic(models.Model):
            --snip/код үзіндісі--
        
         class Entry(models.Model):
            """Тақырып бойынша белгілі бір нәрсе үйренді."""
             topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
             text = models.TextField()
            date_added = models.DateTimeField(auto_now_add=True)
        
             class Meta:
                verbose_name_plural = 'entries'
        
            def __str__(self):
                """Жазбаны білдіретін қарапайым жолды қайтарыңыз."""
                 return f"{self.text[:50]}..."

Entry классы Тақырып . Бірінші атрибут, topic, ForeignKey данасы ❷ болып табылады. өзге планеталық кілт дерекқор термині; бұл дерекқордағы басқа жазбаға сілтеме. Бұл әрбір жазбаны белгілі бір тақырыпқа байланыстыратын код. Әрбір тақырып жасалған кезде оған кілт немесе идентификатор тағайындалады. Джанго деректердің екі бөлігі арасында байланыс орнату қажет болғанда, ол әрбір ақпарат бөлігімен байланысты кілттерді пайдаланады. Белгілі бір тақырыпқа қатысты барлық жазбаларды шығарып алу үшін бұл қосылымдарды жақын арада қолданамыз. on_delete=models.CASCADE аргументі Джангоға тақырып жойылған кезде сол тақырыппен байланысты барлық жазбаларды да жою керектігін айтады. Бұл каскадты жою ретінде белгілі.

Келесі - text деп аталатын атрибут, ол TextField ❸ данасы болып табылады. . Мұндай өріске өлшем шектеуі қажет емес, өйткені біз жеке жазбалардың өлшемін шектегіміз келмейді. date_added атрибуты бізге жазбаларды жасалған ретімен көрсетуге және әрбір жазбаның жанына уақыт белгісін қоюға мүмкіндік береді.

Meta класы Entry класының ❹ ішіне кірістірілген. Meta класы үлгіні басқаруға арналған қосымша ақпаратты қамтиды; мұнда, ол бірнеше жазбаға сілтеме жасау қажет болғанда, Джангоға Entries қолдануын айтатын арнайы атрибут орнатуға мүмкіндік береді. Онсыз, Джанго бірнеше жазбаларды Entrys деп атайды.

__str__() әдісі Джангоға жеке жазбаларға сілтеме жасағанда қандай ақпаратты көрсету керектігін айтады. Жазба мәтіннің ұзақ мәтіні болуы мүмкін болғандықтан, __str__() text мәтінінің алғашқы 50 таңбасын ғана қайтарады.❺. Сондай-ақ біз барлық жазбаны әрдайым көрсетпейтінімізді түсіндіру үшін эллипс қосамыз.

Жазба үлгісін тасымалдау

Біз жаңа үлгі қосқандықтан, дерекқорды қайта тасымалдауымыз керек. Бұл процесс өте таныс болады: сіз models.py өзгертесіз, python manage.py makemigrations пәрменін орындайсыз. app_name,содан кейін python manage.py migrate пәрменін іске қосыңыз.

Дерекқорды тасымалдаңыз және келесі пәрмендерді енгізу арқылы нәтижені тексеріңіз:

(ll_env)learning_log$ python manage.py makemigrations learning_logs
        Migrations for 'learning_logs':
           learning_logs/migrations/0002_entry.py
            - Create model Entry
        (ll_env)learning_log$ python manage.py migrate
        Operations to perform:
          --snip/код үзіндісі--
           Applying learning_logs.0002_entry... OK

0002_entry.py деп аталатын жаңа тасымалдау жасалды, ол Django-ға Entry үлгісіне қатысты ақпаратты сақтау үшін дерекқорды қалай өзгерту керектігін айтады ❶. migrate пәрменін бергенде, Джанго бұл тасымалдауды қолданғанын және бәрі дұрыс жұмыс істегенін көреміз ❷.

Жазбаны әкімші сайтында тіркеу

Сонымен қатар Entry үлгісін тіркеуіміз керек. admin.py енді қандай болуы керек:

admin.py

from django.contrib import admin
        
        from .models import Topic, Entry
        
        admin.site.register(Topic)
        admin.site.register(Entry)

http://localhost/admin/ бетіне оралыңыз, сонда Learning_Logs астында тізімделген жазбаларды көресіз. Жазбалар үшін Қосу сілтемесін басыңыз немесе Жазбалар түймесін басып, Жазба қосу таңдаңыз. Жазба жасап жатқан тақырыпты таңдау үшін ашылмалы тізімді және жазба қосуға арналған мәтін ұясын көруіңіз керек. Ашылмалы тізімнен Шахмат тармағын таңдап, жазба қосыңыз. Міне, мен жасаған бірінші жазба:

Ашылу - бұл ойынның бірінші бөлігі, шамамен алғашқы он қозғалыс немесе одан да көп. Ашылу кезінде үш нәрсені жасаған дұрыс: епископтарыңыз бен рыцарларыңызды шығарып, тақтаның ортасын басқаруға тырысыңыз және патшаңызды құлыптаңыз.

Әрине, бұл тек нұсқаулар. Бұл нұсқауларды қашан орындау керектігін және бұл ұсыныстарды қай кезде елемеу керектігін білу маңызды болады.

Сақтау түймесін басқанда, жазбалар үшін негізгі әкімші бетіне қайта ораласыз. Мұнда сіз әр жазба үшін жол көрінісі ретінде text[:50] пайдаланудың артықшылығын көресіз; әр жазбаның бүкіл мәтінін емес, тек бірінші бөлігін ғана көрсеңіз, әкімші интерфейсіндегі бірнеше жазбалармен жұмыс істеу әлдеқайда оңайырақ.

Шахматқа екінші жазба және жартасқа өрмелеу үшін бір жазба жасаңыз, сонда бізде бастапқы деректер бар. Міне, шахматқа арналған екінші жазба:

Ойынның ашылу кезеңінде епископтарыңыз бен рыцарларыңызды шығару маңызды. Бұл фигуралар ойынның бастапқы қозғалыстарында маңызды рөл атқаратындай күшті және маневрлі.

Міне, жартасқа өрмелеуге арналған бірінші жазба:

Тауға өрмелеудегі ең маңызды ұғымдардың бірі - салмағыңызды мүмкіндігінше аяғыңызда ұстау. Альпинистер күні бойы қолдарына ілінуі мүмкін деген миф бар. Шындығында, жақсы альпинистер мүмкіндігінше салмағын аяғынан асырып ұстаудың арнайы әдістерін қолданды.

Оқу журналын әзірлеуді жалғастыра отырып, бұл үш жазба бізге жұмыс істеуге мүмкіндік береді.

Джанго қабығы

Енді біз кейбір деректерді енгіздік, біз оны интерактивті терминал сеансы арқылы бағдарламалық түрде тексере аламыз. Бұл интерактивті орта Django қабығы деп аталады және бұл жобаны сынауға және ақаулықтарды жоюға арналған тамаша орта. Міне интерактивті қабық сеансының мысалы:

(ll_env)learning_log$ python manage.py shell
         >>> from learning_logs.models import Topic
        >>> Topic.objects.all()
        <QuerySet [<Topic: Chess>, <Topic: Rock Climbing>]>

Белсенді виртуалды ортада іске қосылған python manage.py shell пәрмені жобаңыздың дерекқорында сақталған деректерді зерттеу үшін пайдалануға болатын Python аудармашысын іске қосады. Мұнда біз Тақырып үлгісін learning_logs.models модулінен ❶ импорттаймыз. Содан кейін Topic үлгісінің барлық даналарын алу үшін Topic.objects.all() әдісін қолданамыз; қайтарылатын тізім сұраулар жинағы деп аталады.

Біз тізімді айналдыратындай сұраулар жиынын айналдыра аламыз. Әрбір тақырып нысанына тағайындалған идентификаторды мына жерден көруге болады:

>>> topics = Topic.objects.all()
        >>> for topic in topics:
        ...     print(topic.id, topic)
        ...
        1 Chess
        2 Rock Climbing

Біз сұраныстар жинағын тақырыптарға тағайындаймыз, содан кейін әрбір тақырыптың id атрибутын және әрбір тақырыптың жол көрінісін басып шығарамыз. Шахмат идентификаторы 1, ал Жартасқа өрмелеу-де 2 идентификаторы бар екенін көреміз.

Егер белгілі бір нысанның идентификаторын білсеңіз, сол нысанды шығарып алу және нысанның кез-келген атрибутын тексеру үшін Topic.objects.get() әдісін қолдануға болады. Chess үшін text және date_added мәндерін қарастырайық:

>>> t = Topic.objects.get(id=1)
        >>> t.text
        'Chess'
        >>> t.date_added
        datetime.datetime(2022, 5, 20, 3, 33, 36, 928759,
            tzinfo=datetime.timezone.utc)

Біз белгілі бір тақырыпқа қатысты жазбаларды да қарай аламыз. Бұрын біз Entry үлгісі үшін topic атрибутын анықтадық. Бұл ForeignKey, әрбір жазба мен тақырып арасындағы байланыс болды. Django осы қосылымды белгілі бір тақырыпқа қатысты әрбір жазбаны алу үшін пайдалана алады, мысалы:

 >>> t.entry_set.all()
        <QuerySet [<Entry: The opening is the first part of the game, roughly...>, <Entry:
        In the opening phase of the game, it's important t...>]>

өзге планеталық кілт қатынасы арқылы деректерді алу үшін сіз астын сызу және set ❶ сөзінен кейін тиісті үлгінің кіші әріп атын пайдаланасыз. Мысалы, сізде Pizza және Topping үлгілері бар делік, ал Topping сыртқы кілт арқылы Pizza-ға қатысты. . Егер нысан бір пиццаны білдіретін my_pizza деп аталса, my_pizza.topping_set.all() кодын пайдаланып пиццаның барлық қоспаларын алуға болады.

Біз бұл синтаксисті пайдаланушылар сұрай алатын беттерді кодтауды бастағанда қолданамыз. Қабық кодыңыз қажет деректерді шығарып алатынына көз жеткізу үшін шынымен пайдалы. Егер сіздің кодыңыз қабықшада күткендей жұмыс істесе, ол жобаңыздағы файлдарда да дұрыс жұмыс істеуі керек. Егер код қателер тудырса немесе сіз күткен деректерді шығарып алмаса, веб-беттерді жасайтын файлдарға қарағанда қарапайым қабық ортасында код ақаулықтарын жою оңайырақ. Біз қабықшаға көп сілтеме жасамаймыз, бірақ жобада сақталған деректерге қол жеткізу үшін Django синтаксисімен жұмыс істеу үшін оны пайдалануды жалғастыру керек.

Үлгілерді өзгерткен сайын, сол өзгерістердің әсерін көру үшін қабықты қайта іске қосу керек болады. Қабық сеансынан шығу үшін CTRL-D пернелерін басыңыз; Windows жүйесінде CTRL-Z, одан кейін ENTER пернесін басыңыз.

Беттерді жасау: оқу журналының негізгі беті

Django көмегімен веб-беттерді жасау үш кезеңнен тұрады: URL мекенжайларын анықтау, көріністерді жазу және үлгілерді жазу. Бұларды кез-келген ретпен орындауға болады, бірақ бұл жобада біз әрқашан URL үлгісін анықтаудан бастаймыз. URL үлгісі URL мекенжайының орналасу жолын сипаттайды. Сондай-ақ ол Django-ға браузер сұрауын сайттың URL мекенжайымен сәйкестендіру кезінде не іздеу керектігін айтады, осылайша қай бетті қайтару керектігін біледі.

Әр URL содан кейін белгілі бір көрініспен салыстырылады. көру функциясы сол бетке қажетті деректерді шығарып алады және өңдейді. Көрініс функциясы көбінесе беттің жалпы құрылымын қамтитын үлгі арқылы бетті көрсетеді. Мұның қалай жұмыс істейтінін көру үшін Оқу журналының басты бетін жасайық. Біз басты беттің URL мекенжайын анықтаймыз, оның көру функциясын жазамыз және қарапайым үлгі жасаймыз.

Оқу журналының дұрыс жұмыс істейтініне көз жеткізгіміз келгендіктен, біз әзірге қарапайым бет жасаймыз. Жұмыс істеп тұрған веб-бағдарлама аяқталған кезде оны сәндеу қызық; жақсы көрінетін, бірақ жақсы жұмыс істемейтін қолданбаның мағынасы жоқ. Әзірге басты бетте тек тақырып пен қысқаша сипаттама көрсетіледі.

URL мекенжайын салыстыру

Пайдаланушылар URL мекенжайларын браузерге енгізу және сілтемелерді басу арқылы беттерді сұрайды, сондықтан қандай URL мекенжайлары қажет екенін шешуіміз керек. Басты беттің URL мекенжайы бірінші болып табылады: бұл адамдар жобаға кіру үшін пайдаланатын негізгі URL мекенжайы. Қазіргі уақытта негізгі URL, http://localhost:8000/, жобаның дұрыс орнатылғанын білуге мүмкіндік беретін әдепкі Django сайтын қайтарады. Біз мұны негізгі URL мекенжайын Learning журналының басты бетіне салыстыру арқылы өзгертеміз.

Негізгі ll_project каталогында urls.py файлын ашыңыз. Келесі кодты көруіңіз керек:

ll_project/urls.py

 from django.contrib import admin
        from django.urls import path
        
         urlpatterns = [
             path('admin/', admin.site.urls),
        ]

Алғашқы екі жол admin модулін және URL жолдарын құру функциясын ❶ импорттайды. Файлдың негізгі бөлігі urlpatterns айнымалы мәнін ❷ анықтайды. Жалпы жобаның URL мекенжайларын анықтайтын осы urls.py файлында urlpatterns айнымалысы жобадағы қолданбалардың URL мекенжайларының жиынын қамтиды. Тізімге әкімші сайтынан ❸ сұрауға болатын барлық URL мекенжайларын анықтайтын admin.site.urls модулі кіреді.

Бізге learning_logs үшін URL мекенжайларын қосу керек, сондықтан мыналарды қосыңыз:

from django.contrib import admin
        from django.urls import path, include
        
        urlpatterns = [
            path('admin/', admin.site.urls),
            path('', include('learning_logs.urls')),
        ]

Біз include() функциясын импорттадық, сонымен қатар learning_logs.urls модулін қосатын Тіркесті қостық.

Әдепкі urls.py ll_project каталогында; енді learning_logs каталогында екінші urls.py файлын жасауымыз керек. Жаңа Python файлын жасаңыз, оны learning_logs ішінде urls.py ретінде сақтаңыз және оған мына кодты енгізіңіз:

learning_logs/urls.py

 """Оқу_журналдары үшін URL үлгілерін анықтайды."""
        
         from django.urls import path
        
         from . import views
        
         app_name = 'learning_logs'
         urlpatterns = [
            # Home page
             path('', views.index, name='index'),
        ]

Қай urls.py файлында жұмыс істеп жатқанымызды түсіну үшін файлдың басына құжат жолын қосамыз ❶. Содан кейін URL мекенжайларын көріністерге ❷ салыстыру кезінде қажет болатын path функциясын импорттаймыз. Біз сондай-ақ көріністер модулін ❸ импорттаймыз; нүкте Python-ға views.py модулін ағымдағы urls.py модулімен бірдей каталогтан импорттауын айтады. app_name айнымалысы Django-ға осы urls.py файлын жоба ❹ ішіндегі басқа қолданбалардағы аттас файлдардан ажыратуға көмектеседі. Бұл модульдегі urlpatterns айнымалы мәні learning_logs қолданбасынан ❺ сұрауға болатын жеке беттердің тізімі.

Нақты URL үлгісі үш аргументті ❻ қабылдайтын path() функциясына шақыру болып табылады. Бірінші аргумент Джангоға ағымдағы сұрауды дұрыс бағыттауға көмектесетін жол болып табылады. Django сұралған URL мекенжайын алады және сұрауды көрініске бағыттауға тырысады. Ол мұны ағымдағы сұрауға сәйкес келетінін табу үшін біз анықтаған барлық URL үлгілерін іздеу арқылы жасайды. Django жобаның негізгі URL мекенжайын елемейді (http://localhost:8000/), сондықтан бос жол ('') негізгі URL мекенжайына сәйкес келеді. кез-келген басқа URL мекенжайы бұл үлгіге сәйкес келмейді және сұралған URL мекенжайы бар URL үлгілеріне сәйкес келмесе, Django қате бетін қайтарады.

path() ❻ ішіндегі екінші аргумент views.py ішінде қандай функция шақырылатынын көрсетеді. Сұралған URL мекенжайы біз анықтайтын үлгіге сәйкес келгенде, Django views.py ішінен index() функциясын шақырады. (Бұл көрініс функциясын келесі бөлімде жазамыз.) Үшінші аргумент осы URL үлгісі үшін индекс атауын береді, осылайша жобаның барлық басқа файлдарында оған оңай сілтеме жасай аламыз. Басты бетке сілтеме бергіміз келгенде, URL мекенжайын жазудың орнына осы атауды қолданамыз.

Көрініс жазу

Көру функциясы сұраудан ақпаратты қабылдайды, бетті жасау үшін қажетті деректерді дайындайды, содан кейін деректерді шолғышқа қайта жібереді. Ол мұны көбінесе беттің қандай болатынын анықтайтын үлгіні пайдалану арқылы жасайды.

Learning_logs ішіндегі views.py файлы python manage.py startapp пәрменін орындаған кезде автоматты түрде жасалды. Дәл қазір views.py ішінде не бар:

views.py

from django.shortcuts import render
        
        # Create your views here.

Қазір бұл файл көріністер берген деректер негізінде жауапты көрсететін render() функциясын ғана импорттайды. views.py ашыңыз және басты бетке келесі кодты қосыңыз:

from django.shortcuts import render
        
        def index(request):
            """Оқу журналының басты беті."""
            return render(request, 'learning_logs/index.html')

URL сұрауы біз анықтаған үлгіге сәйкес келгенде, Django views.py файлында index() деп аталатын функцияны іздейді. Содан кейін Django осы көрініс функциясына request нысанын береді. Бұл жағдайда бет үшін ешқандай деректерді өңдеудің қажеті жоқ, сондықтан функциядағы жалғыз код - render() шақыру. Мұндағы render() функциясы екі аргументті өткізеді: бастапқы request нысаны және ол бетті құру үшін пайдалана алатын үлгі. Осы үлгіні жазайық.

Үлгі жазу

Үлгі беттің қандай болуы керектігін анықтайды және Джанго бет сұралған сайын тиісті деректерді толтырады. Үлгі көрініс арқылы берілген кез-келген деректерге қол жеткізуге мүмкіндік береді. Басты бетке арналған көрінісіміз ешқандай деректер бермейтіндіктен, бұл үлгі өте қарапайым.

learning_logs каталогының ішінде үлгілер деп аталатын жаңа каталог жасаңыз. үлгілер каталогының ішінде learning_logs деп аталатын басқа каталогты жасаңыз. Бұл аздап артық болып көрінуі мүмкін (бізде learning_logs деп аталатын каталогтың ішінде үлгілер деп аталатын каталогтың ішінде learning_logs атты каталог бар), бірақ ол реттеледі көптеген жеке қолданбаларды қамтитын үлкен жоба контекстінде де Django бір мағыналы түсіндіре алатын құрылым. Ішкі learning_logs каталогында index.html деп аталатын жаңа файл жасаңыз. Файлға апаратын жол ll_project/learning_logs/templates/learning_logs/index.html болады. Осы файлға келесі кодты енгізіңіз:

index.html

<p>Learning Log</p>
        
        <p>Learning Log helps you keep track of your learning, for any topic you're
        interested in.</p>

Бұл өте қарапайым файл. HTML тілімен таныс болмасаңыз, <p></p> тегтері абзацтарды білдіреді. <p> тегі абзацты ашады, ал </p> тегі абзацты жабады. Бізде екі абзац бар: біріншісі тақырып ретінде әрекет етеді, ал екіншісі пайдаланушылардың Learning Log көмегімен не істей алатынын сипаттайды.

Енді жобаның негізгі URL мекенжайын сұраған кезде, http://localhost:8000/, сіз әдепкі Django бетінің орнына жаңа ғана құрастырған бетті көресіз. Django сұралған URL мекенжайын қабылдайды және бұл URL '' үлгісіне сәйкес келеді; содан кейін Django index.html ішіндегі үлгіні пайдаланып бетті көрсететін views.index() функциясын шақырады. 18-3-сурет нәтиже бетін көрсетеді.

18-3-сурет: Оқу журналының басты беті

Бір бетті жасау күрделі процесс болып көрінгенімен, URL мекенжайлары, көріністер және үлгілер арасындағы бұл бөлу өте жақсы жұмыс істейді. Бұл жобаның әрбір аспектісін бөлек ойлауға мүмкіндік береді. Ірі жобаларда бұл жобада жұмыс істейтін адамдарға өздерін күштірек ететін салаларға назар аударуға мүмкіндік береді. Мысалы, дерекқор маманы модельдерге назар аудара алады, бағдарламашы қарау кодына назар аудара алады, ал интерфейс маманы үлгілерге назар аудара алады.

Қосымша беттерді құру

Енді біз бетті құру тәртібін белгіледік, біз Learning Log жобасын құруға кірісеміз. Біз деректерді көрсететін екі бетті жасаймыз: барлық тақырыптар тізімделген бет және белгілі бір тақырыпқа арналған барлық жазбаларды көрсететін бет. Әрбір бет үшін URL үлгісін көрсетеміз, көру функциясын жазамыз және үлгі жазамыз. Бірақ мұны жасамас бұрын, жобадағы барлық үлгілер мұраға алатын негізгі үлгіні жасаймыз.

Үлгі мұрасы

Веб-сайтты құру кезінде кейбір элементтерді әр бетте қайталау қажет болады. Бұл элементтерді әрбір бетке тікелей жазудың орнына, қайталанатын элементтерді қамтитын негізгі үлгіні жазып, содан кейін әрбір беттің негізден мұралануына болады. Бұл тәсіл әр беттің бірегей аспектілерін дамытуға назар аударуға мүмкіндік береді және жобаның жалпы көрінісі мен сезімін өзгертуді әлдеқайда жеңілдетеді.

Ата-ана үлгісі

Біз index.html сияқты бір каталогта base.html деп аталатын үлгіні жасаймыз. Бұл файлда барлық беттерге ортақ элементтер болады; әрбір басқа үлгі base.html ішінен мұрагер болады. Біз дәл қазір әр бетте қайталағымыз келетін жалғыз элемент - жоғарғы жағындағы тақырып. Бұл үлгіні әр бетке қосатындықтан, тақырыпты басты бетке сілтеме жасайық:

base.html

<p>
           <a href="{% url 'learning_logs:index' %}">Learning Log</a>
        </p>
        
         {% block content %}{% endblock content %}

Бұл файлдың бірінші бөлігі жобаның атауын қамтитын абзацты жасайды, ол сонымен қатар басты бет сілтемесі ретінде әрекет етеді. Сілтемені жасау үшін біз жақшалармен және пайыздық белгілермен ({% %}) көрсетілген үлгі тегін қолданамыз. Үлгі тегі бетте көрсетілетін ақпаратты жасайды. Мұнда көрсетілген {% url 'learning_logs:index' %} үлгі тегі learning_logs/urls.py ішінде ' атымен анықталған URL үлгісіне сәйкес URL жасайды. индекс' ❶. Бұл мысалда learning_logs - аттар кеңістігі және index - бұл аттар кеңістігіндегі бірегей аталған URL үлгісі. Атау кеңістігі learning_logs/urls.py файлындағы app_name үшін тағайындалған мәннен келеді.

Қарапайым HTML бетінде сілтеме зәкір тегімен <a> қоршалған:

<a href="link_url">link text</a>

Үлгі тегінде URL мекенжайын жасау біздің сілтемелерімізді жаңартып отыруды әлдеқайда жеңілдетеді. Бізге тек urls.py ішіндегі URL үлгісін өзгерту керек және Django келесі жолы бет сұралғанда жаңартылған URL мекенжайын автоматты түрде енгізеді. Жобамыздың әрбір беті base.html мұрағатынан өтеді, сондықтан бұдан былай әрбір бетте басты бетке кері сілтеме болады.

Соңғы жолға block тегтерінің жұбын ❷ кірістіреміз. content деп аталатын бұл блок толтырғыш болып табылады; child/бала үлгі content блогына кіретін ақпарат түрін анықтайды.

child/бала үлгіде әрбір блокты ата-анасынан анықтаудың қажеті жоқ, сондықтан ата-аналық үлгілерде қалағаныңызша көп блоктар үшін бос орын қалдыра аласыз; child/бала үлгі қажет болғанша ғана пайдаланады.

Бала үлгісі

Енді base.html файлынан мұра алу үшін index.html файлын қайта жазуымыз керек. Келесі кодты index.html ішіне қосыңыз:

index.html

 {% extends 'learning_logs/base.html' %}
        
         {% block content %}
          <p>Learning Log helps you keep track of your learning, for any topic you're
          interested in.</p>
         {% endblock content %}

Егер мұны бастапқы index.html нұсқасымен салыстырсаңыз, біз Оқу журналының тақырыбын ата-ана үлгісінен мұраға алуға арналған кодпен ❶ ауыстырғанымызды көре аласыз. Джангоға қай ата-аналық үлгіні иелену керектігін айту үшін child/бала үлгінің бірінші жолда {% extensions %} тегі болуы керек. base.html файлы learning_logs бөлігі болып табылады, сондықтан біз learning_logs-ді негізгі үлгіге апаратын жолға қосамыз. Бұл жол base.html үлгісіндегі барлық нәрсені тартады және index.html файлына content блогында сақталған кеңістікте не болатынын анықтауға мүмкіндік береді. .

Біз мазмұн блогын {% block %} тегін content ❷ атауымен кірістіру арқылы анықтаймыз. Бізге ата-аналық үлгіден мұраға алынбайтын барлық нәрсе content блогының ішіне кіреді. Мұнда оқу журналы жобасын сипаттайтын абзац берілген. {% endblock content %} тегін ❸ пайдалану арқылы мазмұнды анықтауды аяқтағанымызды көрсетеміз. {% endblock %} тегі атауды қажет етпейді, бірақ үлгі бірнеше блоктан тұратын болса, қай блоктың аяқталатынын білу пайдалы болуы мүмкін.

Үлгі мұрасының артықшылығын көре бастай аласыз: child/бала үлгіде біз тек сол бетке бірегей мазмұнды қосуымыз керек. Бұл әрбір үлгіні жеңілдетіп қана қоймайды, сонымен қатар сайтты өзгертуді айтарлықтай жеңілдетеді. Көптеген беттерге ортақ элементті өзгерту үшін тек негізгі үлгіні өзгерту қажет. Содан кейін өзгертулер сол үлгіден мұраланған әрбір бетке тасымалданады. Ондаған немесе жүздеген беттерді қамтитын жобада бұл құрылым сайтыңызды жақсартуды әлдеқайда жеңіл және жылдамырақ етеді.

Үлкен жобада бүкіл сайт үшін base.html деп аталатын бір негізгі үлгі және тораптың әрбір негізгі бөлімі үшін негізгі үлгілер болуы әдеттегідей. Барлық бөлім үлгілері base.html файлынан мұраланады және тораптағы әрбір бет бөлім үлгісінен мұраланады. Осылайша сіз тұтастай сайттың, сайттағы кез-келген бөлімнің немесе кез-келген жеке беттің көрінісі мен сезімін оңай өзгерте аласыз. Бұл конфигурация жұмыс істеудің өте тиімді әдісін қамтамасыз етеді және жобаңызды уақыт өте келе тұрақты жаңартуға шақырады.

Тақырыптар беті

Енді бізде беттерді құрудың тиімді тәсілі болғандықтан, біз келесі екі бетке назар аудара аламыз: жалпы тақырыптар беті және бір тақырыпқа арналған жазбаларды көрсететін бет. Тақырыптар беті пайдаланушылар жасаған барлық тақырыптарды көрсетеді және бұл деректермен жұмыс істеуді қамтитын бірінші бет.

Тақырыптардың URL үлгісі

Біріншіден, біз тақырыптар бетінің URL мекенжайын анықтаймыз. Беттегі ақпарат түрін көрсететін қарапайым URL фрагментін таңдау әдеттегідей. Біз тақырыптар сөзін қолданамыз, сондықтан URL http://localhost:8000/topics/ бұл бетті қайтарады. learning_logs/urls.py өзгерту әдісі мынада:

learning_logs/urls.py

"""Оқу_журналдары үшін URL үлгілерін анықтайды."""
        --snip/код үзіндісі--
        urlpatterns = [
            # Home page
            path('', views.index, name='index'),
            # Page that shows all topics.
            path('topics/', views.topics, name='topics'),
        ]

Жаңа URL үлгісі - тақырыптар сөзі, одан кейін қиғаш сызық. Django сұралған URL мекенжайын зерттеген кезде, бұл үлгі негізгі URL мекенжайы бар, одан кейін тақырыптар бар кез-келген URL мекенжайына сәйкес келеді. Соңында қиғаш сызықты қосуға немесе алып тастауға болады, бірақ тақырыптар сөзінен кейін басқа ештеңе болмауы мүмкін немесе үлгі сәйкес келмейді. Осы үлгіге сәйкес келетін URL мекенжайы бар кез-келген сұрау views.py ішіндегі topics() функциясына жіберіледі.

Тақырыптар көрінісі

topics() функциясы дерекқордан кейбір деректерді шығарып алып, үлгіге жіберуі керек. views.py ішіне келесіні қосыңыз:

views.py

from django.shortcuts import render
        
         from .models import Topic
        
        def index(request):
            --snip/код үзіндісі--
        
         def topics(request):
            """Барлық тақырыптарды көрсету."""
             topics = Topic.objects.order_by('date_added')
             context = {'topics': topics}
             return render(request, 'learning_logs/topics.html', context)

Біз алдымен қажетті деректермен байланысты үлгіні импорттаймыз ❶. topics() функциясына бір параметр қажет: Django серверден алынған request нысаны ❷. Біз дерекқорды Тақырып нысандарын сұрау арқылы сұраймыз, date_added атрибуты ❸ бойынша сұрыпталады. Алынған сұраулар жинағын тақырыптарға тағайындаймыз.

Одан кейін біз үлгіге ❹ жіберетін мәтінмәнді анықтаймыз. контекст - бұл сөздік, онда кілттер біз қалаған деректерге қол жеткізу үшін үлгіде қолданатын атаулар, ал мәндер үлгіге жіберу керек деректер болып табылады. Бұл жағдайда біз бетте көрсететін тақырыптар жиынтығын қамтитын бір кілт-мән жұбы бар. Деректерді пайдаланатын бетті құру кезінде біз render() нысанын request нысанымен, қолданғымыз келетін үлгімен және контекст сөздігімен шақырамыз. ❺.

Тақырыптар үлгісі

Тақырыптар бетіне арналған үлгі контекст сөздігін алады, сондықтан үлгі topics() қамтамасыз ететін деректерді пайдалана алады. topics.html деп аталатын файлды index.html каталогымен бірдей етіп жасаңыз. Үлгідегі тақырыптарды мына жолмен көрсетуге болады:

topics.html

{% extends 'learning_logs/base.html' %}
        
        {% block content %}
        
          <p>Topics</p>
        
           <ul>
             {% for topic in topics %}
               <li>{{ topic.text }}</li>
             {% empty %}
              <li>No topics have been added yet.</li>
             {% endfor %}
           </ul>
        
        {% endblock content %}

Біз base.html файлынан мұраға алу үшін {% extensions %} тегін қолданамыз, дәл сол басты бетте жасағандай, содан кейін ашамыз. мазмұн блогы. Бұл беттің негізгі бөлігінде енгізілген тақырыптардың маркерленген тізімі бар. Стандартты HTML тілінде маркерленген тізім ретсіз тізім деп аталады және <ul></ul> тегтерімен белгіленеді. <ul> ашу тегі тақырыптардың маркерленген тізімін ❶ бастайды.

Кейін біз контекст сөздігінен ❷ тақырыптар тізімі арқылы өтетін for цикліне баламалы үлгі тегін қолданамыз. Үлгілерде қолданылатын код Python-дан кейбір маңызды Тіркестермен ерекшеленеді. Python for операторының қай жолдары цикл бөлігі екенін көрсету үшін шегіністерді пайдаланады. Үлгіде әрбір for циклі циклдің соңы қай жерде болатынын көрсететін анық {% endfor %} тегін қажет етеді. Сонымен, үлгіде сіз келесідей жазылған циклдарды көресіз:

{% for item in list %}
          do something with each item
        {% endfor %}

Цикл ішінде біз әрбір тақырыпты маркерленген тізімдегі элементке айналдырғымыз келеді. Үлгідегі айнымалы мәнді басып шығару үшін айнымалы атын қос жақшаға ораңыз. Жақшалар бетте пайда болмайды; олар Джангоға үлгі айнымалысын пайдаланып жатқанымызды көрсетеді. Сонымен, {{ topic.text }} ❸ коды цикл арқылы әрбір өтуде ағымдағы тақырыптың text атрибутының мәніне ауыстырылады. HTML тегі <li></li> тізім элементін көрсетеді. Осы тегтердің арасындағы, <ul></ul> жұбының ішіндегі кез-келген нәрсе тізімде таңбаланған элемент ретінде пайда болады.

Біз сонымен қатар {% empty %} үлгі тегін ❹ қолданамыз, ол тізімде элементтер жоқ болса, Джангоға не істеу керектігін айтады. Бұл жағдайда біз пайдаланушыға әлі тақырыптар қосылмағаны туралы хабарламаны басып шығарамыз. Соңғы екі жол for циклін ❺, содан кейін таңбаланған тізімді ❻ жабады.

Енді тақырыптар бетіне сілтеме қосу үшін негізгі үлгіні өзгертуіміз керек. Келесі кодты base.html ішіне қосыңыз:

base.html

<p>
           <a href="{% url 'learning_logs:index' %}">Learning Log</a> -
           <a href="{% url 'learning_logs:topics' %}">Topics</a>
        </p>
        
        {% block content %}{% endblock content %}

Біз басты бетке ❶ сілтемеден кейін сызықша қосамыз, содан кейін қайтадан {% url %} үлгі тегін ❷ пайдаланып тақырыптар бетіне сілтеме қосамыз. Бұл жол Django-ға learning_logs/urls.py ішіндегі 'topics' атымен URL үлгісіне сәйкес сілтеме жасауды ұсынады.

Енді браузерде басты бетті жаңартқанда, сіз Тақырыптар сілтемесін көресіз. Сілтемені басқан кезде, 18-4-сурет-ге ұқсас бетті көресіз.

18-4-сурет: тақырыптар беті

Жеке тақырып беттері

Содан кейін тақырып атауын және сол тақырыпқа арналған барлық жазбаларды көрсететін бір тақырыпқа назар аудара алатын бетті жасауымыз керек. Біз жаңа URL үлгісін анықтаймыз, көрініс жазамыз және үлгі жасаймыз. Сондай-ақ біз таңбаланған тізімдегі әрбір элемент өзінің сәйкес тақырып бетіне сілтеме жасайтындай етіп тақырыптар бетін өзгертеміз.

Тақырыптың URL үлгісі

Тақырып бетінің URL үлгісі алдыңғы URL үлгілерінен сәл өзгеше, себебі ол қандай тақырып сұралғанын көрсету үшін тақырыптың id атрибутын пайдаланады. Мысалы, егер пайдаланушы шахмат тақырыбының егжей-тегжейлі бетін көргісі келсе (бұл жерде id 1), URL мекенжайы http://localhost:8000/topics/1/ болады. . Міне, осы URL мекенжайына сәйкес келетін үлгі, оны learning_logs/urls.py ішіне орналастыру керек:

learning_logs/urls.py

--snip/код үзіндісі--
        urlpatterns = [
            --snip/код үзіндісі--
            # Detail page for a single topic.
            path('topics/<int:topic_id>/', views.topic, name='topic'),
        ]

Осы URL үлгісіндегі 'topics/<int:topic_id>/' жолын қарастырайық. Тіркестің бірінші бөлігі Джангоға негізгі URL мекенжайынан кейін тақырыптар сөзі бар URL мекенжайларын іздеуді ұсынады. Тіркестің екінші бөлігі /<int:topic_id>/ екі қиғаш сызық арасындағы бүтін санға сәйкес келеді және бүтін мәнді topic_id деп аталатын аргументке тағайындайды.

Django осы үлгіге сәйкес URL мекенжайын тапқанда, ол аргумент ретінде topic_id мәніне тағайындалған topic() көру функциясын шақырады. Функция ішінде дұрыс тақырыпты алу үшін topic_id мәнін қолданамыз.

Тақырып көрінісі

topic() функциясы дерекқордан тақырыпты және барлық қатысты жазбаларды алуы керек, бұл Джанго қабықшасында бұрын жасағандай:

views.py

--snip/код үзіндісі--
         def topic(request, topic_id):
            """Бір тақырыпты және оның барлық жазбаларын көрсетіңіз."""
             topic = Topic.objects.get(id=topic_id)
             entries = topic.entry_set.order_by('-date_added')
             context = {'topic': topic, 'entries': entries}
             return render(request, 'learning_logs/topic.html', context)

Бұл request нысанынан басқа параметрді қажет ететін бірінші көру функциясы. Функция /<int:topic_id>/ өрнегі арқылы алынған мәнді қабылдайды және оны topic_id ❶-ге тағайындайды. Содан кейін біз Django қабықшасындағы ❷ сияқты тақырыпты алу үшін get() қолданамыз. Содан кейін біз осы тақырыпқа қатысты барлық жазбаларды аламыз және оларды date_added ❸ сәйкес реттейміз. date_added алдындағы минус таңбасы нәтижелерді кері ретпен сұрыптайды, бұл ең соңғы жазбаларды алдымен көрсетеді. Тақырыпты және жазбаларды контекст сөздігінде ❹ сақтаймыз және render() қызметін render нысанымен, topic.html деп шақырамыз үлгісі және контекст сөздігі ❺.

Тақырып үлгісі

Үлгі тақырыптың атын және жазбаларды көрсетуі керек. Сондай-ақ, бұл тақырып бойынша әлі ешқандай жазбалар жасалмаған болса, пайдаланушыға хабарлауымыз керек.

topic.html

{% extends 'learning_logs/base.html' %}
        
        {% block content %}
        
           <p>Topic: {{ topic.text }}</p>
        
          <p>Entries:</p>
           <ul>
             {% for entry in entries %}
              <li>
                 <p>{{ entry.date_added|date:'M d, Y H:i' }}</p>
                 <p>{{ entry.text|linebreaks }}</p>
              </li>
             {% empty %}
              <li>There are no entries for this topic yet.</li>
            {% endfor %}
          </ul>
        
        {% endblock content %}

Біз жобаның барлық беттері үшін жасайтындай base.html кеңейтеміз. Содан кейін біз сұралған тақырыптың text атрибутын ❶ көрсетеміз. topic айнымалысы қолжетімді, себебі ол контекст сөздігіне енгізілген. Содан кейін біз әрбір жазбаны көрсету үшін ❷ таңбаланған тізімді бастаймыз және алдыңғы тақырыптарда болғандай ❸ оларды айналдырамыз.

Әр таңбалауыш ақпараттың екі бөлігін көрсетеді: уақыт белгісі және әрбір жазбаның толық мәтіні. Уақыт белгісі ❹ үшін біз қосылған күні атрибутының мәнін көрсетеміз. Django үлгілерінде тік сызық (|) үлгі сүзгіні көрсетеді — көрсету процесі кезінде үлгі айнымалы мәніндегі мәнді өзгертетін функция. date:'M d, Y H:i' сүзгісі уақыт белгілерін 2022 жылғы 1 қаңтар 23:00 пішімінде көрсетеді. Келесі жол ағымдағы жазбаның text атрибутының мәнін көрсетеді. linebreaks сүзгісі ❺ ұзақ мәтіндік жазбаларға үзіліссіз мәтін блогын көрсетудің орнына браузерлер түсінетін пішімдегі жол үзілімдерін қамтуын қамтамасыз етеді. Пайдаланушыға ешбір жазба жасалмағанын хабарлайтын хабарды басып шығару үшін біз қайтадан {% empty %} үлгі тегін ❻ пайдаланамыз.

Тақырыптар бетіндегі сілтемелер

Браузерде тақырып бетін қарастырмас бұрын, әрбір тақырып сәйкес бетке сілтеме жасайтындай етіп тақырыптар үлгісін өзгертуіміз керек. Міне, topics.html файлына өзгерту қажет:

topics.html

--snip/код үзіндісі--
            {% for topic in topics %}
              <li>
                <a href="{% url 'learning_logs:topic' topic.id %}">
                  {{ topic.text }}</a></li>
              </li>
            {% empty %}
        --snip/код үзіндісі--

Біз URL үлгісі тегін 'topic' атауымен learning_logs ішіндегі URL үлгісіне негізделген дұрыс сілтемені жасау үшін пайдаланамыз. Бұл URL үлгісі topic_id аргументін қажет етеді, сондықтан URL үлгісі тегіне topic.id атрибутын қосамыз. Енді тақырыптар тізіміндегі әрбір тақырып http://localhost:8000/topics/1/ сияқты тақырып бетіне сілтеме болып табылады.

Тақырыптар бетін жаңартып, тақырыпты басқан кезде, 18-5-сурет сияқты көрінетін бетті көресіз.

18-5-сурет: тақырыптың барлық жазбаларын көрсететін бір тақырыпқа арналған егжей-тегжейлі бет

Қорытынды

Бұл тарауда сіз Django құрылымын пайдаланып қарапайым веб-бағдарламаны құруды қалай бастау керектігін үйрендіңіз. Сіз жобаның қысқаша сипаттамасын көрдіңіз, виртуалды ортаға Django орнаттыңыз, жобаны орнаттыңыз және жобаның дұрыс орнатылғанын тексердіңіз. Қолданбаға арналған деректерді көрсету үшін қолданбаны және анықталған үлгілерді орнатасыз. Сіз дерекқорлар туралы және модельдеріңізге өзгеріс енгізгеннен кейін Django бағдарламасының дерекқорды тасымалдауға қалай көмектесетінін білдіңіз. Сіз әкімші сайты үшін суперпайдаланушы жасадыңыз және кейбір бастапқы деректерді енгізу үшін әкімші сайтын пайдаландыңыз.

Сонымен қатар терминал сеансында жоба деректерімен жұмыс істеуге мүмкіндік беретін Django қабығын зерттедіңіз. Сіз URL мекенжайларын анықтауды, көру функцияларын жасауды және сайтыңызға беттер жасау үшін үлгілерді жазуды үйрендіңіз. Сондай-ақ жеке үлгілердің құрылымын жеңілдету және жоба дамып жатқанда сайтты өзгертуді жеңілдету үшін үлгі мұрасын пайдаландыңыз.

19-тарауда сіз пайдаланушыларға жаңа тақырыптар мен жазбаларды қосуға және бар жазбаларды өзгертуге мүмкіндік беретін интуитивті, пайдаланушыға ыңғайлы беттер жасайсыз. әкімші сайты арқылы. Сондай-ақ пайдаланушыларды тіркеу жүйесін қосасыз, бұл пайдаланушыларға тіркелгі жасауға және өздерінің оқу журналын жасауға мүмкіндік береді. Бұл веб-қолданбаның жүрегі — пайдаланушылардың кез-келген саны өзара әрекеттесе алатын нәрсені жасау мүмкіндігі.

User Accounts

ITUniver

19
User Accounts

Веб қолданбасының негізінде әлемнің кез-келген жеріндегі кез-келген пайдаланушының қолданбаға тіркелгіні тіркеп, оны пайдалана бастау мүмкіндігі бар. Бұл тарауда пайдаланушылар өздерінің тақырыптары мен жазбаларын қосып, бұрыннан бар жазбаларды өңдей алатындай пішіндерді құрастырасыз. Сондай-ақ, сіз Django пішінге негізделген беттерге қарсы әдеттегі шабуылдардан қалай қорғайтынын білесіз, осылайша қолданбаларды қорғау туралы ойлануға көп уақыт жұмсамайсыз.

Сонымен қатар пайдаланушының аутентификация жүйесін енгізесіз. Сіз пайдаланушыларға тіркелгі жасау үшін тіркеу бетін жасайсыз, содан кейін белгілі бір беттерге кіруді тек жүйеге кірген пайдаланушыларға шектейсіз. Содан кейін пайдаланушылар тек өз деректерін көре алатындай кейбір көру функцияларын өзгертесіз. Сіз пайдаланушылардың деректерін қауіпсіз және қауіпсіз сақтауды үйренесіз.

Пайдаланушыларға деректерді енгізуге рұқсат беру

Тіркелгілерді жасау үшін аутентификация жүйесін жасамас бұрын, алдымен пайдаланушыларға өз деректерін енгізуге мүмкіндік беретін кейбір беттерді қосамыз. Біз пайдаланушыларға жаңа тақырып қосу, жаңа жазба қосу және алдыңғы жазбаларын өңдеу мүмкіндігін береміз.

Қазір тек суперпайдаланушы әкімші сайты арқылы деректерді енгізе алады. Біз пайдаланушылардың әкімші сайтымен өзара әрекеттесуін қаламаймыз, сондықтан пайдаланушыларға деректерді енгізуге мүмкіндік беретін беттерді құру үшін Django пішін құру құралдарын пайдаланамыз.

Жаңа тақырыптар қосу

Пайдаланушыларға жаңа тақырып қосуға рұқсат беруден бастайық. Пішінге негізделген бетті қосу бұрыннан жасалған беттерді қосу сияқты жұмыс істейді: URL мекенжайын анықтаймыз, көру функциясын жазамыз және үлгі жазамыз. Бір маңызды айырмашылық - пішіндерді қамтитын forms.py деп аталатын жаңа модульді қосу.

Тақырып үлгісі пішіні

Пайдаланушыға веб-бетке ақпаратты енгізуге және жіберуге мүмкіндік беретін кез-келген бет пішін деп аталатын HTML элементін қамтиды. Пайдаланушылар ақпаратты енгізген кезде, біз берілген ақпараттың деректердің дұрыс түрі екенін және серверімізді үзуге арналған код сияқты зиянды емес екенін тексеруіміз керек. Содан кейін біз жарамды ақпаратты өңдеп, дерекқордағы тиісті орынға сақтауымыз керек. Джанго бұл жұмыстың көп бөлігін автоматтандырады.

Джангода пішін құрудың ең қарапайым жолы - тарауда біз анықтаған үлгілердегі ақпаратты пайдаланатын ModelForm пайдалану. 18 пішімді автоматты түрде құру. Бірінші пішінді forms.py файлына жазыңыз, ол models.py сияқты бір каталогта жасалуы керек:

forms.py

from django import forms
        
        from .models import Topic
        
         class TopicForm(forms.ModelForm):
            class Meta:
                 model = Topic
                 fields = ['text']
                 labels = {'text': ''}

Біз алдымен forms модулін және біз жұмыс істейтін үлгіні, Тақырып импорттаймыз. Содан кейін forms.ModelForm ❶ ішінен мұраға алатын TopicForm деп аталатын классты анықтаймыз.

ModelForm-дың ең қарапайым нұсқасы Джангоға пішінді қай модельге негіздеу керектігін және пішінге қай өрістерді қосу керектігін айтатын кірістірілген Meta классынан тұрады. Мұнда пішін Тақырып үлгісіне ❷ негізделуі керек екенін және ол тек text өрісін ❸ қамтуы керек екенін көрсетеміз. Белгілер сөздігіндегі бос жол Джангоға text өрісі ❹ үшін белгіні жасамау керектігін айтады.

Жаңа тақырыптың URL мекенжайы

Жаңа беттің URL мекенжайы қысқа және сипаттамалы болуы керек. Пайдаланушы жаңа тақырып қосқысы келгенде, біз оны http://localhost:8000/new_topic/ мекенжайына жібереміз. Мұнда new_topic бетінің URL үлгісі берілген; оны learning_logs/urls.py ішіне қосыңыз:

learning_logs/urls.py

--snip/код үзіндісі--
        urlpatterns = [
            --snip/код үзіндісі--
            # Page for adding a new topic.
            path('new_topic/', views.new_topic, name='new_topic'),
        ]

This URL pattern sends requests to the view function new_topic(), which we’ll write next.

new_topic() көру функциясы

new_topic() функциясы екі түрлі жағдайды өңдеуі керек: new_topic бетіне арналған бастапқы сұраулар, бұл жағдайда ол бос пішінді көрсетуі керек. ; және пішінде ұсынылған кез-келген деректерді өңдеу. Жіберілген пішіндегі деректер өңделгеннен кейін ол пайдаланушыны тақырыптар бетіне қайта бағыттауы керек:

views.py

from django.shortcuts import render, redirect
        
        from .models import Topic
        from .forms import TopicForm
        
        --snip/код үзіндісі--
        def new_topic(request):
            """Жаңа тақырып қосу."""
             if request.method != 'POST':
                # No data submitted; create a blank form.
                 form = TopicForm()
            else:
                # POST data submitted; process data.
                 form = TopicForm(data=request.POST)
                 if form.is_valid():
                     form.save()
                     return redirect('learning_logs:topics')
        
            # Display a blank or invalid form.
             context = {'form': form}
            return render(request, 'learning_logs/new_topic.html', context)

Біз redirect функциясын импорттаймыз, оны пайдаланушы өз тақырыбын жібергеннен кейін тақырыптар бетіне қайта бағыттау үшін қолданамыз. Біз жаңа ғана жазған TopicForm пішінді де импорттаймыз.

GET және POST сұраулары

Қолданбаларды құру кезінде пайдаланатын сұраулардың екі негізгі түрі: GET және POST. Сіз тек серверден деректерді оқитын беттер үшін GET сұрауларын пайдаланасыз. Пайдаланушы ақпаратты пішін арқылы жіберу қажет болғанда әдетте POST сұрауларын пайдаланасыз. Біз барлық пішіндерімізді өңдеу үшін POST әдісін көрсететін боламыз. (Сұраулардың бірнеше басқа түрлері бар, бірақ біз оларды бұл жобада пайдаланбаймыз.)

new_topic() функциясы параметр ретінде request нысанын қабылдайды. Пайдаланушы бастапқыда осы бетті сұрағанда, оның шолғышы GET сұрауын жібереді. Пайдаланушы пішінді толтырып, жібергеннен кейін оның браузері POST сұрауын жібереді. Сұрауға байланысты пайдаланушы бос пішінді (GET) сұрап жатқанын немесе толтырылған пішінді (POST) өңдеуді сұрап жатқанын білеміз.

Сұрау әдісінің GET немесе POST ❶ екенін анықтау үшін if тестін қолданамыз. Егер сұрау әдісі POST болмаса, сұрау GET болуы мүмкін, сондықтан бос пішінді қайтаруымыз керек. (Егер бұл сұраудың басқа түрі болса, бос пішінді қайтару әлі де қауіпсіз.) Біз TopicForm ❷ данасын жасаймыз, оны form айнымалысына тағайындаймыз және пішінді контекст сөздігінде ❼ үлгіге енгізіңіз. TopicForm құру кезінде біз ешқандай аргумент қоспағандықтан, Django пайдаланушы толтыра алатын бос пішін жасайды.

Егер сұрау әдісі POST болса, else блогы пішінде жіберілген деректерді іске қосады және өңдейді. Біз TopicForm ❸ данасын жасаймыз және оған request.POST тағайындалған пайдаланушы енгізген деректерді жібереміз. Қайтарылатын form нысаны пайдаланушы жіберген ақпаратты қамтиды.

Жіберілген ақпаратты оның жарамдылығын тексермейінше дерекқорда сақтай алмаймыз ❹. is_valid() әдісі барлық қажетті өрістердің толтырылғанын (пішіндегі барлық өрістер әдепкі бойынша талап етіледі) және енгізілген деректердің күтілетін өріс түрлеріне сәйкес келетінін, мысалы, ұзындығын тексереді. text 200 таңбадан аз, біз 18-тарауда models.py көрсеткендей. Бұл автоматты тексеру бізге көп жұмысты үнемдейді. Егер бәрі жарамды болса, біз пішіннен деректерді дерекқорға жазатын save() ❺ деп шақыра аламыз.

Деректерді сақтағаннан кейін біз бұл беттен шыға аламыз. redirect() функциясы көрініс атауын алады және пайдаланушыны сол көрініспен байланысты бетке қайта бағыттайды. Мұнда пайдаланушы браузерін тақырыптар бетіне ❻ қайта бағыттау үшін redirect() пайдаланамыз, мұнда пайдаланушы жаңа ғана енгізген тақырыпты тақырыптар тізімінде көруі керек.

контекст айнымалысы көру функциясының соңында анықталады және бет келесіде жасайтын new_topic.html үлгісінің көмегімен көрсетіледі. Бұл код кез-келген if блогынан тыс орналастырылады; ол бос пішін жасалған болса іске қосылады және жіберілген пішін жарамсыз деп анықталған жағдайда іске қосылады. Жарамсыз пішін пайдаланушыға қолайлы деректерді жіберуге көмектесу үшін кейбір әдепкі қате хабарларын қамтиды.

Жаңа_тақырып үлгісі

Енді біз жаңа ғана жасаған пішінді көрсету үшін new_topic.html деп аталатын жаңа үлгі жасаймыз:

new_topic.html

{% extends "learning_logs/base.html" %}
        
        {% block content %}
          <p>Add a new topic:</p>
        
           <form action="{% url 'learning_logs:new_topic' %}" method='post'>
             {% csrf_token %}
             {{ form.as_div }}
             <button name="submit">Add topic</button>
          </form>
        
        {% endblock content %}

Бұл үлгі base.html кеңейтеді, сондықтан оқу журналындағы қалған беттермен бірдей негізгі құрылымға ие. HTML пішінін ❶ анықтау үшін <form></form> тегтерін қолданамыз. әрекет аргументі браузерге пішінде жіберілген деректерді қайда жіберу керектігін айтады; бұл жағдайда оны new_topic() көру функциясына қайта жібереміз. method аргументі браузерге деректерді POST сұрауы ретінде жіберуді ұсынады.

Django шаблон тегін {% csrf_token %} ❷ шабуылдаушылар серверге рұқсатсыз кіру үшін пішінді пайдалануын болдырмау үшін пайдаланады. (Шабуылдың бұл түрі сайт аралық сұрауды жалған жасау деп аталады.) Содан кейін пішінді көрсетеміз; мұнда сіз Джангоның пішінді көрсету сияқты белгілі бір тапсырмаларды қаншалықты қарапайым орындай алатынын көре аласыз. Пішінді автоматты түрде ❸ көрсетуге қажетті барлық өрістерді жасау үшін бізге тек Django үшін {{ form.as_div }} үлгі айнымалысын қосу керек. as_div модификаторы Django-ға барлық пішін элементтерін HTML <div></div> элементтері ретінде көрсетуді ұсынады; бұл пішінді ұқыпты көрсетудің қарапайым жолы.

Django пішіндер үшін жіберу түймешігін жасамайды, сондықтан пішінді ❹ жабу алдында біреуін анықтаймыз.

Жаңа_тақырып бетіне сілтеме

Кейін, тақырыптар бетіндегі new_topic бетіне сілтеме береміз:

topics.html

{% extends "learning_logs/base.html" %}
        
        {% block content %}
        
          <p>Topics</p>
        
          <ul>
            --snip/код үзіндісі--
          </ul>
        
          <a href="{% url 'learning_logs:new_topic' %}">Add a new topic</a>
        
        {% endblock content %}

Сілтемені бұрыннан бар тақырыптар тізімінен кейін орналастырыңыз. 19-1-сурет нәтиже пішінін көрсетеді; Өзіңіздің бірнеше жаңа тақырыптарыңызды қосу үшін пішінді пайдаланып көріңіз.

19-1-сурет: Жаңа тақырып қосу беті

Жаңа жазбаларды қосу

Енді пайдаланушы жаңа тақырып қоса алатындықтан, олар да жаңа жазбаларды қосқысы келеді. Біз қайтадан URL мекенжайын анықтаймыз, көру функциясын және үлгіні жазамыз және бетке сілтеме жасаймыз. Бірақ алдымен forms.py ішіне басқа класс қосамыз.

Енгізу үлгісі

Біз Entry үлгісімен байланыстырылған пішінді жасауымыз керек, бірақ бұл жолы TopicForm-дан сәл көбірек теңшеумен:

forms.py

from django import forms
        
        from .models import Topic, Entry
        
        class TopicForm(forms.ModelForm):
            --snip/код үзіндісі--
        
        class EntryForm(forms.ModelForm):
            class Meta:
                model = Entry
                fields = ['text']
                 labels = {'text': ''}
                 widgets = {'text': forms.Textarea(attrs={'cols': 80})}

Біз import амалынан Entry және Тақырып қосу үшін жаңартамыз. Біз EntryForm деп аталатын жаңа класс жасаймыз, ол forms.ModelForm ішінен мұрагер болады. EntryForm классында ол негізделген үлгіні және пішінге қосылатын өрісті көрсететін кірістірілген Meta классы бар. Біз қайтадан 'text' өрісіне бос белгіні ❶ береміз.

EntryForm үшін біз виджеттер атрибутын ❷ қосамыз. виджет - бұл бір Тіркесті мәтін ұясы, көп Тіркесті мәтін аймағы немесе ашылмалы тізім сияқты HTML пішін элементі. widgets атрибутын қосу арқылы сіз Django әдепкі виджет таңдауларын қайта анықтауға болады. Мұнда біз Джангоға әдепкі 40 бағанның орнына ені 80 баған болатын forms.Textarea элементін пайдалануды айтып отырмыз. Бұл пайдаланушыларға мазмұнды жазба жазуға жеткілікті орын береді.

Жаңа_енгізудің URL мекенжайы

Жаңа жазбалар белгілі бір тақырыппен байланысты болуы керек, сондықтан жаңа жазба қосу үшін URL мекенжайына topic_id аргументін қосу керек. Міне, сіз learning_logs/urls.py ішіне қосатын URL мекенжайы:

learning_logs/urls.py

--snip/код үзіндісі--
        urlpatterns = [
            --snip/код үзіндісі--
            # Page for adding a new entry.
            path('new_entry/<int:topic_id>/', views.new_entry, name='new_entry'),
        ]

Бұл URL үлгісі http://localhost:8000/new_entry/id/ пішіні бар кез-келген URL мекенжайына сәйкес келеді, мұнда id - тақырып идентификаторына сәйкес келетін сан. <int:topic_id> коды сандық мәнді алады және оны topic_id айнымалысына тағайындайды. Осы үлгіге сәйкес URL сұралғанда, Django сұрауды және тақырып идентификаторын new_entry() көру функциясына жібереді.

new_entry() көру функциясы

new_entry көру функциясы жаңа тақырып қосу функциясына ұқсас. views.py файлыңызға келесі кодты қосыңыз:

views.py

from django.shortcuts import render, redirect
        
        from .models import Topic
        from .forms import TopicForm, EntryForm
        
        --snip/код үзіндісі--
        def new_entry(request, topic_id):
            """Белгілі бір тақырыпқа жаңа жазба қосу."""
             topic = Topic.objects.get(id=topic_id)
        
             if request.method != 'POST':
                # No data submitted; create a blank form.
                 form = EntryForm()
            else:
                # POST data submitted; process data.
                 form = EntryForm(data=request.POST)
                if form.is_valid():
                     new_entry = form.save(commit=False)
                     new_entry.topic = topic
                    new_entry.save()
                     return redirect('learning_logs:topic', topic_id=topic_id)
        
            # Display a blank or invalid form.
            context = {'topic': topic, 'form': form}
            return render(request, 'learning_logs/new_entry.html', context)

Біз import амалынан жаңа жасаған EntryForm қосу үшін жаңартамыз. new_entry() анықтамасында URL мекенжайынан алатын мәнді сақтау үшін topic_id параметрі бар. Бізге бетті көрсету және пішін деректерін өңдеу үшін тақырып қажет, сондықтан дұрыс тақырып нысанын ❶ алу үшін topic_id пайдаланамыз.

Одан кейін сұрау әдісі POST немесе GET ❷ екенін тексереміз. if блогы, егер бұл GET сұрауы болса, орындалады және EntryForm ❸ бос данасын жасаймыз.

Егер сұрау әдісі POST болса, біз EntryForm данасын жасау арқылы деректерді өңдейміз, ол request нысанынан ❹ POST деректерімен толтырылады. Содан кейін пішіннің жарамдылығын тексереміз. Олай болса, дерекқорға сақтамас бұрын жазба нысанының topic атрибутын орнатуымыз керек. save() деп атаған кезде, Джангоға жаңа енгізу нысанын жасауды және оны new_entry тағайындауды айту үшін commit=False ❺ аргументін қосамыз. , оны әлі дерекқорға сақтамай. Біз ❻ функциясының басында дерекқордан алынған тақырыпқа new_entry topic атрибутын орнаттық. Содан кейін біз жазбаны дерекқорға дұрыс байланыстырылған тақырыппен сақтай отырып, дәлелсіз save() деп атаймыз.

redirect() шақыруы екі аргументті қажет етеді: біз қайта бағыттағымыз келетін көрініс атауы және көрініс функциясы қажет ететін аргумент ❼. Мұнда біз topic()-ге қайта бағыттап жатырмыз, ол үшін topic_id аргументі қажет. Содан кейін бұл көрініс пайдаланушы жазба жасаған тақырып бетін көрсетеді және олар жазбалар тізімінде өзінің жаңа жазбасын көруі керек.

Функцияның соңында контекст сөздігін жасаймыз және бетті new_entry.html үлгісін қолданып көрсетеміз. Бұл код бос пішін үшін немесе жіберілген, бірақ жарамсыз болып шыққан пішін үшін орындалады.

Жаңа_енгізу үлгісі

Келесі кодта көріп отырғаныңыздай, new_entry үлгісі new_topic үлгісіне ұқсас:

new_entry.html

{% extends "learning_logs/base.html" %}
        
        {% block content %}
        
           <p><a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a></p>
        
          <p>Add a new entry:</p>
           <form action="{% url 'learning_logs:new_entry' topic.id %}" method='post'>
            {% csrf_token %}
            {{ form.as_div }}
            <button name='submit'>Add entry</button>
          </form>
        
        {% endblock content %}

Біз тақырыпты беттің жоғарғы жағында ❶ көрсетеміз, осылайша пайдаланушы қай тақырыпқа жазба қосып жатқанын көре алады. Тақырып сонымен қатар сол тақырыптың негізгі бетіне кері сілтеме ретінде әрекет етеді.

Пішіннің әрекет аргументі URL мекенжайындағы topic.id мәнін қамтиды, сондықтан көру функциясы жаңа жазбаны дұрыс тақырыппен ❷ байланыстыра алады. Бұдан басқа, бұл үлгі new_topic.html сияқты көрінеді.

Жаңа_енгізу бетіне сілтеме

Кейін, тақырып үлгісіне әрбір тақырып бетінен new_entry бетіне сілтеме қосуымыз керек:

topic.html

{% extends "learning_logs/base.html" %}
        
        {% block content %}
        
          <p>Topic: {{ topic }}</p>
        
          <p>Entries:</p>
          <p>
            <a href="{% url 'learning_logs:new_entry' topic.id %}">Add new entry</a>
          </p>
        
          <ul>
          --snip/код үзіндісі--
          </ul>
        
        {% endblock content %}

Жазбаларды қосу сілтемесін жазбаларды көрсетудің алдында ғана орналастырамыз, себебі жаңа жазба қосу осы беттегі ең көп таралған әрекет болады. 19-2-сурет new_entry бетін көрсетеді. Енді пайдаланушылар жаңа тақырыптарды және әр тақырып үшін қалағанынша жазбаларды қоса алады. Өзіңіз жасаған кейбір тақырыптарға бірнеше жазба қосу арқылы new_entry бетін қолданып көріңіз.

19-2-сурет: жаңа_енгізу беті

Жазбаларды өңдеу

Енді пайдаланушылар өздері қосқан жазбаларды өңдей алатындай бет жасаймыз.

edit_entry URL мекенжайы

Беттің URL мекенжайы өңделетін жазбаның идентификаторынан өтуі керек. Мұнда learning_logs/urls.py:

urls.py

--snip/код үзіндісі--
        urlpatterns = [
            --snip/код үзіндісі--
            # Page for editing an entry.
            path('edit_entry/<int:entry_id>/', views.edit_entry, name='edit_entry'),
        ]

Бұл URL үлгісі http://localhost:8000/edit_entry/id/ сияқты URL мекенжайларына сәйкес келеді. Мұнда id мәні entry_id параметріне тағайындалады. Django осы пішімге сәйкес келетін сұрауларды edit_entry() көру функциясына жібереді.

edit_entry() көру функциясы

edit_entry беті GET сұрауын алған кезде, edit_entry() функциясы жазбаны өңдеуге арналған пішінді қайтарады. Бет өңделген жазба мәтіні бар POST сұрауын алғанда, ол өзгертілген мәтінді дерекқорға сақтайды:

views.py

from django.shortcuts import render, redirect
        
        from .models import Topic, Entry
        from .forms import TopicForm, EntryForm
        --snip/код үзіндісі--
        
        def edit_entry(request, entry_id):
            """Бар жазбаны өңдеу."""
             entry = Entry.objects.get(id=entry_id)
            topic = entry.topic
        
            if request.method != 'POST':
                # Initial request; pre-fill form with the current entry.
                 form = EntryForm(instance=entry)
            else:
                # POST data submitted; process data.
                 form = EntryForm(instance=entry, data=request.POST)
                if form.is_valid():
                     form.save()
                     return redirect('learning_logs:topic', topic_id=topic.id)
        
            context = {'entry': entry, 'topic': topic, 'form': form}
            return render(request, 'learning_logs/edit_entry.html', context)

Алдымен Entry үлгісін импорттаймыз. Содан кейін біз пайдаланушы өңдегісі келетін ❶ жазба нысанын және осы жазбамен байланысты тақырыпты аламыз. GET сұрауы үшін орындалатын if блогында біз EntryForm данасын instance=entry ❷ аргументі арқылы жасаймыз. Бұл аргумент Джангоға бар енгізу нысанындағы ақпаратпен алдын ала толтырылған пішінді жасауды ұсынады. Пайдаланушы өзінің бар деректерін көреді және сол деректерді өңдей алады.

POST сұрауын өңдеу кезінде біз instance=entry және data=request.POST аргументтерін ❸ өткіземіз. Бұл аргументтер Джангоға request.POST сайтындағы кез-келген сәйкес деректермен жаңартылған, бар енгізу нысанымен байланысты ақпарат негізінде пішін данасын жасауды ұсынады. Содан кейін пішіннің жарамдылығын тексереміз; егер солай болса, біз save() деп дәлелдерсіз шақырамыз, себебі жазба дұрыс тақырыппен ❹ байланыстырылған. Содан кейін біз topic бетіне қайта бағыттаймыз, мұнда пайдаланушы өңдеген жазбаның жаңартылған нұсқасын көруі керек ❺.

Егер біз жазбаны өңдеуге арналған бастапқы пішінді көрсетсек немесе жіберілген пішін жарамсыз болса, контекст сөздігін жасаймыз және бетті edit_entry.html арқылы көрсетеміз. > үлгі.

edit_entry үлгісі

Кейін, біз edit_entry.html үлгісін жасаймыз, ол new_entry.html-ге ұқсас:

edit_entry.html

{% extends "learning_logs/base.html" %}
        
        {% block content %}
        
          <p><a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a></p>
        
          <p>Edit entry:</p>
        
           <form action="{% url 'learning_logs:edit_entry' entry.id %}" method='post'>
            {% csrf_token %}
            {{ form.as_div }}
             <button name="submit">Save changes</button>
          </form>
        
        {% endblock content %}

әрекет аргументі пішінді ❶ өңдеу үшін edit_entry() функциясына қайта жібереді. Біз entry.id аргумент ретінде {% url %} тегіне қосамыз, осылайша көру функциясы дұрыс енгізу нысанын өзгерте алады. Пайдаланушыға жаңа жазба жасамай, өңдеулерді сақтап жатқанын еске салу үшін жіберу түймесін Өзгерістерді сақтау деп белгілейміз ❷.

edit_entry бетіне сілтеме

Енді тақырып бетіндегі әрбір жазба үшін edit_entry бетіне сілтеме қосуымыз керек:

topic.html

--snip/код үзіндісі--
            {% for entry in entries %}
              <li>
                <p>{{ entry.date_added|date:'M d, Y H:i' }}</p>
                <p>{{ entry.text|linebreaks }}</p>
                <p>
                  <a href="{% url 'learning_logs:edit_entry' entry.id %}">
                   Edit entry</a></p>
              </li>
        --snip/код үзіндісі--

Әр жазбаның күні мен мәтіні көрсетілгеннен кейін өңдеу сілтемесін қосамыз. {% url %} үлгі тегін циклдегі ағымдағы жазбаның идентификатор атрибутымен бірге edit_entry аталатын URL үлгісінің URL мекенжайын анықтау үшін пайдаланамыз entry.id. Жазбаны өңдеу сілтеме мәтіні беттегі әрбір жазбадан кейін пайда болады. 19-3-сурет осы сілтемелер арқылы тақырып беті қалай көрінетінін көрсетеді.

19-3-сурет: Енді әрбір жазбада сол жазбаны өңдеуге арналған сілтеме бар.

Оқыту журналында қазір қажетті функциялардың көпшілігі бар. Пайдаланушылар тақырыптар мен жазбаларды қоса алады және олар қалаған жазбалардың кез-келген жинағын оқи алады. Келесі бөлімде біз пайдаланушыларды тіркеу жүйесін енгіземіз, осылайша кез-келген адам Learning Log арқылы тіркелгі жасап, өз тақырыптары мен жазбаларын жасай алады.

Пайдаланушы тіркелгілерін орнату

Бұл бөлімде адамдар тіркелгіні тіркей, жүйеге кіріп, жүйеден шыға алатындай пайдаланушыны тіркеу және авторизациялау жүйесін орнатамыз. Біз пайдаланушылармен жұмыс істеуге қатысты барлық функцияларды қамтитын жаңа қолданба жасаймыз. Мүмкіндігінше көп жұмысты орындау үшін біз Django бағдарламасына енгізілген әдепкі пайдаланушы аутентификация жүйесін қолданамыз. Әр тақырып белгілі бір пайдаланушыға тиесілі болуы үшін Тақырып үлгісін де аздап өзгертеміз.

Тіркелгілер қолданбасы

Біз startapp пәрменін пайдаланып accounts деп аталатын жаңа қолданба жасаудан бастаймыз:

(ll_env)learning_log$ python manage.py startapp accounts
        (ll_env)learning_log$ ls
         accounts db.sqlite3 learning_logs ll_env ll_project manage.py
        (ll_env)learning_log$ ls accounts
         __init__.py admin.py apps.py migrations models.py tests.py views.py

Әдепкі аутентификация жүйесі пайдаланушы тіркелгілері тұжырымдамасының айналасында құрылған, сондықтан accounts атауын пайдалану әдепкі жүйемен біріктіруді жеңілдетеді. Мұнда көрсетілген startapp пәрмені құрылымы learning_logs қолданбасына ❷ ұқсас accounts ❶ деп аталатын жаңа каталог жасайды.

Settings.py файлына есептік жазбаларды қосу

Бізге жаңа қолданбаны settings.py ішіндегі INSTALLED_APPS қолданбасына қосу керек, мысалы:

settings.py

--snip/код үзіндісі--
        INSTALLED_APPS = [
            # My apps
            'learning_logs',
            'accounts',
        
            # Default django apps.
            --snip/код үзіндісі--
        ]
        --snip/код үзіндісі--

Енді Django жалпы жобаға accounts қолданбасын қосады.

Тіркелгілердегі URL мекенжайларын қосу

Одан кейін біз urls.py түбірін өзгертуіміз керек, сондықтан оған accounts қолданбасы үшін жазатын URL мекенжайлары кіреді:

ll_project/urls.py

from django.contrib import admin
        from django.urls import path, include
        
        urlpatterns = [
            path('admin/', admin.site.urls),
            path('accounts/', include('accounts.urls')),
            path('', include('learning_logs.urls')),
        ]

Біз accounts ішінен urls.py файлын қосу үшін Тіркесті қосамыз. Бұл жол http://localhost:8000/accounts/login/ сияқты accounts сөзінен басталатын кез-келген URL мекенжайына сәйкес келеді.

Кіру беті

Алдымен кіру бетін енгіземіз. Біз Django ұсынған әдепкі login көрінісін қолданамыз, сондықтан бұл қолданбаның URL үлгісі сәл басқаша көрінеді. ll_project/accounts/ каталогында жаңа urls.py файлын жасаңыз және оған келесіні қосыңыз:

accounts/urls.py

"""Тіркелгілер үшін URL үлгілерін анықтайды."""
        
        from django.urls import path, include
        
        app_name = 'accounts'
        urlpatterns = [
            # Include default auth urls.
            path('', include('django.contrib.auth.urls')),
        ]

Біз path функциясын импорттаймыз, содан кейін Django анықтаған кейбір әдепкі аутентификация URL мекенжайларын қосу үшін include функциясын импорттаймыз. Бұл әдепкі URL мекенжайлары 'login' және 'login' сияқты аталған URL үлгілерін қамтиды. Біз app_name айнымалы мәнін 'accounts' етіп орнаттық, осылайша Django бұл URL мекенжайларын басқа қолданбаларға тиесілі URL мекенжайларынан ажырата алады. Тіпті accounts қолданбасының urls.py файлына енгізілген Django ұсынған әдепкі URL мекенжайлары accounts аттар кеңістігі арқылы қол жетімді болады.

Кіру бетінің үлгісі http://localhost:8000/accounts/login/ URL мекенжайына сәйкес келеді. Django осы URL мекенжайын оқығанда, accounts сөзі Джангоға accounts/urls.py ішінен қарауды, ал login оған Джанго мекенжайына сұрау жіберу керектігін айтады. әдепкі логин көрінісі.

Кіру үлгісі

Пайдаланушы кіру бетін сұраған кезде, Django әдепкі көрініс функциясын пайдаланады, бірақ біз әлі де бет үлгісін беруіміз керек. Әдепкі аутентификация көріністері регистрация деп аталатын каталогтың ішінен үлгілерді іздейді, сондықтан бізге сол каталогты жасау керек болады. ll_project/accounts/ каталогының ішінде үлгілер деп аталатын каталог жасаңыз; оның ішінде регистрация деп аталатын басқа каталог жасаңыз. Міне, ll_project/accounts/templates/registration ішінде сақталуы керек login.html үлгісі:

login.html

{% extends 'learning_logs/base.html' %}
        
        {% block content %}
        
           {% if form.errors %}
            <p>Your username and password didn't match. Please try again.</p>
          {% endif %}
        
           <form action="{% url 'accounts:login' %}" method='post'>
            {% csrf_token %}
             {{ form.as_div }}
        
             <button name="submit">Log in</button>
          </form>
        
        {% endblock content %}

Бұл үлгі base.html кеңейтеді, бұл жүйеге кіру беті сайттың қалған бөлігімен бірдей көрініс пен сезімге ие болуын қамтамасыз етеді. Бір қолданбадағы үлгі басқа қолданбадағы үлгіден мұралануы мүмкін екенін ескеріңіз.

Егер пішіннің errors атрибуты орнатылған болса, пайдаланушы аты мен құпия сөз тіркесімі дерекқорда сақталған ештеңеге сәйкес келмейтінін хабарлайтын қате туралы хабарды ❶ көрсетеміз.

Біз жүйеге кіру көрінісі пішінді өңдеуді қалаймыз, сондықтан әрекет аргументін кіру бетінің URL мекенжайы ретінде орнатамыз ❷. Жүйеге кіру көрінісі үлгіге form нысанын жібереді және пішінді ❸ көрсету және жіберу түймешігін ❹ қосу бізге байланысты.

LOGIN_REDIRECT_URL параметрі

Пайдаланушы жүйеге сәтті кіргеннен кейін, Django сол пайдаланушыны қайда жіберу керектігін білуі керек. Біз мұны параметрлер файлында басқарамыз.

Келесі кодты settings.py соңына қосыңыз:

settings.py

--snip/код үзіндісі--
        # My settings.
        LOGIN_REDIRECT_URL = 'learning_logs:index'

Барлық әдепкі параметрлермен settings.py ішінде жаңа параметрлерді қосып жатқан бөлімді алып тастау пайдалы. Біз қосатын бірінші жаңа параметр - LOGIN_REDIRECT_URL, ол Django-ға сәтті кіру әрекетінен кейін қай URL мекенжайын қайта бағыттау керектігін айтады.

Кіру бетіне сілтеме

Кіру сілтемесін base.html сайтына қосайық, осылайша ол әр бетте пайда болады. Пайдаланушы жүйеге кірген кезде сілтеменің көрсетілуін қаламаймыз, сондықтан оны {% if %} тегіне кірістіреміз:

base.html

<p>
          <a href="{% url 'learning_logs:index' %}">Learning Log</a> -
          <a href="{% url 'learning_logs:topics' %}">Topics</a> -
           {% if user.is_authenticated %}
             Hello, {{ user.username }}.
          {% else %}
             <a href="{% url 'accounts:login' %}">Log in</a>
          {% endif %}
        </p>
        
        {% block content %}{% endblock content %}

Django аутентификация жүйесінде әрбір үлгіде әрқашан is_authentication атрибуттары бар қол жетімді user нысаны бар: атрибут True болады, егер пайдаланушы жүйеге кірді, егер ол кірмеген болса, False. Бұл атрибут аутентификацияланған пайдаланушыларға бір хабарды, ал басқасын расталмаған пайдаланушыларға көрсетуге мүмкіндік береді.

Бұл жерде біз қазір жүйеге кірген пайдаланушыларға сәлемдесуді көрсетеміз ❶. Түпнұсқалығы расталған пайдаланушылардың қосымша username атрибуттары бар, біз оны сәлемдесуді жекелендіру және пайдаланушыға жүйеге кіргенін еске салу үшін қолданамыз ❷. Аутентификациядан өтпеген пайдаланушылар үшін біз кіру бетіне ❸ сілтемесін көрсетеміз.

Кіру бетін пайдалану

Біз пайдаланушы тіркелгісін орнатып қойғанбыз, сондықтан бет жұмыс істейтінін көру үшін жүйеге кірейік. http://localhost:8000/admin/ бетіне өтіңіз. Әкімші ретінде жүйеге әлі де кірсеңіз, тақырыптан шығу сілтемесін тауып, оны басыңыз.

Жүйеден шыққан кезде http://localhost:8000/accounts/login/ бетіне өтіңіз. 19-4-сурет-де көрсетілгенге ұқсас кіру бетін көруіңіз керек. Бұрын орнатқан пайдаланушы аты мен құпия сөзді енгізіңіз, сонда сіз бастапқы бетке оралуыңыз керек. Басты беттегі тақырып пайдаланушы атыңызбен жекелендірілген сәлемдемені көрсетуі керек.

19-4-сурет: кіру беті

Шығу

Енді пайдаланушыларға жүйеден шығу жолын қамтамасыз ету керек. Шығу сұраулары POST сұраулары ретінде жіберілу керек, сондықтан base.html ішіне шағын жүйеден шығу пішінін қосамыз. Пайдаланушылар жүйеден шығу түймесін басқанда, олар жүйеден шыққанын растайтын бетке өтеді.

base.html файлына шығу пішінін қосу

Жүйеден шығу пішінін base.html бетіне қосамыз, сондықтан ол әр бетте қолжетімді болады. Біз оны басқа if блогына қосамыз, сондықтан оны жүйеге кірген пайдаланушылар ғана көре алады:

base.html

--snip/код үзіндісі--
        {% block content %}{% endblock content %}
        
        {% if user.is_authenticated %}
           <hr />
           <form action="{% url 'accounts:logout' %}" method='post'>
            {% csrf_token %}
            <button name='submit'>Log out</button>
          </form>
        {% endif %}

Шығуға арналған әдепкі URL үлгісі 'accounts/logout/' болып табылады. Дегенмен, сұрауды POST сұрауы ретінде жіберу керек; әйтпесе, шабуылдаушылар жүйеден шығу сұрауларын оңай мәжбүрлей алады. Шығу сұрауын POST пайдалану үшін жасау үшін біз қарапайым пішінді анықтаймыз.

Пішінді беттің төменгі жағында, көлденең ереже элементінің астына (<hr />) ❶ орналастырамыз. Бұл жүйеден шығу түймешігін әрқашан беттегі кез-келген басқа мазмұнның астында тұрақты күйде ұстаудың оңай жолы. Пішіннің өзінде оның action аргументі ретінде шығу URL мекенжайы және сұрау әдісі ❷ ретінде 'post' болады. Джангодағы әрбір пішін {% csrf_token %}, тіпті осы сияқты қарапайым пішінді қамтуы керек. Жіберу түймешігінен басқа бұл пішін бос.

LOGOUT_REDIRECT_URL параметрі

Пайдаланушы жүйеден шығу түймесін басқанда, Джанго оларды қайда жіберу керектігін білуі керек. Біз бұл әрекетті settings.py ішінде басқарамыз:

settings.py

--snip/код үзіндісі--
        # My settings.
        LOGIN_REDIRECT_URL = 'learning_logs:index'
        LOGOUT_REDIRECT_URL = 'learning_logs:index'

Осында көрсетілген LOGOUT_REDIRECT_URL параметрі Django жүйесіне жүйеден шыққан пайдаланушыларды бастапқы бетке қайта бағыттау керектігін айтады. Бұл олардың жүйеден шыққанын растаудың қарапайым жолы, себебі олар жүйеден шыққаннан кейін өз пайдаланушы атын көрмейтін болады.

Тіркеу беті

Одан кейін жаңа пайдаланушылар тіркеле алатындай бет жасаймыз. Біз Django әдепкі UserCreationForm қолданамыз, бірақ өзіміздің қарау функциясы мен үлгісін жазамыз.

Тіркеу URL мекенжайы

Келесі код тіркеу бетінің URL үлгісін береді, оны accounts/urls.py ішінде орналастыру керек:

accounts/urls.py

"""Тіркелгілер үшін URL үлгілерін анықтайды."""
        
        from django.urls import path, include
        
        from . import views
        
        app_name = accounts
        urlpatterns = [
            # Include default auth urls.
            path('', include('django.contrib.auth.urls')),
            # Registration page.
            path('register/', views.register, name='register'),
        ]

Біз көріністер модулін accounts ішінен импорттаймыз, ол бізге қажет, себебі тіркеу бетіне өз көрінісімізді жазып жатырмыз. Тіркеу бетінің үлгісі http://localhost:8000/accounts/register/ URL мекенжайына сәйкес келеді және біз жазғалы жатқан register() функциясына сұрау жібереді. .

Registr() көру функциясы

register() көру функциясы тіркеу беті бірінші рет сұралғанда бос тіркеу пішінін көрсетуі керек, содан кейін олар жіберілген кезде толтырылған тіркеу пішіндерін өңдеуі керек. Тіркеу сәтті болған кезде, функция жаңа пайдаланушыны да жүйеге енгізуі керек. Келесі кодты accounts/views.py ішіне қосыңыз:

accounts/views.py

from django.shortcuts import render, redirect
        from django.contrib.auth import login
        from django.contrib.auth.forms import UserCreationForm
        
        def register(request):
            """Жаңа пайдаланушыны тіркеу."""
            if request.method != 'POST':
                # Display blank registration form.
                 form = UserCreationForm()
            else:
                # Process completed form.
                 form = UserCreationForm(data=request.POST)
        
                 if form.is_valid():
                     new_user = form.save()
                    # Log the user in and then redirect to home page.
                     login(request, new_user)
                     return redirect('learning_logs:index')
        
            # Display a blank or invalid form.
            context = {'form': form}
            return render(request, 'registration/register.html', context)

Біз render() және redirect() функцияларын импорттаймыз, содан кейін пайдаланушыны жүйеге енгізу үшін login() функциясын импорттаймыз. егер олардың тіркеу деректері дұрыс болса. Біз сондай-ақ әдепкі UserCreationForm импорттаймыз. register() функциясында біз POST сұрауына жауап беріп жатқанымызды тексереміз. Егер олай болмаса, бастапқы деректері жоқ UserCreationForm данасын жасаймыз ❶.

Егер POST сұрауына жауап беретін болсақ, жіберілген деректер негізінде ❷ UserCreationForm данасын жасаймыз. Біз деректердің жарамдылығын тексереміз ❸ — бұл жағдайда пайдаланушы атында сәйкес таңбалар бар, құпия сөздер сәйкес келеді және пайдаланушы оларды жіберу кезінде зиянды әрекет жасағысы келмейді.

Егер жіберілген деректер жарамды болса, пайдаланушы аты мен құпия сөз хэшін дерекқорға сақтау үшін пішіннің save() әдісін шақырамыз ❹. save() әдісі жаңадан жасалған пайдаланушы нысанын қайтарады, оны біз new_user тағайындаймыз. Пайдаланушы ақпараты сақталған кезде, біз оларды жүйеге кіргіземіз, ол login() функциясын request және new_user нысандарымен ❺ жасайды. жаңа пайдаланушы үшін жарамды сеанс. Соңында біз пайдаланушыны ❻ басты бетке қайта бағыттаймыз, онда тақырыптағы жеке сәлемдесу оның тіркеуінің сәтті болғанын хабарлайды.

Функцияның соңында біз бос пішін немесе жарамсыз жіберілген пішін болатын бетті көрсетеміз.

Тізілім үлгісі

Енді тіркеу бетінің үлгісін жасаңыз, ол кіру бетіне ұқсас болады. Оны login.html:мен бірдей каталогта сақтауды ұмытпаңыз

register.html

{% extends "learning_logs/base.html" %}
        
        {% block content %}
        
          <form action="{% url 'accounts:register' %}" method='post'>
            {% csrf_token %}
            {{ form.as_div }}
        
            <button name="submit">Register</button>
          </form>
        
        {% endblock content %}

Бұл біз жазып жүрген басқа пішінге негізделген үлгілер сияқты болуы керек. Біз қайтадан as_div әдісін қолданамыз, осылайша Django пішіндегі барлық өрістерді, соның ішінде пішін дұрыс толтырылмаған жағдайда қате туралы хабарларды да дұрыс көрсетеді.

Тіркеу бетіне сілтеме

Кейін қазір жүйеге кірмеген кез-келген пайдаланушыға тіркеу бетінің сілтемесін көрсету үшін код қосамыз:

base.html

--snip/код үзіндісі--
          {% if user.is_authenticated %}
            Hello, {{ user.username }}.
          {% else %}
            <a href="{% url 'accounts:register' %}">Register</a> -
            <a href="{% url 'accounts:login' %}">Log in</a>
          {% endif %}
        --snip/код үзіндісі--

Енді жүйеге кірген пайдаланушылар жеке сәлемдесу мен жүйеден шығу түймешігін көреді. Жүйеге кірмеген пайдаланушылар тіркеу сілтемесін және кіру сілтемесін көреді. Түрлі пайдаланушы аттары бар бірнеше пайдаланушы тіркелгілерін жасау арқылы тіркеу бетін қолданып көріңіз.

Келесі бөлімде біз кейбір беттерді тек тіркелген пайдаланушыларға қолжетімді етіп шектейміз және әрбір тақырып белгілі бір пайдаланушыға тиесілі екеніне көз жеткіземіз.

Пайдаланушыларға өз деректерін иеленуге рұқсат беру

Пайдаланушылар оқу журналдарына жеке деректерді енгізе алуы керек, сондықтан қай деректер қай пайдаланушыға тиесілі екенін анықтау үшін жүйені жасаймыз. Содан кейін пайдаланушылар тек өз деректерімен жұмыс істей алатындай етіп белгілі бір беттерге кіруді шектейміз.

Біз Тақырып үлгісін әрбір тақырып белгілі бір пайдаланушыға тиесілі болатындай етіп өзгертеміз. Бұл жазбаларға да назар аударады, себебі әрбір жазба белгілі бір тақырыпқа жатады. Біз белгілі бір беттерге кіруді шектеуден бастаймыз.

@login_required арқылы кіруді шектеу

Django @login_required декораторы арқылы белгілі бір беттерге кіруді шектеуді жеңілдетеді. 11-тараудан еске сала кетейік, декоратор функцияның әрекет ету жолын өзгертетін функция анықтамасының алдында орналасқан директива. Мысалды қарастырайық.

Тақырыптар бетіне кіруді шектеу

Әр тақырып пайдаланушыға тиесілі болады, сондықтан тек тіркелген пайдаланушылар тақырыптар бетін сұрай алады. Келесі кодты learning_logs/views.py ішіне қосыңыз:

learning_logs/views.py

from django.shortcuts import render, redirect
        from django.contrib.auth.decorators import login_required
        
        from .models import Topic, Entry
        --snip/код үзіндісі--
        
        @login_required
        def topics(request):
            """Барлық тақырыптарды көрсету."""
            --snip/код үзіндісі--

Алдымен login_required() функциясын импорттаймыз. login_required() параметрін topics() көру функциясына @ символымен алдын ала login_required қою арқылы безендіруші ретінде қолданамыз. . Нәтижесінде Python login_required() ішіндегі кодты topics() ішіндегі кодтан бұрын іске қосуды біледі.

login_required() ішіндегі код пайдаланушының жүйеге кірген-кірмегенін тексереді, ал Django topics() ішіндегі кодты егер олар кірген болса ғана іске қосады. Пайдаланушы жүйеге кірмеген болса, олар кіру бетіне қайта бағытталады.

Бұл қайта бағыттауды орындау үшін, Django кіру бетін қайдан табуға болатынын білу үшін settings.py файлын өзгертуіміз керек. settings.py соңына келесіні қосыңыз:

settings.py

--snip/код үзіндісі--
        # My settings.
        LOGIN_REDIRECT_URL = 'learning_logs:index'
        LOGOUT_REDIRECT_URL = 'learning_logs:index'
        LOGIN_URL = 'accounts:login'

Енді аутентификацияланбаған пайдаланушы @login_required декораторымен қорғалған бетті сұраған кезде, Django пайдаланушыны settings.py ішіндегі LOGIN_URL арқылы анықталған URL мекенжайына жібереді. .

Бұл параметрді кез-келген пайдаланушы тіркелгілерінен шығып, басты бетке өту арқылы тексеруге болады. Жүйеге кіру бетіне қайта бағыттайтын Тақырыптар сілтемесін басыңыз. Содан кейін кез-келген тіркелгіге кіріп, басты беттен Тақырыптар сілтемесін қайта басыңыз. Тақырыптар бетіне кіре алуыңыз керек.

Оқыту журналы арқылы кіруді шектеу

Django беттерге кіруді шектеуді жеңілдетеді, бірақ сіз қай беттерді қорғау керектігін шешуіңіз керек. Алдымен қай беттерге шектеусіз болу керектігін ойластырған дұрыс, содан кейін жобадағы барлық басқа беттерді шектеңіз. Сіз шектен тыс кіруді оңай түзете аласыз және бұл құпия беттерді шектеусіз қалдырудан гөрі қауіпті емес.

Оқыту журналында біз басты бет пен тіркеу бетін шектеусіз сақтаймыз. Біз әрбір басқа бетке кіруді шектейміз.

Міне, index()-дан басқа әрбір көрініске қолданылатын @login_required декораторлары бар learning_logs/views.py:

learning_logs/views.py

--snip/код үзіндісі--
        @login_required
        def topics(request):
            --snip/код үзіндісі--
        
        @login_required
        def topic(request, topic_id):
            --snip/код үзіндісі--
        
        @login_required
        def new_topic(request):
            --snip/код үзіндісі--
        
        @login_required
        def new_entry(request, topic_id):
            --snip/код үзіндісі--
        
        @login_required
        def edit_entry(request, entry_id):
            --snip/код үзіндісі--

Жүйеден шыққан кезде осы беттердің әрқайсысына кіріп көріңіз; кіру бетіне қайта бағытталуыңыз керек. Сондай-ақ, new_topic сияқты беттерге сілтемелерді баса алмайсыз. Бірақ http://localhost:8000/new_topic/ URL мекенжайын енгізсеңіз, кіру бетіне қайта бағытталасыз. Жалпыға қолжетімді және жеке пайдаланушы деректеріне қатысты кез-келген URL мекенжайына кіруді шектеуіңіз керек.

Деректерді белгілі бір пайдаланушыларға қосу

Одан кейін деректерді жіберген пайдаланушыға қосу керек. Бізге тек иерархиядағы ең жоғары деректерді пайдаланушыға қосу керек, одан кейін төменгі деңгейдегі деректер болады. Оқу журналында тақырыптар қолданбадағы деректердің ең жоғары деңгейі болып табылады және барлық жазбалар тақырыпқа қосылған. Әрбір тақырып белгілі бір пайдаланушыға тиесілі болса, біз дерекқордағы әрбір жазбаның иелігін қадағалай аламыз.

Біз пайдаланушыға сыртқы кілт қатынасын қосу арқылы Тақырып үлгісін өзгертеміз. Содан кейін біз дерекқорды көшіруіміз керек. Соңында біз кейбір көріністерді өзгертеміз, осылайша олар тек қазір жүйеге кірген пайдаланушымен байланысты деректерді көрсетеді.

Тақырып үлгісін өзгерту

models.py өзгерту екі Тіркесті ғана құрайды:

models.py

from django.db import models
        from django.contrib.auth.models import User
        
        class Topic(models.Model):
           """Пайдаланушы оқып жатқан тақырып."""
            Text = models.CharField(max_length=200)
            date_added = models.DateTimeField(auto_now_add=True)
            owner = models.ForeignKey(User, on_delete=models.CASCADE)
        
            def __str__(self):
                """Тақырыпты білдіретін жолды қайтару."""
                Return self.text
        
        class Entry(models.Model):
            --snip/код үзіндісі--

Біз User үлгісін django.contrib.auth ішінен импорттаймыз. Одан кейін Тақырып-ға owner өрісін қосамыз, ол User үлгісіне сыртқы кілт қатынасын орнатады. Пайдаланушы жойылса, сол пайдаланушымен байланысты барлық тақырыптар да жойылады.

Бар пайдаланушыларды анықтау

Дерекқорды тасымалдаған кезде, Django дерекқорды әр тақырып пен пайдаланушы арасындағы байланысты сақтай алатындай өзгертеді. Тасымалдау үшін Django әрбір бар тақырыппен қай пайдаланушыны байланыстыру керектігін білуі керек. Ең қарапайым тәсіл - барлық бар тақырыптарды бір пайдаланушыға, мысалы, суперпайдаланушыға тағайындау арқылы бастау. Бірақ алдымен сол пайдаланушының идентификаторын білуіміз керек.

Осы уақытқа дейін жасалған барлық пайдаланушылардың идентификаторларын қарастырайық. Django қабық сеансын бастаңыз және келесі пәрмендерді шығарыңыз:

(ll_env)learning_log$ python manage.py shell
         >>> from django.contrib.auth.models import User
         >>> User.objects.all()
        <QuerySet [<User: ll_admin>, <User: eric>, <User: willie>]>
         >>> for user in User.objects.all():
        ...     print(user.username, user.id)
        ...
        ll_admin 1
        eric 2
        willie 3
        >>>

Алдымен User үлгісін қабық сеансына ❶ импорттаймыз. Содан кейін біз осы уақытқа дейін жасалған барлық пайдаланушыларды қарастырамыз ❷. Шығыс жобаның менің нұсқасы үшін үш пайдаланушыны көрсетеді: ll_admin, eric және willie.

Кейін біз пайдаланушылар тізімін айналдырып, әрбір пайдаланушының пайдаланушы аты мен идентификаторын ❸ басып шығарамыз. Джанго қай пайдаланушыдан бар тақырыптарды байланыстыруды сұрағанда, біз осы идентификатор мәндерінің бірін қолданамыз.

Дерекқорды тасымалдау

Енді біз идентификаторларды білеміз, біз дерекқорды тасымалдай аламыз. Мұны істегенде, Python бізден Тақырып үлгісін белгілі бір иесіне уақытша қосуды немесе не істеу керектігін айту үшін models.py файлымызға әдепкі параметрді қосуды сұрайды. . 1 опциясын таңдаңыз:

 (ll_env)learning_log$ python manage.py makemigrations learning_logs
         It is impossible to add a non-nullable field 'owner' to topic without
        specifying a default. This is because...
         Please select a fix:
         1) Provide a one-off default now (will be set on all existing rows with a
            null value for this column)
         2) Quit and manually define a default value in models.py.
         Select an option: 1
         Please enter the default value now, as valid Python
        The datetime and django.utils.timezone modules are available...
        Type 'exit' to exit this prompt
         >>> 1
        Migrations for 'learning_logs':
          learning_logs/migrations/0003_topic_owner.py
        - Add field owner to topic
        (ll_env)learning_log$

Біз makemigrations пәрменін ❶ шығарудан бастаймыз. Шығаруда Django әдепкі мәні көрсетілмеген ❷ бар үлгіге (тақырып) міндетті (нөлге жатпайтын) өрісті қосуға тырысып жатқанымызды көрсетеді. Django бізге екі нұсқа береді: біз дәл қазір әдепкі мән бере аламыз немесе одан шығып, models.py ❸ ішінде әдепкі мәнді қоса аламыз. Мұнда мен бірінші опцияны таңдадым ❹. Содан кейін Django әдепкі мәнді ❺ енгізуді сұрайды.

Барлық тақырыптарды бастапқы әкімші пайдаланушысымен, ll_admin байланыстыру үшін мен 1 ❻ пайдаланушы идентификаторын енгіздім. Сіз өзіңіз жасаған кез-келген пайдаланушының идентификаторын пайдалана аласыз; ол суперпайдаланушы болуы міндетті емес. Содан кейін Django осы мәнді пайдаланып дерекқорды тасымалдайды және Тақырып үлгісіне owner өрісін қосатын 0003_topic_owner.py тасымалдау файлын жасайды.

Енді біз тасымалдауды орындай аламыз. Белсенді виртуалды ортаға келесіні енгізіңіз:

(ll_env)learning_log$ python manage.py migrate
        Operations to perform:
          Apply all migrations: admin, auth, contenttypes, learning_logs, sessions
        Running migrations:
           Applying learning_logs.0003_topic_owner... OK
        (ll_env)learning_log$

Django жаңа тасымалдауды қолданады және нәтиже OK ❶.

Тасымалдау қабық сеансында күтілгендей жұмыс істегенін тексере аламыз, мысалы:

>>> from learning_logs.models import Topic
        >>> for topic in Topic.objects.all():
        ...     print(topic, topic.owner)
        ...
        Chess ll_admin
        Rock Climbing ll_admin
        >>>

Біз Тақырып файлын learning_logs.models ішінен импорттаймыз, содан кейін әрбір тақырыпты және ол тиесілі пайдаланушыны басып шығара отырып, барлық бар тақырыптарды айналдырамыз. Әрбір тақырып енді ll_admin пайдаланушысына тиесілі екенін көре аласыз. (Осы кодты іске қосқан кезде қате алсаңыз, қабықшадан шығып, жаңа қабықшаны іске қосып көріңіз.)

Тақырыптарға сәйкес пайдаланушыларға кіруді шектеу

Қазір жүйеге кірген болсаңыз, қай пайдаланушы ретінде кіргеніңізге қарамастан, барлық тақырыптарды көре аласыз. Оны пайдаланушыларға тек оларға тиесілі тақырыптарды көрсету арқылы өзгертеміз.

views.py ішіндегі topics() функциясына келесі өзгерісті жасаңыз:

learning_logs/views.py

--snip/код үзіндісі--
        @login_required
        def topics(request):
            """Барлық тақырыптарды көрсету."""
            topics = Topic.objects.filter(owner=request.user).order_by('date_added')
            context = {'topics': topics}
            return render(request, 'learning_logs/topics.html', context)
        --snip/код үзіндісі--

Пайдаланушы жүйеге кірген кезде, request нысанында пайдаланушы туралы ақпаратты қамтитын request.user атрибуттар жинағы болады. Topic.objects.filter(owner=request.user) сұрауы Джангоға дерекқордан owner атрибуты сәйкес келетін Topic нысандарын ғана шығарып алуды ұсынады. ағымдағы пайдаланушы. Тақырыптардың көрсетілу жолын өзгертпейтіндіктен, тақырыптар бетінің үлгісін мүлде өзгертудің қажеті жоқ.

Бұл жұмыс істейтінін көру үшін барлық бар тақырыптарды қосқан пайдаланушы ретінде жүйеге кіріп, тақырыптар бетіне өтіңіз. Сіз барлық тақырыптарды көруіңіз керек. Енді жүйеден шығып, басқа пайдаланушы ретінде қайта кіріңіз. Сіз «Әлі ешбір тақырып қосылмаған» хабарын көресіз.

Пайдаланушы тақырыптарын қорғау

Тақырып беттеріне кіруді әлі шектеген жоқпыз, сондықтан кез-келген тіркелген пайдаланушы бірнеше URL мекенжайларын (мысалы, http://localhost:8000/topics/1/) пайдалана алады. және сәйкес келетін тақырып беттерін шығарып алыңыз.

Өзіңіз көріңіз. Барлық тақырыптарды иеленетін пайдаланушы ретінде жүйеге кірген кезде, URL мекенжайын көшіріп алыңыз немесе тақырыптың URL мекенжайындағы идентификаторды ескеріңіз, содан кейін жүйеден шығып, басқа пайдаланушы ретінде қайта кіріңіз. Осы тақырыптың URL мекенжайын енгізіңіз. Басқа пайдаланушы ретінде кірген болсаңыз да, жазбаларды оқи алуыңыз керек.

Оны қазір topic() көру функциясында сұралған жазбаларды алу алдында тексеруді орындау арқылы түзетеміз:

learning_logs/views.py

from django.shortcuts import render, redirect
        from django.contrib.auth.decorators import login_required
         from django.http import Http404
        
        --snip/код үзіндісі--
        @login_required
        def topic(request, topic_id):
            """Бір тақырыпты және оның барлық жазбаларын көрсетіңіз."""
            topic = Topic.objects.get(id=topic_id)
            # Make sure the topic belongs to the current user.
             if topic.owner != request.user:
                raise Http404
        
            entries = topic.entry_set.order_by('-date_added')
            context = {'topic': topic, 'entries': entries}
            return render(request, 'learning_logs/topic.html', context)
        --snip/код үзіндісі--

404 жауабы - сұралған ресурс серверде болмаған кезде қайтарылатын стандартты қате жауабы. Мұнда біз Http404 ерекше жағдайды ❶ импорттаймыз, егер пайдаланушы оған қол жеткізе алмайтын тақырыпты сұраса, оны көтереміз. Тақырып сұрауын алғаннан кейін, бетті көрсетпес бұрын тақырыптың пайдаланушысы ағымдағы жүйеге кірген пайдаланушыға сәйкес келетініне көз жеткіземіз. Сұралған тақырыптың иесі ағымдағы пайдаланушымен бірдей болмаса, біз Http404 ерекше жағдайды ❷ көтереміз және Django 404 қате бетін қайтарады.

Енді басқа пайдаланушының тақырып жазбаларын көргіңіз келсе, Django қолданбасынан "Бет табылмады" хабарын көресіз. 20-тарауда жобаны конфигурациялаймыз, осылайша пайдаланушылар жөндеу бетінің орнына дұрыс қате бетін көреді.

edit_entry бетін қорғау

edit_entry беттерінде http://localhost:8000/edit_entry/entry_id/ пішінінің URL мекенжайлары бар, мұнда entry_id< /var> - сан. Ешкім басқа біреудің жазбаларына кіру үшін URL мекенжайын пайдаланбауы үшін осы бетті қорғайық:

learning_logs/views.py

--snip/код үзіндісі--
        @login_required
        def edit_entry(request, entry_id):
            """Бар жазбаны өңдеу."""
            entry = Entry.objects.get(id=entry_id)
            topic = entry.topic
            if topic.owner != request.user:
                raise Http404
        
            if request.method != 'POST':
                --snip/код үзіндісі--

Біз жазбаны және осы жазбамен байланысты тақырыпты аламыз. Содан кейін тақырып иесінің қазіргі уақытта кірген пайдаланушыға сәйкес келетінін тексереміз; егер олар сәйкес келмесе, біз Http404 ерекше жағдайды жасаймыз.

Жаңа тақырыптарды ағымдағы пайдаланушымен байланыстыру

Қазіргі уақытта жаңа тақырыптарды қосу беті бұзылған, себебі ол жаңа тақырыптарды ешбір нақты пайдаланушымен байланыстырмайды. Жаңа тақырып қосып көрсеңіз, IntegrityError хабарын және NOT NULL шектеуі орындалмады: learning_logs_topic.owner_id көресіз. Джанго тақырыптың owner өрісі үшін мәнді көрсетпестен жаңа тақырыпты жасай алмайтыныңызды айтады.

Бұл мәселені шешудің қарапайым жолы бар, себебі бізде ағымдағы пайдаланушыға request нысаны арқылы кіру мүмкіндігі бар. Жаңа тақырыпты ағымдағы пайдаланушымен байланыстыратын келесі кодты қосыңыз:

learning_logs/views.py

--snip/код үзіндісі--
        @login_required
        def new_topic(request):
            --snip/код үзіндісі--
            else:
                # POST data submitted; process data.
                form = TopicForm(data=request.POST)
                if form.is_valid():
                     new_topic = form.save(commit=False)
                     new_topic.owner = request.user
                     new_topic.save()
                    return redirect('learning_logs:topics')
        
            # Display a blank or invalid form.
            context = {'form': form}
            return render(request, 'learning_logs/new_topic.html', context)
         --snip/код үзіндісі--

Біз prine () () деп атағанда, біз = == аргументі, өйткені біз оны дерекқорға сақтамас бұрын жаңа тақырыпты өзгертпейміз. Содан кейін біз жаңа тақырыптың иесі атрибуты ағымдық пайдаланушыға ❷ орнатамыз. Соңында, біз жай анықталған тақырыптық данадағы Save деп атаймыз. Енді тақырыпта барлық қажетті мәліметтер бар және сәтті үнемдейді.

Сіз қалағаныңызша көптеген жаңа тақырыптарды өзіңіз қалағандай қосқыңыз келуіңіз керек. Әрбір пайдаланушы тек өз деректеріне, олар деректерге, жаңа деректерді енгізіп, ескі деректерді өзгертуге немесе өзгертуге мүмкіндік береді.

Қорытынды

Бұл тарауда пішіндер пайдаланушыларға жаңа тақырыптар мен жазбаларды қосуға және бар жазбаларды өңдеуге қалай мүмкіндік беретінін білдіңіз. Содан кейін сіз пайдаланушы тіркелгілерін қалай енгізу керектігін үйрендіңіз. Сіз бұрыннан бар пайдаланушыларға жүйеге кіру және шығу мүмкіндігін бердіңіз және адамдарға жаңа тіркелгілер жасауға мүмкіндік беру үшін Django әдепкі UserCreationForm қолданбасын пайдаландыңыз.

Қарапайым пайдаланушы аутентификация және тіркеу жүйесін құрастырғаннан кейін, сіз @login_required декораторын пайдаланып белгілі бір беттер үшін жүйеге кірген пайдаланушыларға кіруді шектедіңіз. Содан кейін сыртқы кілт қатынасы арқылы белгілі бір пайдаланушыларға деректерді тағайындадыңыз. Сондай-ақ, тасымалдау кейбір әдепкі деректерді көрсетуді талап еткенде, дерекқорды тасымалдауды үйрендіңіз.

Соңында, көру функцияларын өзгерту арқылы пайдаланушы тек өзіне тиесілі деректерді көре алатынына көз жеткізу жолын үйрендіңіз. Сіз filter() әдісі арқылы сәйкес деректерді шығарып алдыңыз және сұралған деректердің иесін ағымдағы жүйеге кірген пайдаланушымен салыстырдыңыз.

Қандай деректерді қолжетімді ету керек және қандай деректерді қорғау керек екені әрқашан бірден анық бола бермеуі мүмкін, бірақ бұл дағды тәжірибеде пайда болады. Пайдаланушыларымыздың деректерін қорғау үшін осы тарауда қабылдаған шешімдер жобаны құру кезінде неге басқалармен жұмыс істеу жақсы идея екенін көрсетеді: жобаңызды басқа біреудің қарауы осал аймақтарды анықтау ықтималдығын арттырады.

Сізде енді сіздің жергілікті құрылғыңызда толық жұмыс істейтін жоба бар. Соңғы тарауда оқу журналын көрнекі түрде тартымды ету үшін сәндейсіз және жобаны серверге орналастырасыз, осылайша интернетке кіру мүмкіндігі бар кез-келген адам тіркеліп, есептік жазба жасай алады.

Қолданбаны сәндеу және орналастыру

ITUniver

20
Қолданбаны сәндеу және орналастыру

Оқыту журналы қазір толықтай жұмыс істейді, бірақ оның стилі жоқ және тек жергілікті құрылғыда жұмыс істейді. Бұл тарауда сіз жобаны қарапайым, бірақ кәсіби түрде стильдейтін боласыз, содан кейін оны әлемдегі кез-келген адам есептік жазба жасап, оны пайдалана алатындай тірі серверге орналастырасыз.

Сәндеу үшін біз Bootstrap кітапханасын, веб-қосымшаларды сәндеуге арналған құралдар жинағын қолданамыз, сондықтан олар шағын телефоннан үлкен жұмыс үстелі мониторына дейін барлық заманауи құрылғыларда кәсіби көрінеді. Мұны істеу үшін біз django-bootstrap5 қолданбасын қолданамыз, ол сізге басқа Django әзірлеушілері жасаған қолданбаларды пайдалану тәжірибесін береді.

Оқу журналын Platform.sh арқылы орналастырамыз, ол жобаны оның серверлерінің біріне жіберуге мүмкіндік береді және оны интернет байланысы бар кез-келген адамға қолжетімді етеді. Сондай-ақ жобадағы өзгерістерді бақылау үшін Git деп аталатын нұсқаны басқару жүйесін пайдалана бастаймыз.

Оқыту журналын аяқтаған кезде қарапайым веб-қолданбаларды әзірлеуге, оларға кәсіби көрініс пен сезім беруге және оларды тікелей серверге орналастыруға болады. Сондай-ақ дағдыларыңызды дамыта отырып, қосымша оқу ресурстарын пайдалана аласыз.

Стильді үйрену журналы

Әуелі Learning Log функциясына назар аудару үшін осы уақытқа дейін сәндеуді әдейі елемедік. Бұл әзірлеуге жақындаудың жақсы жолы, себебі қолданба жұмыс істесе ғана пайдалы болады. Қолданба жұмыс істеп тұрғанда, оның сыртқы түрі маңызды, сондықтан адамдар оны пайдаланғысы келеді.

Бұл бөлімде django-bootstrap5 қолданбасын орнатып, оны жобаға қосамыз. Содан кейін оны жобадағы жеке беттерді стильдеу үшін пайдаланамыз, осылайша барлық беттер біркелкі көрініс пен сезімге ие болады.

django-bootstrap5 қолданбасы

Біз Bootstrap-ті жобамызға біріктіру үшін django-bootstrap5 пайдаланамыз. Бұл қолданба қажетті Bootstrap файлдарын жүктеп алып, оларды жобаңыздағы сәйкес орынға орналастырады және жобаңыздың үлгілерінде сәндеу директиваларын қолжетімді етеді.

Django-bootstrap5 орнату үшін белсенді виртуалды ортада келесі пәрменді орындаңыз:

(ll_env)learning_log$ pip install django-bootstrap5
        --snip/код үзіндісі--
        Successfully installed beautifulsoup4-4.11.1 django-bootstrap5-21.3
            soupsieve-2.3.2.post1

Кейін, settings.py ішіндегі INSTALLED_APPS қолданбасына django-bootstrap5 қосуымыз керек:

settings.py

--snip/код үзіндісі--
        INSTALLED_APPS = [
            # My apps.
            'learning_logs',
            'accounts',
        
            # Third party apps.
            'django_bootstrap5',
        
            # Default django apps.
            'django.contrib.admin',
            --snip/код үзіндісі--

Басқа әзірлеушілер жасаған қолданбалар үшін Үшінші тарап қолданбалары деп аталатын жаңа бөлімді бастаңыз және осы бөлімге 'django_bootstrap5' қосыңыз. Бұл бөлімді Менің қолданбаларым параметрінен кейін, бірақ Django әдепкі қолданбалары бар бөлімнің алдына қойғаныңызға көз жеткізіңіз.

Оқу журналын стильдеу үшін Bootstrap пайдалану

Bootstrap - сәндеу құралдарының үлкен жинағы. Сондай-ақ оның жалпы стиль жасау үшін жобаңызға қолдануға болатын бірнеше үлгілері бар. Жеке сәндеу құралдарын пайдаланудан гөрі бұл үлгілерді пайдалану әлдеқайда оңай. Bootstrap ұсынатын үлгілерді көру үшін https://getbootstrap.com сайтына өтіп, Мысалдар түймесін басыңыз. Біз қарапайым жоғарғы шарлау жолағын және бет мазмұнына арналған контейнерді қамтамасыз ететін Navbar статикалық үлгісін қолданамыз.

20-1-сурет Bootstrap үлгісін base.html файлына қолданғаннан кейін басты беттің қандай болатынын көрсетеді. және index.html-ді сәл өзгертіңіз.

20-1-сурет: Bootstrap көмегімен оқу журналының басты беті

Baza.html өзгертілуде

Bootstrap үлгісін пайдаланып base.html қайта жазуымыз керек. Біз жаңа base.html бөлімдерін дамытамыз. Бұл үлкен файл; бұл файлды мына жерден қол жетімді онлайн ресурстардан көшіргіңіз келуі мүмкін https://ehmatthes.github.io/pcc_3e. Егер файлды көшіріп алсаңыз, енгізілген өзгерістерді түсіну үшін келесі бөлімді оқып шығуыңыз керек.

HTML тақырыптарын анықтау

Біз base.html файлына енгізетін бірінші өзгеріс файлдағы HTML тақырыптарын анықтайды. Үлгілерде Bootstrap пайдалану үшін кейбір талаптарды қосамыз және бетке тақырып береміз. base.html ішіндегі барлығын жойып, оны келесі кодпен ауыстырыңыз:

base.html

 <!doctype html>
         <html lang="en">
         <head>
          <meta charset="utf-8">
          <meta name="viewport" content="width=device-width, initial-scale=1">
           <title>Learning Log</title>
        
           {% load django_bootstrap5 %}
          {% bootstrap_css %}
          {% bootstrap_javascript %}
        
        </head>

Біз алдымен бұл файлды ағылшын тілінде ❷ жазылған HTML құжаты ❶ ретінде жариялаймыз. HTML файлы екі негізгі бөлікке бөлінеді: бас және дене. Файлдың басы ашылатын <head> тегін ❸ басталады. HTML файлының басы бет мазмұнының ешқайсысын ұстамайды; ол жай ғана браузерге бетті дұрыс көрсету үшін не білу керектігін айтады. Біз бетке <title> элементін қосамыз, ол оқу журналы ашық ❹ кезде браузердің тақырып жолында көрсетіледі.

Бас бөлігін жаппас бұрын, django-bootstrap5 ❺ ішінде қол жетімді үлгі тегтерінің жинағын жүктейміз. {% bootstrap_css %} үлгі тегі - django-bootstrap5 қолданбасының теңшелетін тегі; ол Bootstrap мәнерлерін енгізу үшін қажетті барлық CSS файлдарын жүктейді. Келесі тег жиналмалы шарлау жолақтары сияқты бетте пайдалануға болатын барлық интерактивті әрекетті қосады. Жабылатын </head> тегі соңғы жолда пайда болады.

Барлық Bootstrap сәндеу опциялары енді base.html ішінен мұраланған кез-келген үлгіде қолжетімді. Егер сіз django-bootstrap5 қолданбасынан реттелетін үлгі тегтерін пайдаланғыңыз келсе, әрбір үлгіде {% load django_bootstrap5 %} тегін қамтуы қажет.

Шарлау жолағын анықтау

Беттің жоғарғы жағындағы шарлау жолағын анықтайтын код өте ұзын, себебі ол тар телефон экрандары мен кең жұмыс үстелі мониторларында бірдей жақсы жұмыс істеуі керек. Шарлау жолағын бөлімдерге бөліп жұмыс жасаймыз.

Міне, шарлау жолағының бірінші бөлігі:

base.html

--snip/код үзіндісі--
        </head>
        <body>
        
           <nav class="navbar navbar-expand-md navbar-light bg-light mb-4 border">
            <div class="container-fluid">
               <a class="navbar-brand" href="{% url 'learning_logs:index' %}">
                  Learning Log</a>
        
               <button class="navbar-toggler" type="button" data-bs-toggle="collapse"
                data-bs-target="#navbarCollapse" aria-controls="navbarCollapse"
                aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
              </button>
        
               <div class="collapse navbar-collapse" id="navbarCollapse">
                 <ul class="navbar-nav me-auto mb-2 mb-md-0">
                   <li class="nav-item">
                     <a class="nav-link" href="{% url 'learning_logs:topics' %}">
                      Topics</a></li>
                </ul> <!-- End of links on left side of navbar -->
              </div> <!-- Closes collapsible parts of navbar -->
        
            </div> <!-- Closes navbar's container -->
          </nav> <!-- End of navbar -->
        
         {% block content %}{% endblock content %}
        
        </body>
        </html>

Бірінші жаңа элемент - ашылатын <body> тегі. HTML файлының мәні пайдаланушылар бетте көретін мазмұнды қамтиды. Әрі қарай беттің жоғарғы жағындағы шарлау жолағының кодын ашатын <nav> элементі бар ❶. Бұл элементте қамтылған барлық нәрсе navbar, navbar-expand-md селекторларымен анықталған Bootstrap мәнері ережелеріне және осы жерде көретін қалғандарына сәйкес стильдендірілген. таңдаушы белгілі бір мәнер ережесінің беттегі қай элементтерге қолданылатынын анықтайды. navbar-light және bg-light селекторлары шарлау жолағын ашық тақырыптық фонмен сәндейді. mb-4 ішіндегі mb сөзі margin-bottom деген сөздің қысқасы; бұл селектор шарлау жолағы мен беттің қалған бөлігі арасында кішкене бос орын болуын қамтамасыз етеді. border селекторы беттің қалған бөлігінен аздап алшақтау үшін ашық фонның айналасында жұқа жиек береді.

Келесі Тіркестегі <div> тегі жалпы шарлау жолағын ұстайтын өлшемі өзгертілетін контейнерді ашады. div термині бөлу деген сөздің қысқасы; сіз веб-бетті бөлімдерге бөлу және осы бөлімге қолданылатын стиль мен мінез-құлық ережелерін анықтау арқылы жасайсыз. Ашылатын <div> тегінде анықталған кез-келген сәндеу немесе мінез-құлық ережелері </div> ретінде жазылған сәйкес жабылу тегіне дейін сіз көрген барлық нәрсеге әсер етеді.

Кейін біз жобаның атын, Оқыту журналы, шарлау жолағында ❷ бірінші элемент ретінде көрсетілетін етіп орнатамыз. Бұл алдыңғы екі тарауда біз құрастырған жобаның минималды стильді нұсқасында орындалғандай, басты бетке сілтеме ретінде қызмет етеді. navbar-brand селекторы бұл сілтемені мәнерлейді, осылайша ол басқа сілтемелерден ерекшеленеді және сайтқа брендинг қосуға көмектеседі.

Бүкіл шарлау жолағын көлденеңінен көрсету үшін шолғыш терезесі тым тар болса, Bootstrap үлгісі ❸ пайда болатын түймені анықтайды. Пайдаланушы түймені басқанда, шарлау элементтері ашылмалы тізімде пайда болады. collapse сілтемесі пайдаланушы шолғыш терезесін кішірейткен кезде немесе сайт шағын экрандары бар құрылғыларда көрсетілгенде шарлау жолағын жиырылады.

Кейін, шарлау жолының ❹ жаңа бөлімін (<div>) ашамыз. Бұл шолғыш терезесінің өлшеміне байланысты жиырылуы мүмкін шарлау тақтасының бөлігі.

Bootstrap шарлау элементтерін ретсіз тізімдегі элементтер ретінде анықтайды ❺ және оны тізімге ұқсамайтын мәнер ережелері бар. Жолаққа қажет әрбір сілтеме немесе элемент реттелмеген тізімге элемент ретінде қосылуы мүмкін ❻. Мұнда тізімдегі жалғыз элемент - біздің тақырыптар бетіне сілтеме ❼. Сілтеменің соңындағы жабылатын </li> тегіне назар аударыңыз; әрбір ашылу тегіне сәйкес жабу тегі қажет.

Мұнда көрсетілген қалған жолдар барлық ашылған тегтерді жабады. HTML тілінде түсініктеме келесідей жазылады:

<!-- This is an HTML comment. -->

Жабу тегтерінде әдетте түсініктемелер болмайды, бірақ HTML тілін жаңадан меңгерген болсаңыз, жабу тегтерінің кейбірін белгілеу өте пайдалы болуы мүмкін. Бір жетіспейтін тег немесе қосымша тег бүкіл беттің орналасуын бұзуы мүмкін. Бізге content блогы ❽ және жабылатын </body> және </html> тегтері де кіреді.

Біз шарлау жолағын аяқтаған жоқпыз, бірақ қазір толық HTML құжаты бар. Егер runserver қазір белсенді болса, ағымдағы серверді тоқтатып, қайта іске қосыңыз. Жобаның басты бетіне өтіңіз, сонда сіз 20-1-сурет-де көрсетілген кейбір элементтері бар шарлау жолағын көресіз. Енді қалған элементтерді шарлау жолағына қосамыз.

Пайдаланушы тіркелгісінің сілтемелерін қосу

Біз әлі де пайдаланушы тіркелгілерімен байланыстырылған сілтемелерді қосуымыз керек. Шығу пішінінен басқа есептік жазбаға қатысты барлық сілтемелерді қосудан бастаймыз.

base.html файлына келесі өзгерістерді жасаңыз:

base.html

        --snip/код үзіндісі--
                </ul> <!-- End of links on left side of navbar -->
        
                <!-- Account-related links -->
                 <ul class="navbar-nav ms-auto mb-2 mb-md-0">
        
                   {% if user.is_authenticated %}
                    <li class="nav-item">
                       <span class="navbar-text me-2">Hello, {{ user.username }}.
                        </span></li>
                   {% else %}
                    <li class="nav-item">
                      <a class="nav-link" href="{% url 'accounts:register' %}">
                          Register</a></li>
                    <li class="nav-item">
                      <a class="nav-link" href="{% url 'accounts:login' %}">
                          Log in</a></li>
                  {% endif %}
        
                </ul> <!-- End of account-related links -->
        
              </div> <!-- Closes collapsible parts of navbar -->
              --snip/код үзіндісі--

Сілтемелердің жаңа жинағын басқа ашылатын <ul> тегін ❶ арқылы бастаймыз. Бетте қанша қажет болса, сонша сілтемелер тобы болуы мүмкін. ms-auto селекторы margin-start-automatic деген сөздің қысқасы: бұл селектор шарлау жолағындағы басқа элементтерді тексереді және оны итеретін сол жақ (бастау) жиегін жасайды. шолғыш терезесінің оң жағындағы сілтемелер тобы.

if блогы - бұл пайдаланушылардың жүйеге кірген-кірмегеніне қарай ❷ сәйкес хабарларды көрсету үшін бұрын қолданылған шартты блок. Блок енді сәл ұзағырақ, себебі шартты тегтердің ішінде сәндеу ережелері бар. Аутентификацияланған пайдаланушыларға арналған сәлемдесу <span> элементіне ❸ оралған. span элементі ұзағырақ Тіркестің бөлігі болып табылатын мәтін бөліктерін немесе бет элементтерін мәнерлейді. div элементтері бетте өз бөлімдерін жасағанда, аралық элементтері үлкенірек бөлімде үздіксіз болады. Бұл алдымен шатастыруы мүмкін, себебі көптеген беттерде терең кірістірілген div элементтері бар. Мұнда біз шарлау жолағындағы ақпараттық мәтінді стильдеу үшін span элементін пайдаланамыз: бұл жағдайда жүйеге кірген пайдаланушының аты.

Түпнұсқалығы расталмаған пайдаланушылар үшін жұмыс істейтін else блогында біз жаңа тіркелгіні тіркеуге және жүйеге кіруге ❹ сілтемелерін қосамыз. Бұл тақырыптар бетінің сілтемесі сияқты болуы керек.

Егер шарлау жолағына қосымша сілтемелер қосқыңыз келсе, біз жасайтын <ul> топтарының біріне басқа <li> элементін қосасыз. осы жерден көргендер сияқты стильдеу директивалары арқылы анықтадым.

Енді жүйеден шығу пішінін шарлау жолағына қосамыз.

Шығу пішінін шарлау тақтасына қосу

Шығу пішінін алғаш жазған кезде оны base.html төменгі жағына қостық. Енді оны шарлау жолағында жақсырақ жерге орналастырайық:

base.html

        --snip/код үзіндісі--
                </ul> <!-- End of account-related links -->
        
                {% if user.is_authenticated %}
                  <form action="{% url 'accounts:logout' %}" method='post'>
                    {% csrf_token %}
                     <button name='submit' class='btn btn-outline-secondary btn-sm'>
                        Log out</button>
                  </form>
                {% endif %}
        
              </div> <!-- Closes collapsible parts of navbar -->
              --snip/код үзіндісі--

Шығу пішіні тіркелгіге қатысты сілтемелер жинағынан кейін, бірақ шарлау жолағының жиналмалы бөлімінің ішіне орналастырылуы керек. Пішіндегі жалғыз өзгеріс - жүйеден шығу түймешігіне ❶ Bootstrap сәндеу элементтерін қолданатын <button> элементіндегі Bootstrap стильдеу класстарының бірқатарының қосылуы.

Негізгі бетті қайта жүктеңіз, сонда сіз жасаған есептік жазбалардың кез келгенін пайдаланып жүйеге кіріп, шыға аласыз.

base.html ішіне әлі де қосу керек. Жеке беттер сол беттерге арналған мазмұнды орналастыру үшін пайдалана алатын екі блокты анықтауымыз керек.

Беттің негізгі бөлігін анықтау

base.html қалған бөлігі беттің негізгі бөлігін қамтиды:

base.html

  --snip/код үзіндісі--
          </nav> <!-- End of navbar -->
        
           <main class="container">
             <div class="pb-2 mb-2 border-bottom">
              {% block page_header %}{% endblock page_header %}
            </div>
             <div>
              {% block content %}{% endblock content %}
            </div>
          </main>
        
        </body>
        </html>

Алдымен <main> тегін ❶ ашамыз. негізгі элементі беттің негізгі бөлігінің ең маңызды бөлігі үшін пайдаланылады. Мұнда біз беттегі элементтерді топтастырудың қарапайым тәсілі болып табылатын контейнер жүктеу жолағын таңдау құралын тағайындаймыз. Бұл контейнерге екі div элементін орналастырамыз.

Бірінші div элементінде page_header блогы ❷ бар. Біз бұл блокты көптеген беттерге атау беру үшін қолданамыз. Бұл бөлімді беттің қалған бөлігінен ерекше ету үшін біз тақырыптың астына толтырғыштарды орналастырамыз. Толтыру элемент мазмұны мен оның шекарасы арасындағы кеңістікті білдіреді. pb-2 селекторы - стильделген элементтің төменгі жағында толтырудың қалыпты мөлшерін қамтамасыз ететін жүктеу жолағы директивасы. маржа - элементтің жиегі мен беттегі басқа элементтер арасындағы бос орын. mb-2 селекторы осы бөлімнің төменгі жағындағы қалыпты маржа мөлшерін қамтамасыз етеді. Біз осы блоктың төменгі жағында жиек алғымыз келеді, сондықтан page_header блогының төменгі жағында жұқа жиекті қамтамасыз ететін border-bottom селекторын қолданамыз.

Одан кейін біз content ❸ блогын қамтитын тағы бір div элементін анықтаймыз. Біз бұл блокқа қандай да бір нақты стиль қолданбаймыз, сондықтан кез-келген беттің мазмұнын сол бетке сәйкес келетіндей мәнерлей аламыз. base.html файлының соңында main, body және html элементтері үшін жабу тегтері бар.

Оқу журналының басты бетін шолғышқа жүктегенде, 20-1-сурет-де көрсетілгенге сәйкес келетін кәсіби көрінетін шарлау жолағын көруіңіз керек. Терезенің өлшемін өзгертіп көріңіз, сонда ол өте тар болады; түйме шарлау жолағын ауыстыруы керек. Түймені басыңыз, сонда барлық сілтемелер ашылмалы тізімде пайда болуы керек.

Джумботрон көмегімен басты бетті сәндеу

Басты бетті жаңарту үшін біз jumbotron деп аталатын Bootstrap элементін қолданамыз, ол беттің қалған бөлігінен ерекшеленетін үлкен жәшік. Әдетте, ол жалпы жобаның қысқаша сипаттамасы мен көрерменді қатысуға шақыратын әрекетке шақыру үшін басты беттерде пайдаланылады.

Here’s the revised index.html file:

index.html

{% extends "learning_logs/base.html" %}
        
         {% block page_header %}
           <div class="p-3 mb-4 bg-light border rounded-3">
            <div class="container-fluid py-4">
               <h1 class="display-3">Track your learning.</h1>
        
               <p class="lead">Make your own Learning Log, and keep a list of the
              topics you're learning about. Whenever you learn something new
              about a topic, make an entry summarizing what you've learned.</p>
        
               <a class="btn btn-primary btn-lg mt-1"
                href="{% url 'accounts:register' %}">Register &raquo;</a>
            </div>
          </div>
        {% endblock page_header %}

Біз алдымен Джангоға page_header блогында ❶ не болатынын анықтағалы жатқанымызды айтамыз. Джумботрон ❷ оларға қолданылатын сәндеу директивалары жинағы бар div элементтері жұбы ретінде жүзеге асырылады. Сыртқы бөлімде толтыру және жиектер параметрлері, ашық фон түсі және дөңгелек бұрыштары бар. Ішкі div - терезе өлшемімен бірге өзгеретін және кейбір толтырғыштары бар контейнер. py-4 селекторы div элементінің жоғарғы және төменгі жағына толтырғыш қосады. Осы параметрлердегі сандарды реттеп, басты беттің қалай өзгеретінін көріңіз.

Джумботронның ішінде үш элемент бар. Біріншісі - жаңа келушілерге Learning Log ❸ не істейтіні туралы түсінік беретін Оқытуыңызды бақылаңыз деген қысқа хабарлама. <h1> элементі бірінші деңгейлі тақырып болып табылады, ал display-3 селекторы осы нақты тақырыпқа жұқа және ұзынырақ көрініс қосады. Біз сондай-ақ пайдаланушының оқу журналымен ❹ не істей алатыны туралы қосымша ақпаратты беретін ұзағырақ хабарды қосамыз. Бұл қарапайым абзацтардан ерекшеленетін lead абзац ретінде пішімделген.

Мәтіндік сілтемені пайдаланудың орнына, біз пайдаланушыларды Оқу журналында ❺ тіркелгісін тіркеуге шақыратын түймені жасаймыз. Бұл тақырыптағы сілтеме, бірақ түйме бетте ерекшеленіп тұрады және жобаны пайдалануды бастау үшін қараушыға не істеу керектігін көрсетеді. Мұнда көріп отырған селекторлар мұны әрекетке шақыруды білдіретін үлкен түйме ретінде стильдейді. &raquo; коды біріктірілген екі тік бұрышты жақшаға ұқсайтын HTML нысаны болып табылады (>>). Соңында біз жабу div тегтерін береміз және page_header блогын жабамыз. Бұл файлда тек екі div элементі бар болса, жабу div тегтерін белгілеу әсіресе пайдалы емес. Біз бұл бетке басқа ештеңе қоспаймыз, сондықтан осы үлгідегі content блогын анықтаудың қажеті жоқ.

Негізгі бет енді 20-1-сурет сияқты көрінеді. Бұл жобаның стильсіз нұсқасына қарағанда айтарлықтай жақсарды!

Кіру бетін сәндеу

Кіру бетінің жалпы көрінісін нақтыладық, бірақ кіру пішінінің өзінде әлі ешқандай стиль жоқ. login.html өзгерту арқылы пішінді беттің қалған бөлігімен сәйкес етейік:

login.html

{% extends 'learning_logs/base.html' %}
         {% load django_bootstrap5 %}
        
         {% block page_header %}
          <h2>Log in to your account.</h2>
        {% endblock page_header %}
        
        {% block content %}
        
          <form action="{% url 'accounts:login' %}" method='post'>
            {% csrf_token %}
             {% bootstrap_form form %}
             {% bootstrap_button button_type="submit" content="Log in" %}
          </form>
        
        {% endblock content %}

Осы үлгіге алдымен bootstrap5 үлгі тегтерін жүктейміз ❶. Содан кейін пайдаланушыға беттің ❷ не үшін екенін айтатын page_header блогын анықтаймыз. Үлгіден {% if form.errors %} блогын алып тастағанымызға назар аударыңыз; django-bootstrap5 пішін қателерін автоматты түрде басқарады.

Пішінді көрсету үшін {% bootstrap_form %} үлгі тегін қолданамыз ❸; бұл біз 19-тарауда пайдаланған {{ form.as_div }} элементін ауыстырады. {% booststrap_form %} үлгі тегі Bootstrap стилінің ережелерін пішіннің жеке элементтеріне келесідей кірістіреді. пішін көрсетіледі. Жіберу түймешігін жасау үшін біз оны жіберу түймесі ретінде белгілейтін дәлелдері бар {% bootstrap_button %} тегін қолданамыз және оған Кіру ❹ белгісін береміз.

20-2-сурет қазір кіру пішінін көрсетеді. Бет әлдеқайда таза, дәйекті сәндеу және айқын мақсат. Қате пайдаланушы атымен немесе құпия сөзбен кіріп көріңіз; Сіз тіпті қате туралы хабарлардың дәйекті түрде стильделгенін және жалпы сайтпен жақсы біріктірілгенін көресіз.

20-2-сурет: Bootstrap көмегімен стильдендірілген кіру беті

Тақырыптар бетін сәндеу

Тақырыптар бетінен бастап ақпаратты көруге арналған беттердің де стильге сай болуын тексерейік:

topics.html

{% extends 'learning_logs/base.html' %}
        
        {% block page_header %}
           <h1>Topics</h1>
        {% endblock page_header %}
        
        {% block content %}
        
           <ul class="list-group border-bottom pb-2 mb-4">
            {% for topic in topics %}
               <li class="list-group-item border-0">
                <a href="{% url 'learning_logs:topic' topic.id %}">
                  {{ topic.text }}</a>
              </li>
            {% empty %}
               <li class="list-group-item border-0">No topics have been added yet.</li>
            {% endfor %}
          </ul>
        
          <a href="{% url 'learning_logs:new_topic' %}">Add a new topic</a>
        
        {% endblock content %}

Бізге {% load bootstrap5 %} тегі қажет емес, себебі біз бұл файлда ешқандай теңшелетін bootstrap5 үлгі тегтерін пайдаланбаймыз. Тақырыптар тақырыбын page_header блогына жылжытамыз және оны қарапайым абзац ❶ орнына <h1> элементіне айналдырамыз.

Бұл беттегі негізгі мазмұн тақырыптар тізімі болып табылады, сондықтан біз бетті көрсету үшін Bootstrap тізім тобы компонентін қолданамыз. Бұл жалпы тізімге және тізімдегі әрбір элементке сәндеу директиваларының қарапайым жинағын қолданады. <ul> тегін ашқанда, тізімге әдепкі стиль директиваларын қолдану үшін алдымен list-group классын қосамыз ❷. Біз тізімнің төменгі жағына жиек, тізімнің астына аздап толтыру (pb-2) және төменгі жиектің астына жиек (mb-4) қою арқылы тізімді әрі қарай реттейміз.

Тізімдегі әрбір элементке list-group-item классы қажет және біз жеке элементтердің ❸ айналасындағы жиекті алып тастау арқылы әдепкі мәнерді реттейміз. Тізім бос кезде көрсетілетін хабарға дәл осы класстар қажет ❹.

Тақырыптар бетіне қазір кірген кезде, басты бетке сәйкес келетін стильді бетті көресіз.

Тақырып бетіндегі жазбаларды сәндеу

Тақырып бетінде біз әрбір жазбаны ерекше ету үшін Bootstrap картасының құрамдас бөлігін қолданамыз. карта - бұл тақырып жазбаларын көрсетуге өте ыңғайлы, икемді, алдын ала анықталған мәнерлері бар divs кірістірілген жиыны:

topic.html

{% extends 'learning_logs/base.html' %}
        
         {% block page_header %}
          <h1>{{ topic.text }}</h1>
        {% endblock page_header %}
        
        {% block content %}
          <p>
            <a href="{% url 'learning_logs:new_entry' topic.id %}">Add new entry</a>
          </p>
        
          {% for entry in entries %}
             <div class="card mb-3">
              <!-- Card header with timestamp and edit link -->
               <h4 class="card-header">
                {{ entry.date_added|date:'M d, Y H:i' }}
                 <small><a href="{% url 'learning_logs:edit_entry' entry.id %}">
                  edit entry</a></small>
              </h4>
              <!-- Card body with entry text -->
               <div class="card-body">{{ entry.text|linebreaks }}</div>
            </div>
          {% empty %}
             <p>There are no entries for this topic yet.</p>
          {% endfor %}
        
        {% endblock content %}

Тақырыпты алдымен page_header блогына ❶ орналастырамыз. Содан кейін осы үлгіде бұрын қолданылған ретсіз тізім құрылымын жоямыз. Әрбір жазбаны тізім элементі етудің орнына, card ❷ селекторымен div элементін ашамыз. Бұл картада екі кірістірілген элемент бар: біреуі уақыт белгісін және жазбаны өңдеуге арналған сілтемені, ал екіншісі жазбаның негізгі бөлігін ұстайды. card селекторы осы div үшін қажет сәндеудің көп бөлігін қамтамасыз етеді; біз картаны әр картаның төменгі жағына кішкене маржа қосу арқылы реттейміз (mb-3).

Картадағы бірінші элемент тақырып болып табылады, ол <h4> элементі card-header селекторы бар ❸. Бұл тақырыпта жазба жасалған күн және жазбаны өңдеу сілтемесі бар. edit_entry сілтемесінің айналасындағы <small> тегі оны уақыт белгісінен ❹ сәл кішірек етіп көрсетеді. Екінші элемент - card-body ❺ селекторы бар div, ол жазба мәтінін картадағы қарапайым жолаққа орналастырады. Беттегі ақпаратты қосу үшін Django коды өзгермегеніне назар аударыңыз; беттің сыртқы түріне әсер ететін элементтер ғана бар. Бізде енді ретсіз тізім болмағандықтан, бос тізім хабарының айналасындағы тізім элементінің тегтерін қарапайым абзац тегтерімен ауыстырдық ❻.

20-3-сурет жаңа көрінісімен тақырып бетін көрсетеді. Learning Log функциясы өзгерген жоқ, бірақ ол әлдеқайда кәсіби және пайдаланушыларды қызықтыратын көрінеді.

Егер жоба үшін басқа Bootstrap үлгісін пайдаланғыңыз келсе, осы тарауда осы уақытқа дейін жасағанымызға ұқсас процесті орындаңыз. Пайдаланғыңыз келетін үлгіні base.html ішіне көшіріп, үлгі жобаңыздың ақпаратын көрсететіндей нақты мазмұны бар элементтерді өзгертіңіз. Содан кейін әр беттегі мазмұнды стильдеу үшін Bootstrap-тің жеке сәндеу құралдарын пайдаланыңыз.

20-3-сурет: Bootstrap стилі бар тақырып беті

Оқу журналын қолдану

Енді бізде кәсіпқой көрінетін жоба болғандықтан, оны интернетке қосылуы бар кез-келген адам пайдалана алатындай тірі серверге орналастырайық. Біз веб-қосымшаларды орналастыруды басқаруға мүмкіндік беретін веб-негізделген платформаны Platform.sh пайдаланамыз. Біз Learning журналын Platform.sh сайтында іске қосамыз.

Platform.sh есептік жазбасын жасау

Тіркелгі жасау үшін https://platform.sh бетіне өтіп, Тегін сынақ нұсқасы түймесі. Platform.sh сайтында тегін деңгей бар, ол осы жазу кезінде несие картасын қажет етпейді. Сынақ мерзімі ең аз ресурстары бар қолданбаны орналастыруға мүмкіндік береді, бұл ақылы хостинг жоспарын орындаудан бұрын жобаңызды тікелей орналастыруда сынауға мүмкіндік береді.

Platform.sh CLI орнату

Платform.sh сайтында жобаны орналастыру және басқару үшін сізге пәрмен жолы интерфейсінде (CLI) қолжетімді құралдар қажет болады. CLI соңғы нұсқасын орнату үшін https://docs.platform.sh/development/cli сайтына кіріңіз. .html және амалдық жүйеңізге арналған нұсқауларды орындаңыз.

Көптеген жүйелерде терминалда келесі пәрменді орындау арқылы CLI орнатуға болады:

$ curl -fsS https://platform.sh/cli/installer | php

Осы пәрмен орындалып болғаннан кейін, CLI қолданбасын пайдаланбас бұрын жаңа терминал терезесін ашуыңыз қажет.

platformshconfig орнату

Сонымен қатар сізге бір қосымша бума, platformshconfig орнату қажет. Бұл бума жобаның жергілікті жүйеде немесе Platform.sh серверінде іске қосылғанын анықтауға көмектеседі. Белсенді виртуалды ортада келесі пәрменді беріңіз:

(ll_env)learning_log$ pip install platformshconfig

Бұл буманы жоба тікелей серверде жұмыс істеп тұрған кезде оның параметрлерін өзгерту үшін пайдаланамыз.

Талаптар.txt файлын жасау

Қашықтағы сервер Learning Log бумаларының қай пакеттерге байланысты екенін білуі керек, сондықтан біз олардың тізімі берілген файлды жасау үшін pip пайдаланамыз. Тағы да, белсенді виртуалды ортадан келесі пәрменді шығарыңыз:

(ll_env)learning_log$ pip freeze > requirements.txt

freeze пәрмені pip-ке жобада қазіргі уақытта орнатылған барлық бумалардың атауларын requirements.txt файлына жазуды ұсынады. Жобаңызда орнатылған пакеттер мен нұсқа нөмірлерін көру үшін осы файлды ашыңыз:

requirements.txt

asgiref==3.5.2
        beautifulsoup4==4.11.1
        Django==4.1
        django-bootstrap5==21.3
        platformshconfig==2.4.0
        soupsieve==2.3.2.post1
        sqlparse==0.4.2

Оқыту журналы қазірдің өзінде жеті түрлі буманың нақты нұсқаларына байланысты, сондықтан қашықтағы серверде дұрыс жұмыс істеу үшін сәйкес орта қажет. (Осы пакеттердің үшеуін қолмен орнаттық, ал төртеуі осы пакеттерге тәуелділік ретінде автоматты түрде орнатылды.)

Оқу журналын қолданған кезде, Platform.sh requirements.txt ішінде тізімделген барлық бумаларды орнатып, біз жергілікті қолданатын бірдей пакеттермен орта жасайды. Осыған байланысты, біз енгізілген жобаның жергілікті жүйедегідей жұмыс істейтініне сенімді бола аламыз. Жүйеде бірнеше жобаны құру және қолдау көрсетуді бастаған кезде жобаны басқарудың бұл тәсілі өте маңызды.

Қосымша орналастыру талаптары

Тірі сервер екі қосымша пакетті қажет етеді. Бұл пакеттер көптеген пайдаланушылар бір уақытта сұрау жасай алатын өндірістік ортада жобаға қызмет көрсету үшін пайдаланылады.

requirements.txt сақталған сол каталогта requirements_remote.txt деп аталатын жаңа файл жасаңыз. Оған келесі екі буманы қосыңыз:

requirements_remote.txt

# Requirements for live project.
        gunicorn
        psycopg2

gunicorn бумасы қашықтағы серверге келген кезде сұрауларға жауап береді; бұл біз жергілікті қолданып жүрген әзірлеу серверінің орнын алады. psycopg2 бумасы Django-ға Platform.sh пайдаланатын Postgres дерекқорын басқаруға мүмкіндік беру үшін қажет. Postgres - өндірістік қолданбаларға өте қолайлы ашық бастапқы дерекқор.

Конфигурация файлдарын қосу

Әр хостинг платформасы жобаның серверлерінде дұрыс жұмыс істеуі үшін кейбір конфигурацияны қажет етеді. Бұл бөлімде біз үш конфигурация файлын қосамыз:

.platform.app.yaml Бұл жобаның негізгі конфигурация файлы. Бұл Platform.sh сайтына қандай жобаны орналастыруға тырысып жатқанымызды және жобамызға қандай ресурстар қажет екенін айтады және серверде жобаны құруға арналған пәрмендерді қамтиды.

.platform/routes.yaml Бұл файл жобамыздың бағыттарын анықтайды. Platform.sh сұрауды алған кезде, бұл сұрауларды біздің арнайы жобаға бағыттауға көмектесетін конфигурация.

.platform/services.yaml Бұл файл жобамызға қажет кез-келген қосымша қызметтерді анықтайды.

Бұл барлық YAML (YAML белгілеу тілі емес) файлдары. YAML — конфигурация файлдарын жазуға арналған тіл; оны адамдар да, компьютер де оңай оқи алатындай етіп жасалған. Әдеттегі YAML файлын қолмен жазуға немесе өзгертуге болады, бірақ компьютер файлды бір мәнді түрде оқи және түсіндіре алады.

YAML файлдары орналастыру конфигурациясы үшін тамаша, себебі олар сізге орналастыру процесі кезінде не болатынын жақсы басқару мүмкіндігін береді.

Жасырын файлдарды көрінетін ету

Операциялық жүйелердің көпшілігі .platform сияқты нүктеден басталатын файлдар мен каталогтарды жасырады. Файл шолғышын ашқанда, әдепкі бойынша мұндай файлдар мен каталогтарды көрмейсіз. Бірақ бағдарламашы ретінде сіз оларды көруіңіз керек. Операциялық жүйеңізге байланысты жасырын файлдарды көру жолы:

  • Windows жүйесінде Windows Explorer бағдарламасын ашыңыз, содан кейін Жұмыс үстелі сияқты каталогты ашыңыз. Көру қойындысын басып, Файл атауы кеңейтімдері және Жасырын элементтер тексерілгеніне көз жеткізіңіз.
  • MacOS жүйесінде ⌘-SHIFT- пернесін басуға болады. Жасырын файлдар мен каталогтарды көру үшін кез-келген Finder терезесінде (нүкте).
  • Ubuntu сияқты Linux жүйелерінде жасырын файлдар мен каталогтарды көрсету үшін кез-келген файл шолғышында CTRL-H пернелерін басуға болады. Бұл параметрді тұрақты ету үшін Nautilus сияқты файл шолғышын ашып, опциялар қойындысын басыңыз (үш жолмен көрсетілген). Жасырын файлдарды көрсету құсбелгісін қойыңыз.
.platform.app.yaml конфигурация файлы

Бірінші конфигурация файлы ең ұзын, себебі ол жалпы орналастыру процесін басқарады. Біз оны бөліктерге бөлеміз; оны мәтіндік редакторға қолмен енгізуге немесе https://ehmatthes.github сайтындағы онлайн ресурстардан көшірмесін жүктеп алуға болады. .io/pcc_3e.

Міне, .platform.app.yaml бірінші бөлігі, ол manage.py сияқты бір каталогта сақталуы керек:

.platform.app.yaml

 name: "ll_project"
        type: "python:3.10"
        
         relationships:
            database: "db:postgresql"
        
        # The configuration of the app when it's exposed to the web.
         web:
            upstream:
                socket_family: unix
            commands:
                 start: "gunicorn -w 4 -b unix:$SOCKET ll_project.wsgi:application"
             locations:
                "/":
                    passthru: true
                "/static":
                    root: "static"
                    expires: 1h
                    allow: true
        
        # The size of the persistent disk of the application (in MB).
         disk: 512

Осы файлды сақтаған кезде файл атауының басында нүктені қосқаныңызға көз жеткізіңіз. Егер нүктені өткізіп алсаңыз, Platform.sh файлды таба алмайды және жобаңыз қолданылмайды.

Осы кезде .platform.app.yaml ішіндегі барлығын түсінудің қажеті жоқ; Мен конфигурацияның ең маңызды бөліктерін бөлектеймін. Файл жобаны ❶ бастаған кезде пайдаланған атқа сәйкес болу үшін 'll_project' деп атайтын жобаның name көрсетуден басталады. Біз сондай-ақ біз пайдаланып жатқан Python нұсқасын көрсетуіміз керек (осы жазу кезінде 3.10). Қолдау көрсетілетін нұсқалардың тізімін https://docs.platform.sh/languages/python сайтынан таба аласыз. html.

Келесі - жобаға қажет басқа қызметтерді анықтайтын қарым-қатынастар деп белгіленген бөлім ❷. Мұнда жалғыз байланыс Postgres дерекқорымен байланысты. Одан кейін web бөлімі ❸. commands:start бөлімі Platform.sh сайтына кіріс сұрауларға қызмет көрсету үшін қандай процесті пайдалану керектігін айтады. Мұнда біз gunicorn сұрауларды ❹ өңдейтінін көрсетеміз. Бұл пәрмен біз жергілікті қолданып жүрген python manage.py runserver пәрменінің орнын алады.

орындар бөлімі Platform.sh сайтына кіріс сұрауларын ❺ қайда жіберу керектігін айтады. Сұраулардың көпшілігі gunicorn арқылы өтуі керек; біздің urls.py файлдары gunicorn-ға сол сұрауларды қалай өңдеу керектігін нақты айтады. Статикалық файлдарға арналған сұраулар бөлек өңделеді және сағатына бір рет жаңартылады. Соңғы жол Platform.sh серверлерінің бірінде 512 МБ дискілік кеңістік сұрап жатқанымызды көрсетеді ❻.

The rest of .platform.app.yaml is as follows:

--snip/код үзіндісі--
        disk: 512
        
        # Set a local read/write mount for logs.
         mounts:
            "logs":
                source: local
                source_path: logs
        
        # The hooks executed at various points in the lifecycle of the application.
         hooks:
            build: |
                 pip install --upgrade pip
                pip install -r requirements.txt
                pip install -r requirements_remote.txt
        
                mkdir logs
                 python manage.py collectstatic
                rm -rf logs
             deploy: |
                python manage.py migrate

монтаждар бөлімі ❶ жоба жұмыс істеп тұрған кезде деректерді оқуға және жазуға болатын каталогтарды анықтауға мүмкіндік береді. Бұл бөлім орналастырылған жоба үшін logs/ каталогын анықтайды.

ілмектер бөлімі ❷ орналастыру процесі кезінде әртүрлі нүктелерде орындалатын әрекеттерді анықтайды. build бөлімінде біз жобаны тірі ортада ❸ қызмет ету үшін қажетті барлық пакеттерді орнатамыз. Біз сонымен қатар жобаға қажетті барлық статикалық файлдарды бір жерге жинайтын collectstatic ❹ іске қосамыз, осылайша оларға тиімді қызмет көрсетуге болады.

Соңында, deploy бөлімінде ❺, біз тасымалдаулар жобаны қолданған сайын іске қосылуы керек екенін көрсетеміз. Қарапайым жобада ешқандай өзгерістер болмаса, бұл әсер етпейді.

Басқа екі конфигурация файлы әлдеқайда қысқа; оларды қазір жазайық.

routes.yaml конфигурация файлы

маршрут — сұрау сервер өңдеген кезде алатын жол. Platform.sh сұрауды алған кезде, ол сұрауды қайда жіберу керектігін білуі керек.

manage.py каталогымен бір каталогта .platform деп аталатын жаңа каталогты жасаңыз. Атаудың басына нүктені қосқаныңызға көз жеткізіңіз. Сол каталогтың ішіне routes.yaml деп аталатын файл жасаңыз және келесіні енгізіңіз:

.platform/routes.yaml

# Each route describes how an incoming URL will be processed by Platform.sh.
        
        "https://{default}/":
            type: upstream
            upstream: "ll_project:http"
        
        "https://www.{default}/":
            type: redirect
            to: "https://{default}/"

Бұл файл https://project_url.com және www.project_url.com сияқты сұраулардың барлығы бір жерге бағытталуын қамтамасыз етеді.

services.yaml конфигурация файлы

Бұл соңғы конфигурация файлы жобаны іске қосу үшін қажет қызметтерді көрсетеді. Бұл файлды .platform/ каталогында routes.yaml қатарында сақтаңыз:

.platform/routes.yaml

# Each service listed will be deployed in its own container as part of your
        #   Platform.sh project.
        
        db:
            type: postgresql:12
            disk: 1024

Бұл файл бір қызметті, Postgres дерекқорын анықтайды.

Platform.sh үшін settings.py өзгертілуде

Енді Platform.sh ортасының кейбір параметрлерін өзгерту үшін settings.py соңына бөлім қосу керек. Бұл кодты settings.py ең соңына қосыңыз:

settings.py

--snip/код үзіндісі--
        # Platform.sh settings.
         from platformshconfig import Config
        
        config = Config()
         if config.is_valid_platform():
             ALLOWED_HOSTS.append('.platformsh.site')
        
             if config.appDir:
                STATIC_ROOT = Path(config.appDir) / 'static'
             if config.projectEntropy:
                SECRET_KEY = config.projectEntropy
        
            if not config.in_build():
                 db_settings = config.credentials('database')
                DATABASES = {
                    'default': {
                        'ENGINE': 'django.db.backends.postgresql',
                        'NAME': db_settings['path'],
                        'USER': db_settings['username'],
                        'PASSWORD': db_settings['password'],
                        'HOST': db_settings['host'],
                        'PORT': db_settings['port'],
                    },
                }

Біз әдетте import амалдарын модульдің басында орналастырамыз, бірақ бұл жағдайда қашықтан басқаруға арналған барлық параметрлерді бір бөлімде сақтау пайдалы. Мұнда қашықтағы сервердегі параметрлерді анықтауға көмектесетін platformshconfig ❶ ішінен Config импорттаймыз. Біз параметрлерді тек config.is_valid_platform() әдісі параметрлердің Platform.sh серверінде қолданылып жатқанын көрсететін True ❷ қайтаратын болса ғана өзгертеміз.

Біз жобаға .platformsh.site ❸ арқылы аяқталатын хосттарға қызмет көрсетуге рұқсат беру үшін ALLOWED_HOSTS өзгертеміз. Тегін деңгейге орналастырылған барлық жобалар осы хост арқылы қызмет көрсетеді. Параметрлер орналастырылған қолданба каталогында ❹ жүктеліп жатса, біз статикалық файлдар дұрыс қызмет көрсететін етіп STATIC_ROOT орнатамыз. Сондай-ақ қашықтағы серверде ❺ қауіпсізырақ SECRET_KEY орнаттық.

Соңында біз өндірістік дерекқорды конфигурациялаймыз ❻. Бұл құрастыру процесі аяқталып, жобаға қызмет көрсетілсе ғана орнатылады. Мұнда көріп тұрғаныңыздың барлығы Django-ға Platform.sh жоба үшін орнатқан Postgres серверімен сөйлесуге мүмкіндік беру үшін қажет.

Жоба файлдарын қадағалау үшін Git пайдалану

17-тарауда талқыланғандай, Git - кодтың суретін алуға мүмкіндік беретін нұсқаны басқару бағдарламасы. жаңа мүмкіндікті сәтті енгізген сайын жобаны орындаңыз. Егер бірдеңе дұрыс болмаса, жобаның соңғы жұмыс суретіне оңай оралуға болады; мысалы, жаңа мүмкіндікте жұмыс істеу кезінде қатені кездейсоқ енгізсеңіз. Әрбір сурет коммит деп аталады.

Git қолданбасын пайдаланып, жобаңызды бұзу туралы алаңдамай, жаңа мүмкіндіктерді енгізіп көруге болады. Тікелей серверге орналастыру кезінде жобаңыздың жұмыс нұсқасын қолданып жатқаныңызға көз жеткізуіңіз керек. Git және нұсқаны басқару туралы қосымша ақпаратты Қосымша D қараңыз.

Git орнату

Жүйеңізде Git орнатылған болуы мүмкін. Мұны білу үшін жаңа терминал терезесін ашып, git --version пәрменін беріңіз:

(ll_env)learning_log$ git --version
        git version 2.30.1 (Apple Git-130)

Егер Git орнатылмағаны туралы хабар алсаңыз, Қосымша D бөліміндегі орнату нұсқауларын қараңыз.

Git конфигурациялау

Git жобада тек бір адам жұмыс істеп тұрса да, жобаға кім өзгерістер енгізетінін қадағалайды. Ол үшін Git пайдаланушы атыңызды және электрондық поштаңызды білуі керек. Пайдаланушы атын көрсетуіңіз керек, бірақ тәжірибе жобаларыңыз үшін электрондық поштаны жасай аласыз:

(ll_env)learning_log$ git config --global user.name "eric"
        (ll_env)learning_log$ git config --global user.email "eric@example.com"

Егер бұл қадамды ұмытып қалсаңыз, Git сізге бірінші міндеттеме жасаған кезде осы ақпаратты сұрайды.

Файлдарды елемеу

Жобадағы әрбір файлды бақылау үшін бізге Git қажет емес, сондықтан біз оған кейбір файлдарды елемеу керектігін айтамыз. manage.py бар каталогта .gitignore деп аталатын файлды жасаңыз. Бұл файл атауы нүктеден басталып, файл кеңейтімі жоқ екенін ескеріңіз. Міне, .gitignore ішіндегі код:

.gitignore

ll_env/
        __pycache__/
        *.sqlite3

Біз Git-ке бүкіл ll_env каталогын елемеуді айтамыз, себебі біз оны кез-келген уақытта автоматты түрде қайта жасай аламыз. Біз сондай-ақ __pycache__ каталогын бақыламаймыз, оның құрамында .pyc файлдары бар, олар .py файлдары орындалған кезде автоматты түрде жасалады. Біз жергілікті дерекқордағы өзгерістерді қадағаламаймыз, себебі бұл жаман әдет: егер сіз серверде SQLite қолданбасын пайдалансаңыз, жобаны серверге жіберген кезде кездейсоқ дерекқорды жергілікті сынақ дерекқорымен қайта жазуыңыз мүмкін. *.sqlite3 ішіндегі жұлдызша Git-ке .sqlite3 кеңейтімімен аяқталатын кез-келген файлды елемеу керектігін айтады.

Жобаны орындау

We need to initialize a Git repository for Learning Log, add all the necessary files to the repository, and commit the initial state of the project. Here’s how to do that:

 (ll_env)learning_log$ git init
        Initialized empty Git repository in /Users/eric/.../learning_log/.git/
         (ll_env)learning_log$ git add .
         (ll_env)learning_log$ git commit -am "Ready for deployment to Platform.sh."
        [main (root-commit) c7ffaad] Ready for deployment to Platform.sh.
         42 files changed, 879 insertions(+)
         create mode 100644 .gitignore
         create mode 100644 .platform.app.yaml
         --snip/код үзіндісі--
         create mode 100644 requirements_remote.txt
         (ll_env)learning_log$ git status
        On branch main
        nothing to commit, working tree clean
        (ll_env)learning_log$

Біз git init пәрменін оқу журналы ❶ бар каталогта бос репозиторийді инициализациялау үшін шығарамыз. Содан кейін біз ❷ репозиторийіне еленбейтін барлық файлдарды қосатын git add . пәрменін қолданамыз. (Нүктені ұмытпаңыз.) Әрі қарай, біз пәрменді шығарамыз git commit -am "commit message": -a жалау Git-ке осы міндеттемеге барлық өзгертілген файлдарды қосуды айтады, ал -m жалаушасы Git-ке журнал хабарламасын ❸ жазуды ұсынады.

git status пәрменін ❹ шығару біздің негізгі тармақта екенімізді және жұмыс ағашымыздың таза екенін көрсетеді. Бұл жобаңызды қашықтағы серверге жіберген кезде көргіңіз келетін күй.

Platform.sh сайтында жоба жасау

Осы кезде Learning Log жобасы әлі де жергілікті жүйемізде жұмыс істейді және қашықтағы серверде дұрыс жұмыс істеуге теңшелген. Серверде жаңа жоба жасау үшін Platform.sh CLI пайдаланамыз, содан кейін жобамызды қашықтағы серверге жібереміз.

Терминалда, learning_log/ каталогында екеніңізді тексеріп, келесі пәрменді орындаңыз:

(ll_env)learning_log$ platform login
        Opened URL: http://127.0.0.1:5000
        Please use the browser to log in.
        --snip/код үзіндісі--
         Do you want to create an SSH configuration file automatically? [Y/n] Y

Бұл пәрмен жүйеге кіруге болатын шолғыш қойындысын ашады. Жүйеге кіргеннен кейін шолғыш қойындысын жауып, терминалға оралуға болады. Егер сізге SSH конфигурация файлын жасау ұсынылса ❶, қашықтағы серверге кейінірек қосылу үшін Y енгізіңіз.

Енді біз жоба жасаймыз. Шығарылым көп, сондықтан жасау процесін бөлімдерде қарастырамыз. жасау пәрменін шығару арқылы бастаңыз:

(ll_env)learning_log$ platform create
        * Project title (--title)
        Default: Untitled Project
         > ll_project
        
        * Region (--region)
        The region where the project will be hosted
          --snip/код үзіндісі--
          [us-3.platform.sh] Moses Lake, United States (AZURE) [514 gC02eq/kWh]
         > us-3.platform.sh
        * Plan (--plan)
        Default: development
        Enter a number to choose:
          [0] development
          --snip/код үзіндісі--
         > 0
        
        * Environments (--environments)
        The number of environments
        Default: 3
         > 3
        
        * Storage (--storage)
        The amount of storage per environment, in GiB
        Default: 5
         > 5

Бірінші шақыру жобаның атын сұрайды ❶, сондықтан біз ll_project атауын қолданамыз. Келесі нұсқау сервердің ❷ қай аймақта болғанын қалайтынымызды сұрайды. Сізге ең жақын серверді таңдаңыз; мен үшін бұл us-3.platform.sh. Қалған сұраулар үшін әдепкі параметрлерді қабылдауға болады: ең төменгі даму жоспарындағы сервер ❸, жоба үшін үш орта ❹ және жалпы жоба үшін 5 ГБ жад ❺.

Жауап беру үшін тағы үш сұрау бар:

Default branch (--default-branch)
        The default Git branch name for the project (the production environment)
        Default: main
         > main
        
        Git repository detected: /Users/eric/.../learning_log
         Set the new project ll_project as the remote for this repository? [Y/n] Y
        
        The estimated monthly cost of this project is: $10 USD
         Are you sure you want to continue? [Y/n] Y
        
        The Platform.sh Bot is activating your project
        
              ▀▄   ▄▀
            █▄█▀███▀█▄█
            ▀█████████▀
             ▄▀     ▀▄
        
        The project is now ready!

Git репозиторийінде бірнеше тармақтар болуы мүмкін; Platform.sh бізден жобаның әдепкі тармағы main ❶ болуы керек пе деп сұрайды. Содан кейін ол жергілікті жобаның репозиторийін қашықтағы репозиторийге ❷ қосқымыз келетінін сұрайды. Ақырында, бұл жобаны тегін сынақ мерзімінен ❸ ұзағырақ іске қоссақ, айына шамамен $10 тұратыны туралы хабардар болдық. Несие картасын әлі енгізбеген болсаңыз, бұл құн туралы алаңдамауыңыз керек. Несие картасын қоспай-ақ тегін сынақ нұсқасының шегінен асып кетсеңіз, Platform.sh жай ғана жобаңызды тоқтатады.

Platform.sh жүйесіне өту

Жобаның тікелей нұсқасын көрудің алдындағы соңғы қадам біздің кодты қашықтағы серверге жіберу болып табылады. Ол үшін келесі пәрменді беріңіз:

(ll_env)learning_log$ platform push
         Are you sure you want to push to the main (production) branch? [Y/n] Y
        --snip/код үзіндісі--
        The authenticity of host 'git.us-3.platform.sh (...)' can't be established.
        RSA key fingerprint is SHA256:Tvn...7PM
         Are you sure you want to continue connecting (yes/no/[fingerprint])? Y
        Pushing HEAD to the existing environment main
          --snip/код үзіндісі--
          To git.us-3.platform.sh:3pp3mqcexhlvy.git
           * [new branch]      HEAD -> main

платформаны push пәрменін бергенде, сізден жобаны итергіңіз келетіні туралы тағы бір растау сұралады ❶. Сондай-ақ Platform.sh сайтының түпнұсқалығы туралы хабарды көруіңіз мүмкін, егер бұл сайтқа ❷ бірінші рет қосылып жатсаңыз. Осы шақырулардың әрқайсысы үшін Y енгізіңіз, сонда сіз шығыс айналдыру тобын көресіз. Бұл нәтиже алдымен түсініксіз болып көрінуі мүмкін, бірақ егер бірдеңе дұрыс болмаса, ақауларды жою кезінде оны пайдалану өте пайдалы. Шығаруды қарап шықсаңыз, Platform.sh қажетті бумаларды қай жерде орнататынын, статикалық файлдарды жинайтынын, тасымалдауларды қолданатынын және жоба үшін URL мекенжайларын орнататынын көре аласыз.

Тікелей жобаны көру

Итеру аяқталғаннан кейін жобаны ашуға болады:

(ll_env)learning_log$ platform url
        Enter a number to open a URL
          [0] https://main-bvxea6i-wmye2fx7wwqgu.us-3.platformsh.site/
          --snip/код үзіндісі--
         > 0

платформа url пәрмені орналастырылған жобамен байланысты URL мекенжайларының тізімін береді; сізге жобаңыз үшін жарамды бірнеше URL мекенжайын таңдау мүмкіндігі беріледі. Біреуін таңдаңыз, жобаңыз жаңа шолғыш қойындысында ашылуы керек! Бұл біз жергілікті орындап жатқан жобаға ұқсайды, бірақ сіз бұл URL мекенжайын әлемдегі кез-келген адаммен бөлісе аласыз және олар жобаңызға кіріп, пайдалана алады.

Platform.sh орналастыруды нақтылау

Енді біз жергілікті жерде жасағандай суперпайдаланушы жасау арқылы орналастыруды нақтылаймыз. Сондай-ақ, DEBUG параметрін False етіп өзгерту арқылы жобаны қауіпсіз етеміз, сондықтан қате туралы хабарлар пайдаланушыларға серверге шабуыл жасау үшін пайдалана алатын қосымша ақпаратты көрсетпейді. .

Platform.sh сайтында суперпайдаланушы жасау

Тірі жобаның дерекқоры орнатылды, бірақ ол толығымен бос. Біз бұрын жасаған пайдаланушылардың барлығы жобаның жергілікті нұсқасында ғана бар.

Жобаның тікелей нұсқасында суперпайдаланушыны жасау үшін қашықтағы серверде басқару пәрмендерін іске қоса алатын SSH (қауіпсіз ұяшық қабығы) сеансын бастаймыз:

(ll_env)learning_log$ platform environment:ssh
        
         ___ _      _    __                    _
        | _ \ |__ _| |_ / _|___ _ _ _ __    __| |_
        |  _/ / _` |  _|  _/ _ \ '_| '  \ _(_-< ' \
        |_| |_\__,_|\__|_| \___/_| |_|_|_(_)__/_||_|
        
         Welcome to Platform.sh.
        
         web@ll_project.0:~$ ls
        accounts  learning_logs  ll_project  logs  manage.py  requirements.txt
            requirements_remote.txt  static
         web@ll_project.0:~$ python manage.py createsuperuser
         Username (leave blank to use 'web'): ll_admin_live
        Email address:
        Password:
        Password (again):
        Superuser created successfully.
         web@ll_project.0:~$ exit
        logout
        Connection to ssh.us-3.platform.sh closed.
         (ll_env)learning_log$

платформа ортасы:ssh пәрменін алғаш рет іске қосқан кезде, осы хосттың түпнұсқалығы туралы басқа сұрауды алуыңыз мүмкін. Бұл хабарды көрсеңіз, Y енгізіңіз және қашықтағы терминал сеансына кіруіңіз керек.

ssh пәрменін іске қосқаннан кейін терминалыңыз қашықтағы сервердегі терминал сияқты әрекет етеді. Сұрауыңыз ll_project ❶ деп аталатын жобамен байланысты web сеансында екеніңізді көрсету үшін өзгергенін ескеріңіз. ls пәрменін шығарсаңыз, Platform.sh серверіне жіберілген файлдарды көресіз.

Біз 18-тарауда пайдаланған бірдей createsuperuser пәрменін шығарыңыз ❷. Бұл жолы мен әкімші пайдаланушы атын енгіздім, ll_admin_live, бұл мен жергілікті қолданатын ❸ атауынан ерекше. Қашықтағы терминал сеансында жұмысты аяқтағаннан кейін шығу пәрменін ❹ енгізіңіз. Сұрау жергілікті жүйеде қайтадан жұмыс істеп жатқаныңызды көрсетеді ❺.

Енді тірі қолданбаның URL мекенжайының соңына /admin/ қосып, әкімші сайтына кіре аласыз. Басқалар жобаңызды пайдалана бастаған болса, олардың барлық деректеріне қол жеткізе алатыныңызды ескеріңіз! Бұл жауапкершілікті байыппен қабылдаңыз, сонда пайдаланушылар өз деректерімен сізге сенуді жалғастырады.

Тірі жобаны қорғау

Біздің жобамызды қазіргі уақытта қолдану жолында бір маңызды қауіпсіздік мәселесі бар: жөндеу туралы хабарларды қамтамасыз ететін settings.py ішіндегі DEBUG = True параметрі. қателер пайда болған кезде. Django қате беттері жобаны әзірлеу кезінде сізге маңызды жөндеу туралы ақпаратты береді; дегенмен, егер сіз оларды тікелей серверде қосулы қалдырсаңыз, олар шабуылдаушыларға тым көп ақпарат береді.

Мұның қаншалықты нашар екенін көру үшін енгізілген жобаның басты бетіне өтіңіз. Пайдаланушының есептік жазбасына кіріп, негізгі беттің URL мекенжайының соңына /topics/999/ қосыңыз. Мыңдаған тақырыптарды жасамаған болсаңыз, /topics/999/ мекенжайында NotExist» хабары бар бетті көруіңіз керек. Төменге айналдырсаңыз, жоба мен сервер туралы ақпараттың толық жиынтығын көресіз. Пайдаланушыларыңыздың мұны көргенін қаламайсыз және бұл ақпараттың сайтқа шабуыл жасауға мүдделі кез-келген адамға қолжетімді болуын қаламайсыз.

Бұл ақпараттың тек орнатылған нұсқасына қолданылатын settings.py бөлігінде DEBUG = False параметрін орнату арқылы тікелей сайтта көрсетілуіне жол бермей аламыз. жоба. Осылайша сіз бұл ақпарат пайдалы, бірақ ол тікелей эфирде көрсетілмейді.

Мәтіндік өңдегіште settings.py ашыңыз және Platform.sh параметрлерін өзгертетін бөлікке кодтың бір жолын қосыңыз:

settings.py

--snip/код үзіндісі--
        if config.is_valid_platform():
            ALLOWED_HOSTS.append('.platformsh.site')
            DEBUG = False
            --snip/код үзіндісі--

Жобаның енгізілген нұсқасы үшін конфигурацияны орнату бойынша барлық жұмыстар өз нәтижесін берді. Жобаның тікелей нұсқасын реттегіміз келгенде, біз жай ғана бұрын орнатқан конфигурацияның тиісті бөлігін өзгертеміз.

Өзгерістерді енгізу және басу

Енді біз settings.py ішіне енгізілген өзгерістерді орындауымыз керек және өзгертулерді Platform.sh сайтына жылжытуымыз керек. Міне, осы процестің бірінші бөлігін көрсететін терминал сеансы:

 (ll_env)learning_log$ git commit -am "Set DEBUG False on live site."
        [main d2ad0f7] Set DEBUG False on live site.
          1 file changed, 1 insertion(+)
         (ll_env)learning_log$ git status
        On branch main
        nothing to commit, working tree clean
        (ll_env)learning_log$

Біз git commit пәрменін қысқа, бірақ сипаттайтын міндеттеме хабарламасымен ❶ шығарамыз. -am жалауын есте сақтаңыз, Git өзгертілген барлық файлдарды орындайтынына және журнал хабарын жазатынына көз жеткізіңіз. Git бір файлдың өзгергенін таниды және бұл өзгерісті репозиторийге жібереді.

git status іске қосылуы репозиторийдің main тармағында жұмыс істеп жатқанымызды және енді ❷ орындалатын жаңа өзгерістер жоқ екенін көрсетеді. Қашықтағы серверге баспас бұрын күйді тексеру маңызды. Таза күйді көрмесеңіз, кейбір өзгертулер жасалмаған және бұл өзгерістер серверге жіберілмейді. commit пәрменін қайта шығарып көруге болады; егер мәселені қалай шешу керектігін білмесеңіз, Git-пен қалай жұмыс істеу керектігін жақсырақ түсіну үшін D қосымшасын оқып шығыңыз.

Енді жаңартылған репозиторийді Platform.sh сайтына көшірейік:

(ll_env)learning_log$ platform push
        Are you sure you want to push to the main (production) branch? [Y/n] Y
        Pushing HEAD to the existing environment main
        --snip/код үзіндісі--
          To git.us-3.platform.sh:wmye2fx7wwqgu.git
             fce0206..d2ad0f7  HEAD -> main
        (ll_env)learning_log$

Platform.sh репозиторийдің жаңартылғанын таниды және барлық өзгерістер ескерілгеніне көз жеткізу үшін жобаны қайта құрады. Ол дерекқорды қайта жасамайды, сондықтан біз ешбір деректерді жоғалтқан жоқпыз.

Бұл өзгерістің күшіне енгеніне көз жеткізу үшін /topics/999/ URL мекенжайына қайта кіріңіз. Сіз тек Сервер қатесі (500) хабарын көресіз, жоба туралы құпия ақпарат мүлде жоқ.

Теңшелетін қате беттерін жасау

19-тарауда пайдаланушы тақырыпты немесе жазбаны сұраса, оқу журналын 404 қатесін қайтаратын етіп конфигурацияладық. t оларға тиесілі. Енді сіз 500 сервер қатесін көрдіңіз. 404 қатесі әдетте Django кодының дұрыс екенін білдіреді, бірақ сұралатын нысан жоқ. 500 қатесі әдетте сіз жазған кодта қате бар екенін білдіреді, мысалы, views.py ішіндегі функциядағы қате. Django қазіргі уақытта екі жағдайда бірдей жалпы қате бетін қайтарады, бірақ біз Learning журналының жалпы көрінісіне сәйкес келетін өзіміздің 404 және 500 қате беттерінің үлгілерін жаза аламыз. Бұл үлгілер түбірлік үлгі каталогына жатады.

Арнаулы үлгілерді жасау

learning_log каталогында үлгілер деп аталатын жаңа каталог жасаңыз. Содан кейін 404.html деп аталатын жаңа файл жасаңыз; бұл файлға жол learning_log/templates/404.html болуы керек. Міне, осы файлдың коды:

404.html

{% extends "learning_logs/base.html" %}
        
        {% block page_header %}
          <h2>The item you requested is not available. (404)</h2>
        {% endblock page_header %}

Бұл қарапайым үлгі 404 қате туралы жалпы ақпарат береді, бірақ сайттың қалған бөлігімен сәйкестендіру үшін стильдендірілген.

Келесі кодты пайдаланып 500.html деп аталатын басқа файлды жасаңыз:

500.html

{% extends "learning_logs/base.html" %}
        
        {% block page_header %}
          <h2>There has been an internal error. (500)</h2>
        {% endblock page_header %}

Бұл жаңа файлдар settings.py файлына сәл өзгертуді қажет етеді.

settings.py

--snip/код үзіндісі--
        TEMPLATES = [
            {
                'BACKEND': 'django.template.backends.django.DjangoTemplates',
                'DIRS': [BASE_DIR / 'templates'],
                'APP_DIRS': True,
                --snip/код үзіндісі--
            },
        ]
        --snip/код үзіндісі--

Бұл өзгерту Django-ға қате бет үлгілерін және белгілі бір қолданбамен байланысы жоқ кез-келген басқа үлгілерді түбірлік үлгілер каталогынан іздеуді ұсынады.

Platform.sh жүйесіне өзгертулер енгізу

Енді біз жаңа ғана енгізілген өзгерістерді орындап, оларды Platform.sh сайтына жіберуіміз керек:

 (ll_env)learning_log$ git add .
         (ll_env)learning_log$ git commit -am "Added custom 404 and 500 error pages."
         3 files changed, 11 insertions(+), 1 deletion(-)
         create mode 100644 templates/404.html
         create mode 100644 templates/500.html
         (ll_env)learning_log$ platform push
        --snip/код үзіндісі--
          To git.us-3.platform.sh:wmye2fx7wwqgu.git
             d2ad0f7..9f042ef  HEAD -> main
        (ll_env)learning_log$

Біз git add . пәрменін ❶ шығарамыз, себебі жобада кейбір жаңа файлдар жасалды. Содан кейін біз өзгерістерді орындаймыз ❷ және жаңартылған жобаны Platform.sh ❸ сайтына жібереміз.

Енді қате беті пайда болған кезде, ол сайттың қалған бөлігімен бірдей стильде болуы керек, бұл қателер туындаған кезде пайдаланушы тәжірибесін біркелкі етеді.

Ағымдағы даму

Тікелей серверге бастапқы итерілгеннен кейін Learning журналын одан әрі дамытқыңыз келуі мүмкін немесе орналастыру үшін өз жобаларыңызды дамытқыңыз келуі мүмкін. Бұл кезде жобаларды жаңарту үшін жеткілікті дәйекті процесс бар.

Біріншіден, жергілікті жобаңызға қажетті өзгерістерді енгізесіз. Өзгертулеріңіз нәтижесінде кез-келген жаңа файлдар болса, сол файлдарды git add . пәрмені арқылы Git репозиторийіне қосыңыз (пәрменнің соңына нүктені қосуды ұмытпаңыз). Дерекқорды тасымалдауды қажет ететін кез-келген өзгерту осы пәрменді қажет етеді, себебі әрбір тасымалдау жаңа тасымалдау файлын жасайды.

Екіншіден, git commit -am "коммит хабары" арқылы репозиторийіңізге өзгертулерді орындаңыз. Содан кейін platform push пәрменін пайдаланып, өзгертулерді Platform.sh сайтына жылжытыңыз. Тікелей жобаға кіріп, күтілетін өзгерістердің күшіне енгеніне көз жеткізіңіз.

Бұл процесс кезінде қателесу оңай, сондықтан бірдеңе дұрыс емес болып жатса таң қалмаңыз. Егер код жұмыс істемесе, не істегеніңізді қарап шығыңыз және қатені анықтауға тырысыңыз. Қатені таба алмасаңыз немесе оны жою жолын таба алмасаңыз, Қосымша С бөліміндегі анықтама алу бойынша ұсыныстарды қараңыз. Көмек сұраудан ұялмаңыз: барлығы сіз қоятын сұрақтарды қою арқылы жобаларды құруды үйренді, сондықтан біреу сізге көмектесуге қуанышты болады. Пайда болған әрбір мәселені шешу мағыналы, сенімді жобаларды құрып, басқа адамдардың сұрақтарына жауап бермейінше, дағдыларыңызды тұрақты дамытуға көмектеседі.

Platform.sh жүйесіндегі жобаны жою

Орналастыру процесін үйрену үшін бір жобамен немесе бірқатар шағын жобалармен бірнеше рет қолдану тамаша тәжірибе. Бірақ сіз енгізілген жобаны қалай жою керектігін білуіңіз керек. Platform.sh сонымен қатар тегін орналастыруға болатын жобалардың санын шектейді және есептік жазбаңызды тәжірибелік жобалармен толтырғыңыз келмейді.

CLI арқылы жобаны жоюға болады:

(ll_env)learning_log$ platform project:delete

Сізден осы жойқын әрекетті жасағыңыз келетінін растау сұралады. Сұрауларға жауап беріңіз, сонда жобаңыз жойылады.

платформа жасау пәрмені сонымен қатар жергілікті Git репозиторийіне Platform.sh серверлеріндегі қашықтағы репозиторийге сілтеме берді. Бұл қашықтан басқару құралын пәрмен жолынан да жоюға болады:

(ll_env)learning_log$ git remote
        platform
        (ll_env)learning_log$ git remote remove platform

git remote пәрмені ағымдағы репозиториймен байланыстырылған барлық қашықтағы URL мекенжайларының атауларының тізімін береді. git remote remove remote_name пәрмені бұл қашықтағы URL мекенжайларын жергілікті репозиторийден жояды.

Сонымен қатар Platform.sh веб-сайтына кіру және https://console сайтындағы бақылау тақтасына кіру арқылы жоба ресурстарын жоюға болады. .platform.sh. Бұл бетте барлық белсенді жобалар тізімі берілген. Жоба жолағындағы үш нүктені басып, Жоспарды өңдеу түймесін басыңыз. Бұл жобаның баға беті; беттің төменгі жағындағы Жобаны жою түймесін басыңыз, сонда сізге жоюды жалғастыруға болатын растау беті көрсетіледі. CLI арқылы жобаңызды жойсаңыз да, сіз орналастыратын кез-келген хостинг провайдерінің бақылау тақтасымен танысқаныңыз жөн.

Қорытынды

Бұл тарауда Bootstrap кітапханасы мен django-bootstrap5 қолданбасы арқылы жобаларыңызға қарапайым, бірақ кәсіби көрініс беруді үйрендіңіз. Bootstrap көмегімен сіз таңдаған стильдер жобаңызға кіру үшін адамдар пайдаланатын кез-келген дерлік құрылғыда тұрақты жұмыс істейді.

Сіз Bootstrap үлгілері туралы білдіңіз және Navbar static үлгісін Оқыту журналының қарапайым көрінісі мен сезімін жасау үшін пайдаландыңыз. Сіз басты беттің хабарын ерекше ету үшін жұмботронды қолдандыңыз және сайттағы барлық беттерді дәйекті түрде стильдеуді үйрендіңіз.

Жобаның соңғы бөлігінде сіз жобаны қашықтағы серверге қалай орналастыру керектігін үйрендіңіз, сонда кез-келген адам оған қол жеткізе алады. Platform.sh тіркелгісін жасадыңыз және орналастыру процесін басқаруға көмектесетін кейбір құралдарды орнаттыңыз. Сіз жұмыс жобасын репозиторийге тапсыру үшін Git қолданбасын пайдаландыңыз, содан кейін репозиторийді Platform.sh сайтындағы қашықтағы серверге итермеледіңіз. Соңында, сіз тікелей серверде DEBUG = False параметрін орнату арқылы қолданбаңызды қорғауды бастауды үйрендіңіз. Сіз сондай-ақ пайдаланушы қате беттерін жасадыңыз, сондықтан пайда болатын қателер жақсы өңделген болып көрінеді.

Оқу журналын аяқтағаннан кейін, өз жобаларыңызды құруға кірісуге болады. Қарапайымнан бастаңыз және күрделілік қоспас бұрын жобаның жұмыс істейтініне көз жеткізіңіз. Оқуды жалғастырып, жобаларыңызға сәттілік тілейміз!

Сөздік

ITUniver

Ағылшынша-Қазақша терминдер сөздігі. Кейбір аудармаларға түсініктеме

# Ағылшын тілінде Қазақ тілінде Түсініктеме
1 stack of items элементтер дестесі The term pop comes from thinking of a list as a stack of items / pop термині тізімді элементтер жинағы ретінде ойлаудан шыққан
1 Skill Дағды, шеберлік бір нәрсені жақсы істеу қабілеті. ерекше қабілет.

ChatGPT

Python-ды ChatGPT-дан сұраймыз!

sys модульі

Python Docs: sys — System-specific parameters and functions

Python тілінде import sys — кірістірілген sys модулін ағымдағы Python скриптіне немесе ортасына импорттайтын амал/statement. sys модулі Python интерпретаторы пайдаланатын немесе қолдайтын кейбір айнымалы мәндерге, сондай-ақ Python орындалу ортасымен әрекеттесетін функцияларға қол жеткізуді қамтамасыз етеді.

    sys модулінің кейбір жалпы пайдаланулары мыналарды қамтиды:

  • пәрмен жолы арқылы берілген аргументтерге скриптіден қатынасу үшін sys.argv-ті пайдалану
  • sys.exit() арқылы Python скриптінен шығуға болады
  • Нұсқа нөмірі, платформа және ең үлкен бүтін өлшем сияқты Python интерпретаторы және орындалу ортасы туралы ақпаратқа қол жеткізу.
  • Python интерпретаторының әдепкі әрекетін өзгерту, мысалы, рекурсия шегін орнату немесе алу арқылы.

          import sys

          # Accessing command-line arguments
          print("Command-line arguments:", sys.argv)

          # Accessing information about the Python interpreter
          print("Python version:", sys.version)
          print("Platform:", sys.platform)
        

Шарт негізінде Python скриптіден шығу үшін sys.exit() пайдалануды көрсететін тағы бір мысал:


          import sys

          # Prompt the user to enter a number
          number = input("Enter a number: ")

          # Convert the input to an integer
          try:
              number = int(number)
          except ValueError:
              print("Error: Invalid input. Please enter a valid integer.")
              sys.exit(1)  # Exit with an error code 1 if the input is not a valid integer

          # Check if the number is positive
          if number <= 0:
              print("Error: The number must be positive.")
              sys.exit(1)  # Exit with an error code 1 if the number is not positive

          # If the number is positive, calculate its square
          square = number ** 2
          print("Square of", number, "is", square)
        
        

Бұл мысалдарда `import sys` бізге `sys.argv`, `sys.exit()`, `sys.version` және `sys.platform` атрибуттарына қол жеткізуге мүмкіндік береді. Бұл атрибуттар сәйкесінше скриптіден, Python нұсқасынан және платформадан шығу пәрмен жолы аргументтері туралы ақпаратты береді.

if __name__ == '__main__': - деген не?

if __name__ == '__main__': main() — скрипт тікелей іске қосылған кезде main() деп аталатын функцияны орындау үшін Python скриптілерінде пайдаланылатын жалпы констурктор. Сізге оны егіжей-тегіжейлі ашып көрсетуге рұқсат етіңіз:

  • __name__ - Python-да __name__ ағымдағы модульдің атын ұстап тұратын арнайы айнымалы. Python скрипті негізгі бағдарлама ретінде іске қосылатын болса __name__ мәні __main__ деп қойылады. Егер скрипт басқа скриптіге модуль ретінде import-талса __name__ мәні модульдің атымен қойылады.
  • __main__: Бұл Python тіліндегі негізгі модульдің атын білдіретін тіркес. Скрипт бірден өзі іске қосылатын болса (импортталмай), оның аты (__name__) __main__ деп қойылады.

    Демек, if __name__ == '__main__': код жолы скрипті бірден Python интерпретаторында орындалып жатыр ма? соны тексереді.

Міне не болып жатыр, қараңыз:

  • Скрипт интерпретаторда бірден, тікелей орындалып жатса, __name__ мәне __main__ болады, және if __name__ == '__main__': шартының мәне True деген сөз.
  • Сондықтан, main() функциясы (немесе шарттан кейінге кез-келген код) орындалады деген сөз.

Бұл құрылымның идеясы скриптті басқа скриптіге модуль ретінде импорттағанда іске қосылуы керек кодтан скрипт орындалған кезде іске қосылатын кодты бөлу болып табылады. Бұл кодты ұйымдастыруға көмектеседі және модульдерді импорттау кезінде кодтың белгілі блоктарының байқаусызда іске қосылуын болдырмайды.


          def main():
              print("Бұл негізгі функция.")

          if __name__ == '__main__':
              main()
        

Бұл мысалдағы скрипт тікелей іске қосылғанда, main() функциясы орындалады және «Бұл негізгі функция.» басып шығарылады. Егер скрипт басқа модульге импортталса, main() функциясы автоматты түрде орындалмайды.