ԴԱՍԸՆԹԱՑՆԵՐԻ ՄԱՏՅԱՆ
Դասընթացներին վերաբերվող նյութեր և նշումներ
Table of Contents
- ԳԼԽԱՎՈՐ
- ԴԱՍԸՆԹԱՑՆԵՐ
- 1. Տեղեկատվական տեխնոլոգիաներ
- 1.1 Ծանոթություն
- 1.2 Տեղեկատվություն կամ ինֆորմացիա
- 1.3 Վերացականություն (Abstraction)
- 1.4 Սարքավորումներ (Hardware)
- 1.5 Ծրագրային միջավայր (Software)
- 1.6 Շարահյուսություն (Syntax)
- 1.7 Իմաստաբանություն (Semantics)
- 1.8 Տվյալներ (Data)
- 1.9 Ալգորիթմներ
- 1.10 Ծրագրավորում
- 1.11 Ցանց (Network)
- 1.12 Արտադրական պրոցես
- 2. Համակարգչային գրաֆիկայի հիմունքներ
- 3. Ծրագրավորում
- 3.1 Միջավայր
- 3.2 Պարադիգմ և կատարման փուլ
- 3.3 Ֆունկցիոնալ ծրագրավորման մոդել
- 3.4 Օբյեկտ֊օրիենտացված մոտեցում (Java)
- 3.5 Ինկապսուլյացիա, ժառանգականություն, պոլիմորֆիզմ (Java)
- 3.6 Օբյեկտ֊օրիենտացման գործիքներ և հավաքածուներ (Java)
- 3.7 Պրակտիկ (Java)
- 3.8 Մուլտիպարադիգմ մոտեցում (Python)
- 3.9 Ֆունկցիոնալ գործիքներ (Python)
- 3.10 Այլ պրակտիկ գործիքներ (Python)
- 3.11 Օբյեկտ֊օրիենտացման գործիքներ (Python)
- 3.12 Ֆունկցիոնալ մոտեցում (Lisp)
- 3.13 «Զուտ» ֆունկցիոնալ մոտեցում (Haskell)
- 3.14 Ալգորիթմներ (պրակտիկ)
- 3.15 Տվյալների Բազա
- 3.16 Ցանցային հաղորդակցություն
- 3.17 Web ծրագրավորման բաղադրիչներ
- 3.18 Պրակտիկ
- 1. Տեղեկատվական տեխնոլոգիաներ
- ԸՆԴՀԱՆՈՒՐ ՀՂՈՒՄՆԵՐ
- ՏԵՐՄԻՆՆԵՐԻ ԲԱՌԱՐԱՆ
ԳԼԽԱՎՈՐ
Էջի մասին
Այս էջում հրապարակվելու են դասընթացների վերաբերյալ բոլոր նյութերը, հղումները և պրակտիկ աշխատանքները՝ դասընթացների անցկամանը զուգահեռ։
PowerPoint ձևաչափով սլայդերը կարող եք դիտել նաև վեբ֊հավելվածի օգնությամբ։ Հավելվածից օգտվելու համար հարկավոր է ունենալ Microsoft հաշիվ (account):
- Հետադարձ կապ
- info@ingenium.am - ընդհանուր հարցերի համար
lmelikyan@ingenium.am - դասընթացների բովանդակությանը վերաբերող հարցերի համար
ԴԱՍԸՆԹԱՑՆԵՐ
1. Տեղեկատվական տեխնոլոգիաներ
1.1 Ծանոթություն
1.2 Տեղեկատվություն կամ ինֆորմացիա
1.3 Վերացականություն (Abstraction)
Պարզաբանում
Ռեկուրսիան, դիտարկելով միայն որպես վերացկանություն (ընդհանուր հասկացություն), չի արտացոլում Համակարգչային գիտության (Computer Science) մեջ կիրառական կարևորությունն ու լայն հնարավորությունները։ Այդ իսկ պատճառով՝ Լեզվական շարահյուսություն (1.6), Տվյալներ (1.8) և Ալգորիթմներ (1.9) դասընթացների ընթացքում առանձին դիտարկվելու են ռեկուրսիայի համապատասխան կիրառական մոդելները։
Հետևյալ արխիվային ֆայլը [ droste.zip ] կիրառական որևէ արժեք չի ներկայացնում, բայց, որպես ռեկուրսիվ տվյալի իրական իմպլեմենտացիա, հետաքրքիր կարող է լինել ուսումնասիրության տեսանկյունից։
- Վիզուալ հաշվիչ՝ տարբեր հիմքով թվերի զուգահեռ արտապատկերմամբ։
- Հղում ծանոթության համար - ASCII, Unicode
1.4 Սարքավորումներ (Hardware)
Հետևյալ հղումներով կարելի է տեսնել MOS 6502 պրոցեսորի աշխատանքի վիզուալ սիմուլյացիան`
- Հղում ծանոթության համար - RAID
1.5 Ծրագրային միջավայր (Software)
1.6 Շարահյուսություն (Syntax)
1.7 Իմաստաբանություն (Semantics)
1.8 Տվյալներ (Data)
1.9 Ալգորիթմներ
1.10 Ծրագրավորում
1.12 Արտադրական պրոցես
2. Համակարգչային գրաֆիկայի հիմունքներ
2.1 Ներածական
2.2 Տարածական և գունային մոդելներ
2.3 Ռաստերային գրաֆիկա
2.4 Վեկտորային գրաֆիկա
2.5 Եռաչափ գրաֆիկա
2.6 Փոխարկում (Conversion)
3. Ծրագրավորում
3.1 Միջավայր
- Environment
- Path - հասցե (հասկացողություն)
Ֆայլային համակարգի հասցեավորման ձևաչափ, որով բնորոշվում է ֆայլի եզակի հասցեն։
Տես՝ Path - փոփոխական
Յուրաքանչյուր հասցե, ըստ POSIX ստանդարտի, պարունակում է առնվազն երկու «ենթահասցե» (sub-directory)`
.
- current directory և..
- parent directory: Հասցեն կարող է լինել ամբողջական (absolute-path) և հարաբերական (relative-path)` որևէ հասցեի նկատմամբ (լռելյայն՝ current directory):
Հասցեավորման առանձնահատկությունները տարբերվում են՝ կախված օպերացիոն համակարգի և ֆայլային համակարգի համադրությունից.
UNIX-like Windows Ելակետ (root) /
<letter>:
Բաժանիչ /
\
(/
- մուտք)Case sensitive insensitive Նշաններ բացառությամբ /
բացառությամբ /\:*”?<>
Օրինակներ /
(root),/usr/bin
,../../home
D:\
(root),C:\Users\Public
,../Users/Public
DOS/Windows ՕՀ֊երում յուրաքանչյուր կրիչ ունի սեփական ելակետային հասցե:
Գրեթե բոլոր ժամանակակից ֆայլային համակարգերը Unicode համատեղելի են և case-sensitive` բացառությամբ օպերացիոն համակարգի առանձնահատկությունների (օրինակ՝ DOS / Windows)։
Հարաբերական (relative) հասցեներն, ի տարբերություն ամբողջական (absolute) հասցեների, կարող են չներառել ելակետային հասցեն և «հիմք» ընդունել կատարման ենթակա ֆայլի հասցեն, ինչն ապահովում է միևնույն հասցեավորման կառուցվածի համատեղելիությունը տարբեր համակարգերում։ Օրինակ՝
../files/
կամ./images/pic.jpg
:
- Environment variables
Օպերացիոն համակարգի փոփոխականներ, որոնք կրում են կանխորոշված արժեքներ՝ որպես հասցե կամ հատուկ կարգավորում, և հասանելի են ՕՀ֊ում կատարման ենթակա բոլոր պրոցեսներին։
Windows ՕՀ֊ի միջավայրի փոփոխականները գտնվում են հետևյալ կարգավորման պատուհանում՝
Control Panel
-System
-Advanced system settings
(ձախ մենյուից) -Environment Variables...
(ներքևի աջ անկյունում)։ Համապատասխան կարգավորումները հարկավոր է կատարելSystem variables
դաշտում։
Փոփոխականների արժեքները կարելի է ստանալ հղում հատուկ ձևաչափով, օրինակ՝
$PATH
(UNIX-like),%PATH%
(DOS/Windows)։
- Path - հասցե (հասկացողություն)
- Terminal - CLI
Հրամանների տողի միջերեսը (Command-Line Interface) կամ տերմինալը, ըստ POSIX ստանդարտի, օպերացիոն համակարգի ֆունկցիոնալի հետ փոխհամագործակցության միջերես է։
DOS և GNU/Linux ՕՀ֊երում տերմինալն առաջնային միջերեսն է։
MacOS ՕՀ֊երում կա հատուկ հավելված`Termial
:
Window ՕՀ֊երում տերմինալի դեր է կատարումcmd
հավելվածը։
- Տերմինալի աշխատանքը
Տերմինալի հետ փոխհամագործակցությունը տեղի է ունենում.
- հրամանների կամ հավելվածների (եթե վերջինների հասցեները պահպանված են Path փոփոխականում) և դրանց արգումենտների ներմուծմամբ,
- արդյունքի արտաբերմամբ, եթե այդպիսին նախատեսվում է, կամ սխալների պարագայում դրանց արտաբերմամբ։
DOS/Windows ՕՀ֊երի հրամանների ցանկը կարելի է ստանալ
help
հրամանի օգնությամբ (առանց արգումենտների)։
Տերմինալում կատարման ընթացքը դադարեցնելու կամ հրամանը չեղարկելու համար հարկավոր է ստեղնաշարի օգնությամբ կատարել
Ctrl-C
հրամանը։
Օրինակներ․
Help and docs
# UNIX-like <command> --help man <command> # Windows <command> /? # on Windows/DOS native commands only help <command>
Get current (working) directory
# UNIX-like pwd # print working directory # Windows cd # print working directory with no-args only
List files and directories
# UNIX-like ls # list files and directories ls -l # list as long listing ls -la # list all (+ hidden) as long listing # Windows dir # list files and directories
-- UNIX-like output (ls -l) -- drwxr-xr-x 5 user users 4096 2020-08-31 01:26 . drwxr-xr-x 4 user users 4096 2020-08-31 01:05 .. drwxr-xr-x 3 user users 4096 2020-07-27 14:10 counter drwxr-xr-x 2 user users 4096 2020-07-11 00:02 files drwxr-xr-x 4 user users 4096 2020-05-31 19:15 styles -rw-r--r-- 1 user users 36205 2020-08-31 01:26 Docs.org -rw-r--r-- 1 user users 645 2020-07-26 23:55 counter.html -rw-r--r-- 1 user users 17757 2020-05-29 00:22 example.html -rw-r--r-- 1 user users 766 2020-05-26 21:17 favicon.ico -rw-r--r-- 1 user users 70634 2020-08-31 01:10 index.html
-- Windows output (dir) -- 2020-08-31 22:41 <DIR> . 2020-08-31 22:41 <DIR> .. 2020-08-31 20:09 <DIR> Desktop 2020-08-20 16:16 <DIR> Documents 2020-06-27 18:21 <DIR> Favorites 2020-08-31 22:40 3,005 lorem-ipsum.txt 2020-06-27 18:21 <DIR> Music 2020-06-27 18:21 <DIR> Pictures 2020-06-27 18:21 <DIR> Searches 2020-06-27 18:21 <DIR> Videos 1 File(s) 3,005 bytes 9 Dir(s) 272,352,854,016 bytes free
Change directory
Առանց արգումենտիcd
հրամանը Windows ՕՀ֊ում տպում է աշխատանքային հասցեն (working directory)։
cd # change directory to user's HOME on UNIX-like systems cd <name> # change to <name> directory (if exists) cd .. # go up to one directory cd ../.. # go up to two directories (\ - backslash on Windows)
Make directory
mkdir <name> # creates a new directory <name> in current directory mkdir -p <name1>/<name2> # UNIX-like only - creates chain of directories
- հրամանների կամ հավելվածների (եթե վերջինների հասցեները պահպանված են Path փոփոխականում) և դրանց արգումենտների ներմուծմամբ,
- Escape character
Հատուկ տառանշան (character), որն այլ կերպ է մեկնաբանում հաջորդող տառանշանները։
Օրինակ՝ տերմինալում բացատ (space) պարունակող հասցեներ ներմուծելու դեպքում տերմինալը մեկնաբանում է բացատը որպես հրամանի կամ արգումենտի ավարտ։ Նման դեպքում կարող ենք տերմինալի «ուշադրությունը շեղենք» բացատից escape characte -ով։ Հասցեների պարագայում, երբ նշվում է, օրինակ, ֆայլի անվանումը, կարելի է անվանումը վերցնել կրկնակի
"
չակերտի մեջ, օրինակ՝cd "New Folder"
:
UNIX-like ՕՀ֊երի տերմինալում և, առհասարակ, տեքստային ինֆորմացիայի պարագայում հատուկ դեր ունի
\
(հակառակ կոտորակ) նշանը:
DOS/Windows ՕՀ֊երի տերմինալում հատուկ նշան է
^
, որը մեկնաբանում է&, |, (, ), <, >, ^
նշանները, իսկ բացատի պարագայում ընդհանուր հատվածը վերցվում է կրկնակի չակերտների"
մեջ։ Ծրագրավորման մաս կազմող տեքստային ինֆորմացիայի պարագայում գործում է UNIX-like ՕՀ֊երի նշանային համակարգը։
# UNIX-like mkdir New Folder # ERROR - too many arguments mkdir New\ Folder mkdir "New Folder" mkdir Mike\'s\ folder # Mike's folder mkdir \"BIG\"\ folder # "BIG" folder (DOS/Windows doesn't support <">!) # Windows mkdir New Folder # creates TWO folders - New and Folder mkdir "New Folder" cd New Folder # change directory to New Folder cd "New Folder" # same as above echo <tag> # ERROR - The syntax of the command is incorrect. echo ^<tag^> # <tag>
- Control character
Կարգավորիչ նշան տառանշանների ցանկում (character set), որը չունի տպագրային էլեմենտ ֊ ASCII աղյուսակում՝ 32-ից ցածր բոլոր նշանները, օրինակ՝
0x0A
LF (line feed, newline),0x0D
CR (carriage return) կամ0x09
TAB։
Ծրագրավորման մաս կազմող տեքստային ինֆորմացիայի պարագայում, որպես բացառություն, որոշ կարգավորիչ նշաններ escape character
\
օգնությամբ ստանում են տառանշանային փոխարինող, օրինակ՝
\'
- single quote
\"
- double quote
\\
- backslash
\n
- new line
\r
- carriage return
\t
- tab
\0
- null character (U+0000 NULL) (only if the next character is not a decimal digit)
\xFF
- character represented by the hexadecimal byte "FF"
- Տերմինալի աշխատանքը
3.2 Պարադիգմ և կատարման փուլ
- Տիպային համակարգ
Ծրագրավորման որոշակի կանոնների ամբողջություն, որոնք «տիպային» հատկությամբ են բնորոշում համակարգչային հավելվածների տարբեր բաղադրիչներ, ինչպիսիք են փոփոխականները (variables), արտահայտությունները (expressions), ֆունկցիաները (functions), և այլ։
Տիպիզացիայի հիմնական նպատակն է վերհանել տվյալների համադրությամբ պայմանավորված խնդիրները (bug-երը)՝ փոխկապակցելով հավելվածների տարբեր մասերը և նախօրոք ստուգելով դրանց «կայունությունը» (consistency)։ Ստուգումները կարող են կատարվել կազմման (compile-time) կամ կատարման (runtime) փուլերում՝ կախված լեզվի և կատարման միջավայրի տիպիզացիոն առանձնաhատկություններից։
Typing Example Notes Static int x = 2;
ՈՒղղակի հայտարարություն Dynamic x = 2
Անուղղակի հայտարարություն Strong 2 + 1.5
throws type errorՏվյալը կցված է որոշակի տիպի Week 2 + 1.5 = 3.5
converts 2 to floatՏվյալն ազատ է (կարող է փոխարկվել) Manifest 2 :int + 1.5 :float
throws type errorՈՒղղակի նույնականացում Inferred 2 + 1.5
generalize both (:num) types to :fractionalԱռավել ընդհանրացված տիպի դուրսբերում Strict1 new A()
not equal tonew B()
Տվյալները միայն հայտարարված անվանմամբ են նույնատիպ3 Duck2 new A()
equalsnew B()
Տվյալները կարող են համարվել նույնատիպ կառուցվածքով3 - Also called Nominal or Nominative
- Also called Structural
- Data declared as
record A {float x; float y;}
andrecord B {float x; float y;}
- Also called Nominal or Nominative
- Stack & Heap
Օպերացիոն համակարգի միջավայրում հավելվածին հասանելի հիշողության կառավարումը (memory management) ենթադրում է որոշակի հիշողության հատկացում և ազատում, երբ դրա կարիքն այլևս չկա։
Հիշողության ստատիկ հատկացման համար գործարկվում է stack, դինամիկ հատկացման համար՝ heap:
- Stack
Այստեղ, յուրաքանչյուր միջակայքի (scope) կատարման ենթակա տվյալները (փոփոխականները) պահվում են հաջորդական տրամաբանությամբ, իսկ ամբողջ հիշողությունը հատկացվում է նախքան կատարման փուլի մեկնարկը։
Կատարման փուլում առաջնային ֆունկցիան կարող է կանչել (call) մեկ այլ ֆունկցիա՝ դադարեցնելով սեփական կատարումը և սպասելով արդյունքի, հերթական կատարման միջակայքում կարող է կանչվել մեկ ուրիշ ֆունկցիա, և այլն։ Տվյալ հերթականությունը պահպանվում է LIFO (Last In, First Out) տրամաբանությամբ, և պարզեցնում է հիշողության ազատումը յուրաքանչյուր կատարման փուլի ավարտով։
- Heap
Անկախ կատարման միջակայքից և հաջորդականությունից՝ տվյալների համար հիշողություն հատկացվում է կատարման փուլում, իսկ հասանելի հիշողությունը սահմանափակվում է միայն ֆիզիկական հիշողությամբ։
Տվյալ հատվածում տվյալներից օգտվելը համեմատաբար ավելի դանդաղ է տեղի ունենում, սակայն տեղակայված տվյալները հասանելի են բոլոր միջակայքերի և կատարման հոսքերի (threads) համար, իսկ հիշողությունը կարող է հատկացվել և ազատվել ցանկացած պահի։
Հիշողության ազատումը կարող է կատարվել ուղղակիորեն և ինքնաշխատ: Առաջին դեպքում, չազատված հիշողության պատճառով հնարավոր է «հիշողության արտահոսք» (memory leak)։ Ինքնաշխատ ազատման համար պատասխանատու են «աղբահավաք» հավելվածները (GC - Garbage Collection)։
- Stack
- Տվյալների փոխանցում
Տվյալները կարող են փոխանցվել երկու ձևով՝ արժեքով (by value) կամ հղմամբ (by reference)։ Հղման դեպքում փոխանցվում է տվյալի հատուկ համարը կամ տեղակայման հասցեն:
Փոխանցման ձևը, կախված ծրագրավորման լեզվից, կարող է լինել ուղղակի (շարահյուսական տարբերակմամբ) և անուղղակի: «Բարձր մակարդակի» ծրագրավորման լեզուների դեպքում, սովորաբար, փոխանցումները տեղի են ունենում առանց շարահյուսական տարբերակման՝ անուղղակի:
- By Reference
Տվյալն անուղղակիորեն և հղմամբ այլ փոփոխականի փոխանցելուց հետո կարող է ենթարկվել փոփոխության վերջինի կողմից, եթե տվյալի տիպը փոփոխման ենթակա է (mutable data), և, այդպիսով, կորցնել որոշակիությունը, քանի որ առաջին փոփոխականը ժամանակի տարբեր կետերում կունենա տարբեր արժեքներ։
Տվյալը ուղղակիորեն (մտածված) և հղմամբ փոխանցելը, օրինակ՝ պահպանման ենթակա տվյալների (DB - Database) պարագայում, կարող է տալ մի շարք առավելություններ։
// EXPLICIT pass by REFERENCE #include <stdio.h> int main() { int x = 2; printf("Address of x: %p\n", &x); increment(&x); // pass argument by ADDRESS printf("x = %d\n", x); } void increment(int *n) // get argument by ADDRESS { printf("Address of n: %p\n", n); *n += 1; printf("n = %d\n", *n); }
Address of x: 0x7ffdd34ce384 Address of n: 0x7ffdd34ce384 n = 3 x = 3
# IMPLICIT pass by REFERENCE x = [0, 1, 2, 3] y = x # pass by REFERENCE print("Identifier of x:", id(x)) print("Identifier of y:", id(y)) x += [4, 5, 6] # lists are MUTABLE in Python print("x =", x) print("y =", y)
Identifier of x: 140144711080448 Identifier of y: 140144711080448 x = [0, 1, 2, 3, 4, 5, 6] y = [0, 1, 2, 3, 4, 5, 6]
- By Value
Տվյալը արժեքով փոխանցելուց, կամ փոփոխման ոչ ենթակա (immutable data) տվյալը հղմամբ փոխանցելուց, նախ, կրկնօրինակվում են նոր հասցեում, այնուհետև փոխանցվում են նոր հասցեի տեսքով։
// EXCPLICIT pass by VALUE #include <stdio.h> int main() { int x = 2; printf("Address of x: %p\n", &x); increment(x); // pass argument by VALUE printf("x = %d\n", x); } void increment(int n) // get argument by VALUE { printf("Address of n: %p\n", &n); n++; printf("n = %d\n", n); }
Address of x: 0x7fff2e58d014 Address of n: 0x7fff2e58cffc n = 3 x = 2
# IMPLICIT pass by VALUE x = 2 print("Identifier of x:", id(x)) def increment(n): # get argument by REFERENCE print("Identifier of n:", id(n)) n += 1 print("n =", n) increment(x) # pass argument by REFERENCE print("x =", x) # but integers are IMMUTABLE in Python
Identifier of x: 140518751926432 Identifier of n: 140518751926432 n = 3 x = 2
- By Reference
- Միևնույն հավելվածի համեմատությունը տարբեր լեզուներով
Հավելվածի բնութագիրը․
- Տպում է թիվ մուտքագրելու հրավեր (ենթադրվում է դրական ամբողջ թիվ, իսկությունը չի ստուգվում),
- Ընդունում է մուտքագրված թիվը,
- Տպում է զանգված՝ 1-ից մինչև մուտքագրված թիվը,
- Տպում է զանգվածի բոլոր թվերի գումարը։
Օրինակները՝ GitHub։
Տվյալ օրինակները նախնական ծանոթություն են՝ հաջորդող թեմատիկ դասընթացների առանձին լեզվական առանձնահատկությունները որպես «կանոն» չընդունելու համար։
- Տպում է թիվ մուտքագրելու հրավեր (ենթադրվում է դրական ամբողջ թիվ, իսկությունը չի ստուգվում),
3.3 Ֆունկցիոնալ ծրագրավորման մոդել
Ծրագրավորման ոլորտում (կիրառական տեսանկյունից) ֆունկցիան ունի մեկ նպատակ՝ մեկ միավորի մեջ «փաթեթավորել» կատարման որոշակի տրամաբանություն։ Դասական function ձևակերպումից բացի հանդիպում են նաև այլ անվանումներ՝ methode, procedure, etc։
Ֆունկցիայի միջակայքում կատարման ենթակա հատվածը անվանում են «ֆունկցիայի մարմին»։ Ֆունցիան կարող է ընդունել մեկ և ավելի արգումենտներ` հղմամբ կամ արժեքով։ Արգումենտների հայտարարությունը ֆունկցիայի հայտարարման անբաժանելի մաս է կազմում, և կախված է լեզվական առանձնաhատկություններից։
Ֆունկցիան կարող է ուղղակի կամ անուղղակի կերպով վերադարձնել իր կատարման արդյունքը՝ նույնպես հղմամբ կամ արժեքով:
function f() { // no arguments console.log("Hello!") // body } function add(x, y) { // two arguments without types return x + y // body with explicit return }
(defn add ;; declaration with name [x y] ;; two arguments (let [res (+ x y)] ;; first line of function body (res))) ;; implicit return of last statement
- Անանուն ֆունկցիա
Anonymous function, lambda abstraction - ֆունկցիա որը չունի ցուցիչ (անվանում, իդենտիֆիկատոր)։ Օրինակ հետևյալ դասական ձևակերպումը՝
λx.x
, որտեղλ
նշանը հայտարարում է անանուն ֆունկցիա, իսկ.
հատուկ նշանը բաժանում է սահմանումը երկու մասերի՝ արգումենտների (ձախ) և ֆունկցիայի «մարմնի» (աջ), որը անուղղակիորեն նաև ֆունկցիայի արդյունքն է։
Ի տարբերություն հատուկ անվանմամբ ֆունկցիաների (օրինակ՝
f(x)
կամsin(a)
)՝ անանուն ֆունկցիաներին հղում անել հնարավոր չէ` բացառությամբ այն դեպքերի, երբ անանուն ֆունկցիան հնարավոր է կցել փոփոխականի (ինչը շատ դեպքերում համարժեք է անվանական հայտարարման)։
Հետևյալ օրինակում անանուն ֆունկցիան ըստ պահանջի միաժամանակ հայտարարվում և փոխանցվում է որպես արգումենտ ֊ GitHub։
- «Զուտ» ֆունկցիա և «կողմնակի էֆեկտ» (Pure functions and Side-effect)
Զուտ կամ մաքուր ֆունկցիան պարտավոր է բավարարել հետևյալ պայմաներին․
- նույն արգումենտների փոխանցման պարագայում միշտ վերադարձնել նույն արդյունքը (առանց միջակայքից դուրս հասանելի տվյալների հետ հարաբերվելու),
- կատարվել առանց «կողմնակի էֆեկտ» (առանց միջակայքից դուրս հասանելի տվյալների փոփոխության և IO (input-output) ազդեցության)։
Նախորդ օրինակում
f()
ֆունկցիան ոչինչ չի վերադարձնում, սակայն կատարումն ունի կողմնակի էֆեկտ՝ IO ֆունկցիայի կանչ (տեքստային արտաբերում), ի տարբերությունadd(x, y)
«զուտ »ֆունկցիայի, որը ոչ մի կերպ չի հարաբերվում «արտաքին աշխարհի» հետ։
Այլ օրինակներ՝ GitHub։
- նույն արգումենտների փոխանցման պարագայում միշտ վերադարձնել նույն արդյունքը (առանց միջակայքից դուրս հասանելի տվյալների հետ հարաբերվելու),
- Առաջին կարգի ֆունկցիա
First-class function - այն ֆունկցիաներն են, որոնք դասվում են որպես «առաջին կարգի օբյեկտ», և, հետևաբար, կարող են մաս կազմել այլ օբյեկտների նկատմամբ կիրառվող բոլոր գործողությունների։ Օրինակ՝ կցվել փոփոխականների, փոխանցվել ֆունկցիայի որպես արգումենտ, վերադարձվել որպես ֆունկցիայի արդյունք, և այլն։ Առաջին կարգի ֆունկցիաներ են, ըստ էության, անանուն ֆունկցիաները։
- Ֆունկցիա֊տվյալ վերացականություն
Մաթեմատիկական տեսանկյունից Ֆունկցիան դիտարկվում է որպես հարաբերություն որոշակի մուտքային և ելքային միավորների միջև։
In mathematics, a function is a binary relation over two sets that associates every element of the first set, to exactly one element of the second set."
Այսպիսով, մասնավորապես «զուտ» ֆունկցիաների պարագայում, կարելի է պնդել, օրինակ, որ
f ≡ f'
, եթեf(x) = x²
,f' = {... (2: 4), (3: 9), (4: 16) ...}
(զանգվածը տեսականորեն պարունակում է հնարավոր բոլոր մուտքային և ելքային արժեքների համադրությունները)։
Անանուն «զուտ» ֆունկցիաների դեպքում զուգահեռները կարող են ավելի ակնհայտ դառնալ՝
var f = () => 42 var f' = 42
- Հղման թափանցիկություն (Referential Transparency)
Ֆունկցիան կարող է համարվել «հղմամբ թափանցիկ», եթե այն կարող է փոխարինվել համապատասխան արժեքով՝ առանց ծրագրի վարքագծի փոփոխության։
Տվյալ ֆունկցիաները, ըստ էության, կարելի է դիտարկել որպես «զտվածության» (purity) և անփոփոխ տվյալների (immutable data) համադրություն, օրինակ՝ երբ ֆունկցիան հարաբերվում է միջակայքից դուրս հայտարարված և ընդհանուր հասանելիության անփոփոխ տվյալների հետ։
Օրինակ՝ GitHub։
3.4 Օբյեկտ֊օրիենտացված մոտեցում (Java)
Դասընթացներին վերաբերվող ծրագրային օրինակները հիմնականում վերաբերում են դասընթացի վերնագրում նշված լեզվին՝ բացառությամբ հատուկ նշված ընդհանուր կամ մասնավոր դեպքերի։
Որպես «ծայրահեղ» օբյեկտ֊օրիենտացված՝ Java լեզվում ցանկացած կոդ պետք է լինի որևէ կլասի միջակայքում, նույնիսկ եթե չի ստեղծվում ոչ մի օբյեկտ։ Կլասը, որպես կանոն, ստեղծվում է համանուն ֆայլում և հայտարարվում է ամենավերին մակարդակում։ Կլասերի քանակը մեկ ֆայլում սովորաբար սահմանափակված չէ, սակայն ընդունված է պահպանել մեկ ֆայլում մեկ կլաս ունենալու սկզբունքը։
- Class
Կլաս են կոչվում այն «ձևանմուշները» (template), որոնց օգնությամբ օբյեկտ֊օրիենտացված ծրագրավորման մեջ ստեղծվում են հիմնարար տարրերը՝ Object (օբյեկտ)։ Այստեղ հայտարարվում են Կլասին վերաբերվող բոլոր բաղադրիչները՝ Fields (տվյալներ), Constructors (օբյեկտի կոնստրուկտորներ), Methods (մեթոդներ), Nested Classes (ներդրված կլասեր)։ Կլասի տվյալներին տարբեր լեզուներում անվանում են՝ Field (Java), Property, Member, Attribute, և այլն։
public class Person { // Fields String name; int age; // Constructor public Person(String name, int age) { this.name = name; this.age = age; } // Method returning String representation of object public String toString() { return "Name: " + this.name + ", Age: " + this.age; } }
- Objects (instances)
Կլասի հիմքում ստեղծվում են համապատասխան տվյալներ և «գործողություններ» (methods) կրող օրինակները (instances)` օբյեկտները։ Օբյեկտները ստեղծվում են Heap-ում
new
օպերատորի օգնությամբ, որն, իր հերթին, մեկնարկի է բերում տվյալ կլասի կոնստրուկտորը` փոխանցելով անհրաժեշտ տվյալները։ Եթե կոնստրուկտոր ուղղակիորեն հայտարարված չէ՝ անուղղակիորեն գործում է առանց արգումենտների լռելյայն (default) կոնստրուկտորը։
Ստեղծվող օբյեկտները, որպես կանոն, հղմամբ կցվում են համապատասխան փոփոխականների՝ բացառությամբ այն դեպքերի, երբ հղումը պահպանման կարիք չունի և օբյեկտը փոխանցվում է անմիջապես հայտարարմամբ։
// passing constructor arguments Person objJohn = new Person("John", 21); Person objPaul = new Person("Paul", 42); System.out.println(objJohn); System.out.println(objPaul); System.out.println(new Person("Peter", 84)); // inline init
Name: John, Age: 21 Name: Paul, Age: 42 Name: Peter, Age: 84
- Fields (տվյալներ)
Տվյալները կարող են կազմված լինել պրիմիտիվներից և օբյեկտներից։ Այսինքն, կլասը կարող է հայտարարվել տվյալներով, որոնք պատկանում են սեփական (ռեկուրսիվ ներդրվածություն) կամ մեկ այլ կլասի։
- Methods
- Scope & Access modifiers
Հետևյալ աղյուսակում նշված են կլասերի, կոնստրուկտորների, մեթոդների և տվյալների հասանելիության կարգերը։
Class Package Subclass (same pkg) Subclass (diff pkg) World public * * * * * protected * * * * no modifier * * * private *
- Objects (instances)
- Data
- Primitives
Պրիմիտիվ տվյալներին են պատկանում տվյալների մեքենայական մակարդակի տիպերը, որոնցից են.
int
32-bit կրողունակությամբ ամբողջ թվերի տիպը` իր ենթատիպերով (byte
8-bit,short
16-bit,long
64-bit),float
ևdouble
, համապատասխանաբար եզակի և կրկնակի ճշգրտության, տասնորդական (լողացող կետով) թվերը,char
տառանշային տիպը՝ unicode կոդավորմամբ,boolean
տրամաբանական true (ճշմարիտ) և false (սխալ)։
- Objects (type)
Օբյեկտային տիպը, մի դեպքում, կարող է հանդես գալ որպես պրիմիտիվ տվյալի «տիպ֊շապիկ» (wrapper-type), օրինակ՝
Integer
,Boolean
,Character
: Մյուս դեպքում, առանձին կլասի օրինակ (instance), օրինակ`Person
: Օբյեկտի հղում կրող փոփոխականների տիպը հայտարարվում է սեփական կամ «ծնողական» (ժառանգականություն) կլասի անունով։
- Null
Կատարման տարբեր փուլերում օբյեկտային տիպերը կարող են հայտարարվել և փոխանցվել
null
հղմամբ՝ ուղղակի կամ անուղղակի կերպով։
Person objJohn = null; // explicit init objJohn.toString(); // NullPointerException // list() on File object returns null if 'directory' does not exist String[] listOfDirs = new File("directory").list(); // listOfDirs is null String firstDir = listOfDirs[0]; // NullPointerException
Առավել հաճախ հանդիպող խնդիր է
null
հղմանը որևէ մեթոդ կամ հրաման հաջորդաբար փոխանցելը, ինչը բերում է ամբողջ ծրագրի կատարման խափանմանը։
- Comparison
Տվյալների համեմատությունը կախված է տվյալների տեսակից։
- Պրիմիտիվ տվյալները համեմատվում են
==
(հավասարություն) կամ!=
(անհավասարություն) օպերատորների օգնությամբ՝ ըստ արժեքի։ - Օբյեկտները համեմատվում են
==
կամ!=
օպերատորների օգնությամբ՝ ըստ հղման, և կլասում ուղղակիորեն հայտարարվածequals()
մեթոդի օգնությամբ, եթե երկու օբյեկտները պատկանում են նույն կլասին։
int x = 42; x == 42; // true objJohn == objPaul; // false Person objJohn2 = new Person("John", 21); objJohn == objJohn2; // false (different references) objJohn == objJohn; // true (same reference, same object) objJohn.equals(objJohn2); // may be true depending on 'equals' implementation
- Պրիմիտիվ տվյալները համեմատվում են
- Primitives
- Control Statements
- Selective
Պայմանային արտահայտությունները կարող են լինել ներդրված։
//IF-THEN-ELSE if (x > 0) // ... one-line satement without enclosing { } else { // Case that doesn't match previous // ... milti-line code // ... with enclosing { } } //IF-ELSE-IF-THEN-ELSE if (x > 0) // ... else if (x == 0) // ... else { // Case that doesn't match all previous // ... } // SWITCH int numDays; switch (monthNum) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: numDays = 31; break; case 4: case 6: case 9: case 11: numDays = 30; break; case 2: if (isLeapYear) numDays = 29; else numDays = 28; break; default: System.out.println("Invalid month."); break; // optional if the last } // TERNARY (ELVIS) OPERATOR - ?: String john = (objJohn != null) ? objJohn.toString() : "objJohn is null"
- Repetitive
Ցիկլիկ արտահայտությունները նույնպես կարող են լինել ներդրված։
// WHILE LOOP int n = 0; while (n < 10) { // check on every iteration if (caseWeAreSearching) { continue; // jump to next iteration } // ... do some stuff n++; // increment n } // DO-WHILE LOOP do { // ... do some stuff (at least once) n++; // increment n } while (n < 10); // check after first iteration // array example for iterating over int[] arr = {1,2,3,4,5,6,7,8}; // CLASSIC LOOP ITERATING BY INDEX for (int i = 0; i < arr.length; i++) { int elem arr[i]; // ... do some stuff with element } // FOR-EACH LOOP ITERATING BY ELEMENT for (int elem : arr) { // check some conditions if (elem == whatWeAreSearching) { // ... do some stuff break; // exit current loop } }
- Selective
3.5 Ինկապսուլյացիա, ժառանգականություն, պոլիմորֆիզմ (Java)
- Encapsulation
Ինկապսուլյացիայի նպատակը ծրագրի տարբեր հատվածներ տրամաբանորեն և/կամ հասանելությամբ առանձնացնելն է, որը թույլ է տալիս թաքցնել տվյալներ ու ծրագրային իրականացման մանրամասները՝ միմյանց ուղղակիորեն տրամադրելով միայն փոխհամագործակցության համար անհրաժեշտ հատվածները։
- Package and import
Կլասերը ըստ տրամաբանության խմբավորելու միավորը կոչվում է «փաթեթ» (package)։ Փաթեթների որոշակի ներդրվածությունը իրենից ներկայացնում է փոխադարձ հասցեավորման համար անհրաժեշտ նույնականացման մոդել։ Ինչպես էլ կլասի անվան դեպքում՝ փաթեթների անվանումները կրկնում են ֆայլային համակարգի համապատասխան հասցեն, oրինակ՝
./data/model/Model.java
ֆայլը պետք է առաջին տողում հայտարարի իր փաթեթըpackage data.model;
, իսկ տվյալ ֆայլի համանուն կլասը այլ ֆայլում ներմուծելու համար պետք է օգտագործելimport data.model.Model;
կամimport data.model.*;
և ներմուծել բոլոր ֆայլերի բոլոր կլասերը։
Կազմակերպությունների համար գոյություն ունի «փաթեթավորման» համաձայնություն՝ օգտագործել սեփական վեբ֊հասցեի հակառակ հաջորդականությունը, օրինակ՝
com.sun.eng
կամorg.apache.commons
:
Java API֊ը տրամադրում է բազմաթիվ փաթեթներ, որոնցից են՝
java.lang
,java.utils
,java.io
և այլ (Java SE 14 & JDK 14)։
java.lang
փաթեթի բովանդակությունն անուղղակի կերպով միշտ ներառվում է և ներմուծման կարիք չունի։
- Class and fields
Տվյալների իկապսուլյացիայի հիմնական գործիքը հասանելիության կարգերն են, որոնց միջոցով հայտարարվում են կլասերի, կոնստրուկտորների, մեթոդների և տվյալների հասանելիության կարգը տարբեր մակարդակներում։
Կլասի օրինակներին վերաբերվող տվյալներն, ըստ ընդունված կարգի, հայտարարվում են
private
, այսինքն՝ կլասի միջակայքից դուրս անհասանելի, իսկ հասանելիությունն ապահովում են համապատասխան Getter և Setter մեթոդները՝ սահմանափակելով տվյալների ուղղակի փոփոխումը։
Հետևյալ օրինակում
absoluteValue
փոփոխականն անհասանելի է, հակառակ դեպքում փոփոխականին հնարավոր կլիներ ուղղակիորեն կցել բացասական թիվ, ինչը հայտարարված տրամաբանությունից դուրս է։
// no modifier // available for package member and subclasses class AbsoluteValue { // private field private int absoluteValue; // Constructor uses setter public AbsoluteValue(int value) { absolutevalue = setValue(value); } // Getter public getAbsoluteValue() { return absolutevalue; } // Setter public void setAbsoluteValue(int value) { // check input if (checkValue(value) absoluteValue = value; else absolutevalue = Math.abs(value); } // private methode private boolean checkValue(int value) { return value >= 0; } }
Ներքին տրմաբանության մեթոդները նույնպես կարող են լինել հասանելությամբ սահմանափակված։
- Nested classes
Ներդրված կլասերը նույնպես օգտագործվում են ինկապսուլյացիայի նպատակով, երբ օբյեկտային որևէ մոդել ըստ իր տրամաբանության հանդիսանում է «ներքին» օգտագործման։
class OuterClass{ // ... class block private void innerMethod() { InnerClass innerObj = new InnerClass(); // ... doing some stuff with inner object } private InnerClass { // ... encapsulated structure } }
- Anonymous classes
Նախորդ օրինակում կլասը կարող էր ներդրված լինել նաև մեթոդի ներսում, քանի որ չէր օգտագործվում
innerMethod
մեթոդից դուրս։ Այդպիսի դեպքերում կլասը կարելի է հայտարարել անանուն, եթե պահանջվում է այդ կլասի միայն մեկ օրինակ։
Անանուն կլասը հայտարարվում է նոր օբյեկտի ստեղծման օրինակով՝ ավելացնելով կլասի հայտարարման «մարմինը»
{ }
փակագծերի մեջ։ Կլասի օրինակը, օբյեկտը, տվյալ դեպքում ստեղծվում է չհայտարարված լռելյայն (default) կոնստրուկտորի օգնությամբ։
class OuterClass{ // ... class block private void innerMethod() { // creates an inplace instance InnerAnonymous innerObj = new InnerAnonymous() { // ... anonymous class blocks }; } }
Անանուն կլասը կարելի է հայտարարել նաև՝ փոխանցելով այն որպես արգումենտ։
// sampleMethod takes InnerClass object sampleObject.sampleMethode( new AnonymousClass() { // ... anonymous class block });
- Package and import
- Inheritance
Ժառանգականությունը օբյեկտային ծրագրավորման հենասյուներից է, որը թույլ է տալիս ժառանգել և վերաօգտագործել (reuse) մեկ այլ կլասի դաշտերը և մեթոդները։
Oրինակ, եթե հայտարարենք հետևյալ կլասը, որն արտահայտում է երկրաչափական ուղղանկյան տրամաբանություն՝
// parent class example class Rectangle { double width; double height; // rectangle constructor public Rectangle(double width, double height) { this.width = width; this.height = height; } public double area() { return width * height; } }
Square
(քառակուսի) կլասի համար այն կարող է ծառայել որպես ծնողական կլաս, իսկ ժառանգող կլասը այլևս կարիք չի ունենա հայտարարել կրկնող տրամաբանությամբ դաշտեր և մեթոդներ (այնուամենայնիվ, ծնողական կլասիprivate
դաշտերը և մեթոդները ժառանգող կլասում հասանելի չեն, հասանելության համար հարկավոր է ծնողական կլասում դրանք հայտարարելprotected
)։
// child class with constructor only class Square extends Rectangle { // square constructor public Square(double side) { // calling parent's constructor super(side, side); // as width and height } }
Square square = new Square(5); // calling inherited method double squareArea = square.area(); // => 5
Ժառանգող կլասը կարող է հայտարարել իր սեփական դաշտերն ու մեթոդները, ինչպես նաև՝ վերահայտարարելով «ծածկել» (override) ծնողական մեթոդները։
// child class class Square extends Rectangle { // ... class block // Override parent's method (override) public double area() { // ... do some stuff // calling parent's area method for result return super.area(); } }
Ժառանգականության աստիճանը սահմանափակված չէ, սակայն ժառանգել միաժամանակ կարելի է միայն մեկ կլասից:
- Abstract classes
Աբստրակտ (վերացական) կլասերը կարող են փոխարինել ծնողական կլասերին այն դեպքերում, երբ ծնողական կլասը տրամաբանորեն վերացական է, և վերջինիս օբյեկտի (օրինակի) ստեղծում չի ենթադրվում։
Ի տարբերություն սովորական կլասերի՝ աբստրակտ կլասի մեթոդները կարող են նույնպես հայտարարվել աբստրակտ։ Այդ դեպքում մեթոդը բովանդակություն չի ունենում, սակայն տվյալ աբստրակտ կլասը անմիջականորեն ժառանգող բոլոր կլասերը պարտավոր են ռեալիզացնել ծնողական աբստրակտ մեթոդը։
public abstract class GeometryShape { // fields // non-abstract methods abstract double area(); // empty } class Triangle extends GeometryShape { // mandatory declaration public double area() { // calculating area for Triangle } }
- Interfaces
Ինտերֆեյսը նման է աբստրակտ կլասի։ Այն չի կարող ունենալ անմիջական օբյեկտ (օրինակ), և կարող է պարունակել բովանդակությամբ և առանց բովանդակություն մեթոդներ։ Սակայն, ի տարբերություն աբստրակտ կլասի, ինտերֆեյսի բոլոր մեթոդները ունեն լռելյայն (by default)
public
հասանելություն։
Ինտերֆեյսների մեկ այլ առանձնահատկությունն այն է, որ կլասերը կարող են «իրականացնել» (implement) մեկից ավելի ինտերֆեյս։ Բացի դրանից, ինտերֆեյսը ժառանգական տրամաբանությունից անկախ է և կարող է իրականացման «օրինակ» ծառայել տրամաբանորեն տարբեր կլասերի համար։ Ինտերֆեյսը այլ կերպ անվանում են նաև «կոնտրակտ», քանի որ ինտերֆեյսը երաշխավորում է մեթոդի առկայությունը։
public interface Measurable { // public by default double getValue(); } class Angle implements Measurable, BiComponent { // implementing getValue() // implementing all methods of BiComponent }
Ինտերֆեյսը կարող է ժառանգել (
extends
) մեկ այլ ինտերֆեյս։
- Abstract classes
- Polymorphism
Պոլիմորֆիզմ են անվանում այն հատկությունը, երբ տվյալի տիպիզացված միավորը ներկայանում է այլ կերպ։ Օբյեկտները (կլասի օրինակների) պոլիմորֆ են ըստ էության, և կարող են ներկայանալ որպես ցանկացած ծնողական կլաս կամ իրականացվելիք ինտերֆեյս:
Հետևյալ օրինակում
Android
կլասը ժառանգողGalaxyA51
կլասը վերահայտարարել է միայնcheck()
ծնողական մեթոդը, և հայտարարել էcpu()
սեփական մեթոդը։ Քանի որmain
մեթոդում ստեղծվողGalaxyA51
կլասի օբյեկտի հղումը կցվում է ծնողականAndroid
տիպին, ապա կազզման (compilation) ընթացքում տեղծվող օբյեկտը ներկայանում է որպես ծնողական կլասի օբյեկտ, և հաշվարկվում են միմիայն հղման կլասի մեթոդները։ Այս դեպքում օբյեկտը, լինելովGalaxyA51
տիպի, չի կարող օգտագործել իր սեփականcpu()
մեթոդը, սակայն վերահայտարարված (override)check()
մեթոդի դեպքում կգործարկվի հենցGalaxyA51
կլասի մեթոդը, քանի որ այն հաշվարկվել է կազզման ընթացքում և ժառանգականության տրամաբանությամբ «ամենամոտն է»։
abstract class Android { // not overridden public String kernel() { return "has Linux kernel"; } // OVERRIDDEN public String check() { return "is Android"; } } class GalaxyA51 extends Android { // child-specific public String cpu() { return "has Exynos CPU"; } // OVERRIDES Parent's check() public String check() { return "is Galaxy A51"; } } class Main { public static void main(String[] args) { // parent reference type Android objA51 = new GalaxyA51(); // objA51.cpu() will throw an ERROR // cannot find 'cpu' symbol // overridden check() method invoked (see below) System.out.println("objA51 " + objA51.check()); } }
objA51 is Galaxy A51
Օբյեկտ֊օրիենտացված լեզուներում բոլոր կլասերն ունեն լեզվի մաս կազմող ամենաբարձր ծնողական կլաս, որն ուղղակիորեն կամ անուղղակիորեն ժառանգում են, և որին կարող են հղում անել ստեղծվող օբյեկտերի փոփոխականները։ Java լեզվում այն կոչվում է
Object
, որն աանուղղակիորեն (առանց հայտարարելու) ժառանգում են բոլոր կլասերը։
Կա օբյեկտի (ոչ փոփոխականի) իրական տիպը ստուգելու երկու տարածված տարբերակ՝ ըստ ժառանգականության և ըստ ուղիղ համեմատության։ Առաջին դեպքում կարելի է պնդել, որ օբյեկտը նշված կամ ժառանգորդ կլասի օրինակ է։ Երկրորդ դեպքում կատարվում է օբյեկտի կլասի ուղղակի համեմատություն։ Երկու դեպքում էլ կարելի է օբյեկտը «ստվերել» (cast) ստուգված կլասով և հայտարարել նոր փոփոխական կամ տեղում փոխանցել որպես արգումենտ։
// valid assignment Object objA51 = new GalaxyA51(); // only Object's methods are available objA51.toString(); // checking inheritance if (objA51 instanceof Android) { // cast by own or parent class Android newA51 = (Android) objA51; // ... do some stuff with new type } // checking exact class if (objA51.getClass() == GalaxyA51.class) { // cast by own class GalaxyA51 newA51 = (GalaxyA51) objA51); // ... do some stuff with new type }
3.6 Օբյեկտ֊օրիենտացման գործիքներ և հավաքածուներ (Java)
- Entrypoint
C լեզվաընտանիքում ընդունված է օպերացիոն համակարգի միջավայրում կատարման ենթակա ծրագրային հավելվածը մեկնարկել ուղղակի կերպով հայտարարված
main
ֆունկցիայի օգնությամբ, որը համակարգային ավելի «ցածր մակարդակի» (low-level) կատարման պարագայում, որպես կատարման արդյունք, վերադարձնում էint
ամբողջ թիվ՝ փոխանցելով կատարումը նախաձեռնող «ավելի բարձր» պրոցեսին (օրինակ՝ տերմինալին, կամ այլ հավելվածին) կատարման ավարտի կոդը (exit status)։ Ընդունվող արգումենտները պատասխանատու են միջավայրից փոխանցվող արգումենտների համար (տես՝ հաջորդ պարբերություն)։ Առաջին արգումենտը որոշ լեզուների դեպքում կատարման ֆայլի անունն է։
// argc - arguments' count // argv - arguments' strings // return int int main(int argc, char *argv[]) { // MAIN PROCEDURES }
Վիրտուալ մեքենայում կատարման ենթակա հավելվածների պարագայում
main
ֆունկցիան հայտարարվում է որպես որևէ մի կլասի (անվանումը կարևոր չէ) ստատիկ մեթոդ։ Վերադարձվող արժեքը բաց է թողնվում (void
), քանի որ վիրտուալ մեքենան տիրապետում է կատարման ավարտի մասին ամբողջ ինֆորմացիային, իսկ փոխանցվող արգումենտը՝ միջավայրից փոխանցվող արգումենտների զանգվածն է։
import java.util.Arrays; // class name doesn't matter class Entrypoint { public static void main(String[] args) { if (args.length > 0) { // print args passed by running process System.out.printf("Passed args: %s\nType: %s\n", Arrays.toString(args), args.getClass().getSimpleName()); } } }
Տվյալ դեպքում
Entrypoint
կլասի կատարումը համապատասխան հրամանի օգնությամբ սկսվում էmain
մեթոդից, որին փոխանցվում են կատարման հրամանի պայմանական արգումենտները՝argument1
ևargument2
, և որը, ըստ վերը նշված իրականացման, արտաբերում է փոխանցված արգումենտները։
# run main of Entrypoint class and pass args java Entrypoint argument1 argument2
Passed args: [argument1, argument2] Type: String[]
- Static & Final components
- Static fields and methods
Ստատիկ կարող են հայտարարվել կլասի բոլոր բաղադրիչները՝ տվյալները, մեթոդները և ներդրված կլասերը։ Ստատիկ բաղադրիչները, ի տարբերություն սովորական բաղադրիչների, պատկանում են ոչ թե օբյեկտին, այլ կլասին, հետևաբար՝ ստատիկ հայտարարված տվյալներն ունեն եզակի օրինակ։
Այդպես, օրինակ,
static
հայտարարված դաշտը կարող է կրել կլասի օրինակների քանակի մասին տվյալ` կոնստրուկտորում ավելացում հաշվելով, իսկ տվյալի հասանելիությունը կարող է ապահովել համապատասխան ստատիկ մեթոդը, որն այլ կերպ անվանում են կլասի մեթոդ։ Օբյեկտների (ոչ ստատիկ) մեթոդների համար ստատիկ տվյալները հասանելի են (ինչպես երևում է կոնստրուկտորի դեպքում), իսկ ստատիկ մեթոդները՝ ոչ։
class Factory { // static field - unique data private static int numberOfObjects = 0; // non-static fields public Factory() { // ... do some stuff numberOfObjects++; // increment } // class-method (static) public static int getNumberOfObjects() { return numberOfObjects; } } class Main { public static void main(String[] args) { // creating objects Factory objF = new Factory(); Factory objS = new Factory(); Factory objT = new Factory(); // class-method invokation int num = Factory.getNumberOfObjects(); System.out.println("Number of objects: " + num); } }
Number of objects: 3
Ներդրված կլասի
static
հայտարարումը թույլ է տալիս ապահովել ներքին կլասի հասանելիությունը արտաքին կլասի միջոցով։
class Outer { // outer class stuff static class Inner { // inner class stuff } } class Main { // declaration via outer class Outer.Inner innerClassObj = new Outer.Inner(); }
- Final components
Փոփոխականները, մեթոդները և կլասերը այս օպերատորի օգնությամբ ստանում են համապատասխան սահմանափակումներ։
Բաղադրիչ Վարքագիծ Փոփոխական Փոփոխականի հղումը չի կարող փոխվել (reference is constant) Մեթոդ Մեթոդը չի կարող վերահայտարարվել (prevent override) Կլաս Կլասից ժառանգել հնարավոր չէ (prevent inheritance) Պրիմիտիվ տվյալների դեպքում փոփոխականը կարելի է ընդունել որպես հաստատուն, քանի որ պրիմիտիվ տվյալները համարվում են «անփոփոխ» (immutable), իսկ հղումը չի կարող փոխվել։
Օբյեկտներին հղում արվող փոփոխականների դեպքում անփոփոխ է մնում միայն օբյեկտի հղումը, օբյեկտը բովանդակությամբ ենթակա է փոփոխության (mutable)՝ բացառությամբ նախանշված անփոփոխ օբյեկտների (օրինակ՝
String
)։
- Static fields and methods
- Overloaded constructor & methods
Մեթոդների վերաբեռնավորումը (overloading) ևս մեկ օրինակ է, որը թույլ է տալիս տարբեր տիպի տվյալների դեպքում օգտագործել միևնույն մեթոդը։ Օրինակ՝ ամբողջական 64-bit
long
, ամբողջական 32-bitint
և տասնորդականdouble
տվյալների դեպքում հաշվարկային մեթոդները կարող են կրկնվել: Այս դեպքում համանուն մեթոդները կարող են վերաբեռնավորվել ըստ արգումենտների տիպի և քանակի։
Պրիմիտիվ արգումենտներն առանց տիպի ուղղակի նշման փոխանցելու դեպքում մոտարկում է արվում հնարավոր «անկորուստ» հաշվարկային տիպի։ Համընկնում չլինելու պարագայում կատարվում է անուղղակի փոխարկում, որի ընթացքում հնարավոր է ինֆորմացիայի կորուստ, օրինակ՝
long
ևint
միջև։
class SumClass { public static int sum(int x1, int x2) { return x + y; } public static long sum(long x1, long x2) { return x + y; } public static double sum(double x1, double x2) { return x + y; } } class Main { // using different methods SumClass.sum(42, 3215468); // 1st SumClass.sum(2147483648, 1); // 2nd - Integer.MAX_VALUE = 2147483647 SumClass.sum(0.1, 7); // 3th - double // ... }
Վերաբեռնավորել կարելի է նաև կլասի կոնստրուկտորը, վերաօգտագործելով արդեն առկա հայտարարումը։
class Rectangle { double width; double height; // ordinary rectangle constructor public Rectangle(double width, double height) { this.width = width; this.height = height; } // square case constructor public Rectangle(double side) { // reuse matching appropriate constructor this(side, side); // constructor call must be the first statement } } class Main { // using different constructors Rectangle rectangle = new Rectangle(3, 4); Rectangle square = new Rectangle(5); }
- Parametric polymorphism (Generics)
- Generic Classes
Կլասերի վերաօգտագործման պարագայում հաճախ առաջանում է տիպիզացման կախվածության խնդիր։ Օրինակ միևնույն բաղադրիչի երկու օրինակ պարունակող
BiComponent
կլասը ամեն անգամ պետք է տիպիզացվի ըստ բաղադրիչի տիպի:
class ButtonBiComponent { private Button button1; private Button button2; // ... constructor and methods } class SpeakerBiComponent { private Speaker speaker1; private Speaker speaker2; // ... constructor and methods } // ... so on and so forth
Այստեղ օգնության են գալիս այսպես կոչված «ջեներիկները» (Generics), որոնք թույլ են տալիս կլասը պարամետրիզացնել (ընդհանրացնել) փոփոխական տիպով։
// parameterized class class BiComponent<T> { // parameterized field private T component1; private T component2; // parameterized constructor public BiComponent(T component1, T component2) { this.component1 = component1; this.component2 = component2; } // getters and setters } class Main { // ... some initializations BiComponent<Button> btnPair = new BiComponent<>(btn1, btn2); BiComponent<Speaker> spkrPair = new BiComponent<>(spkr1, spkr2); }
Պարամետրիզացիան կարող է լինել մեկից ավելի տիպերի համար։
// parameterized class class Pair<T1, T2> { // parameterized field private T1 component1; private T2 component2; // parameterized constructor public Pair(T1 component1, T2 component2) { this.component1 = component1; this.component2 = component2; } // getters and setters } class Main { // ... some initializations Pair<Button, Speaker> btnSpkr = new Pair<>(btn1, spkr2); }
Պոլիմորֆ կլասերի տիպիզացիան Java լեզվի դեպքում տեղի է ունենում կազմման փուլում։ C# լեզվում, օրինակ, տիպիզացիան տեղի է ունենում կատարման փուլում, ինչը հավելյալ ճկունության հնարավորություն է տալիս։
- Generic Methods
Մեթոդների պարամետրիզացիան օգնում է ընդհանրացնել այն բազմաթիվ կլասերի օբյեկտների համար՝ ըստ փոփոխականների, որոնք առանձին նշվում են
< >
հատուկ «չակերտների» մեջ։
class Components { // ... some initializations // return value and argument are parameterized by T public static <T> T getFirstComponent(BiComponent<T> bc) { return bc.getFirstComponent(); } // arguments are parameterized by K and V public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) { return p1.getKey().equals(p2.getKey()) && p1.getValue().equals(p2.getValue()); } }
- Generic Classes
- Arrays & Collections
Զանգվածները (Array), C լեզվաընտանիքի ավանդույթի համաձայն, հայտարարվում են
[]
փակագծերի միջոցով՝ նշելով ծավալը, որը փոփոխման ենթակա չէ։ Ի տարբերություն ավելի ցածր մակարդակի (low-lewel) լեզուների՝ զանգվածները Java լեզվում օբյեկտ են և կարող են պարունակել պրիմիտիվ տվյալներ կամ օբյեկտներ։
// initializing empty array by length int[] intArray = new int[20]; // initializing array by values int[] intArray = {1,2,3,4,5,6,7};
Հավաքածուները (Collections) զանգվածներից տարբերվում են դինամիկ ծավալով և համեմատաբար ավելի ցածր արագագործությամբ։ Հավաքածուները պոլիմորֆ են պարամետրիկ փոփոխականով՝ ըստ պարունակության, կարող են լինել միատարր և բազմատարր։
Հավաքածուները կարող են հայտարարվել դատարկ, որից հետո կարող են ընդունել և հեռացնել էլեմենտներ։ Ի տարբերություն զանգվածների՝ կարող են պարունակել միայն օբյեկտներ։ Պրիմիտիվ տվյալների համար կան «փաթեթավորող» (wrapper) կլասեր, որոնք ավտոմատ կերպով փոխարկում են պրիմիտ տվյալները։
// initializing empty list of Integer objects LinkedList<Integer> linkedList = new LinkedList<>(); // add int elements explicitly boxing int to Integer for (int i = 1; i <= Math.pow(2, 16); i++) linkedList.add(i); // initializing empty map of key-value HashMap<String, Boolean> hashMap = new HashMap<>(); // put key-value pairs hashMap.put("p1", true); hashMap.put("p2", false); hashMap.put("p3", true);
Արդեն նշված գործիքները բավարար են ցանկացած հավաքածու ստեղծելու համար, սակայն ավելի արդյունավետ է վերաօգտագործման մոտեցումը։ Java API-ի կողմից տրամադրվում են բազմաթիվ պատրաստի հավաքածուներ, որոնք հավաքված են
java.utils
փաթեթում։ Յուրաքանչյուր հավաքածուի տեսակ օպտիմալ է որոշակի խնդիրների լուծման պարագայում։
- Synchronous vs asyncronous
Ծրագրային կատարման ընթացքի սովորական տրամաբանությունը «սինխրոն» է (synchronous)։ Կատարումը համարվում է սինխրոն, երբ այն հաջորդական է մեկ շղթայական կատարման (thread, поток ռուս․, հոսք հոմ․) սահմաններում, այսինքն՝ հաջորդ կատարմանն անցնելու համար պետք է սպասել ընթացիկ կատարման ավարտին։ Օրինակ՝ ցանկացած I/O գործարկման պարագայում (storage, network, etc.)։ Հոսքերը, ի տարբերություն պրոցեսների, միմյանց հետ կիսում են հատկացված հիշողությունը, այսինքն՝ միևնույն տվյալը հասանելի կարող է լինել տարբեր կատարումների համար։
Ի տարբերություն սինխրոն կատարման՝ ասինխրոն (asynchronous) կատարումը ենթադրում է միևնույն ծրագրի մեկից ավելի հոսքեր (threads), որոնք միմյանց կատարման ավարտին սպասելու կարիք չունեն։ Զուգահեռ շղթաները կարող են կատարվել բարձր հաճախականությամբ մեկից մյուսին անցնելով և ստեղծել համաժամանակյա (տես՝ հաջորդող Attention բլոկ) կատարման էֆեկտ։ Բազմամիջուկ պրոցեսորների պարագայում տարբեր հոսքեր կարող են ֆիզիկապես կատարվել միաժամանակ։
Սինխրոն և ասինխրոն կատարումների տերմինաբանության մեջ կա ակնհայտ տարընթերցում։
Տեղեկատվական տեխնոլոգիաներում «սինխրոն» (synchronous) է կոչվում ժամանակի կտրվածքում մեկ հոսքով և խիստ հաջորդականությամբ կատարումը, և ոչ՝ համաժամանակյա։ ԵՎ հակառակը՝ «ասինխրոն» (asynchronous) են կոչվում հիմնական հոսքից (main thread) անջատ կատարումները։
Կախված խնդրից՝ կարիք է առաջանում ստեղծել անջատ հոսքեր, կամ հակառակը՝ պահպանել խիստ հաջորդականություն։
Առաջին դեպքում, օրինակ, I/O գործարկումները կարող են կատարվել առանձին հոսքերով, և, այդպիսով, ազատել հիմնական կատարման հոսքը, քանի որ նման գործարկումները սովորաբար ժամանակատար են լինում և կախված են արտաքին ռեսուրսներից։ Մեկ այլ օրինակ է մեծ զանգվածների սորտավորումը և ֆիլտրացիան, որոնք կարելի է կատարել «զուգահեռ» (parallel)։ Նման դեպքերում ստեղծվում են առանձին հոսքեր, որոնք կատարման ավարտից հետո վերադարձնում են կատարման արդյունքը այն հոսքին, որից ճյուղավորվել են։
Երկրորդ դեպքում տվյալները կարող են փոփոխվել խիստ հաջորդաբար՝ անկանխատեսելի հետևանքներ չունենալու համար։ Զանգվածների և հավաքածուների դեպքում, բարեբախտաբար, կան ասինխրոն կատարման համար նախատեսված օրինակներ, որոնք սովորաբար ունենում են "Concurrent", "Synchronized", "Atomic" կամ այլ ընդգծված նախածանց, օրինակ՝
ConcurrentHashMap
,SynchronizedRandomAccessList
,AtomicReferenceArray
, և այլն։
Պրոցեսորի միջուկների «բազմահոսք» (multi-thread) տեխնոլոգիան նույնպես հաճախ շփոթություն է առաջացնում՝ մինչդեռ դրանք տարբեր հասկացություններ են։
- Synchronized methods
Մեթոդները նույնպես կարող են հայտարարվել «սինխրոնիզացված»՝
synchronized
և ապահովել տարբեր հոսքերի (threads) կողմից տվյալ մեթոդի խիստ հաջորդական կատարումը։
synchronized public void write() { // ... do synchronized }
Եթե սինխրոնիզացման ենթակա է մեթոդի միայն մի մասը՝ այն կարող է առանձնացվել սինխրոնիզացված բլոկի մեջ։
public void write() { // ... do some stuff synchronized { // ... do synchronized } }
- Synchronized methods
- Stream
(հոսք անգլ․, չշփոթել կատարման շղթայի հետ) Զանգվածների և հավաքածուների հետ աշխատելու գործիք, որը թույլ է տալիս օգտագործել անանուն ("lambda") ֆունկցիաներ և գործողությունները խմբավորել շարահյուսական տեսանկյունից հաջորդական ու ընթեռնելի հրամաններով՝ պահպանելով, միաժամանակ, «ծույլ» կատարում (lazy evaluation) և ռեսուրսների օպտիմալ օգտագործում։
List<Models> listOfModels = listOfAllSmartphones.stream() .map(Smartphone::getModel) // method reference .distinct() // filter duplicates .collect(Collectors.toList()); // collect long cheapSmartphones = listOfModels.stream() .filter(m -> m.getPrice() <= 200) // filter by price .count(); // count
Stream ստեղծելուց կարելի է հայտարարել այն «զուգահեռ»
parallelStream
մեթոդի օգնությամբ։
- Exception handling
Բացառությունները (exceptions) կոդի տեսանկյունից լինում են երկու տեսակի՝ ստուգման ենթակա (checked) և ոչ ենթակա (unchecked)։
Վերջինները նույնպես կարող են ստուգվել, սակայն ծրագրավորողի կողմից սովորաբար անտեսվում են, քանի որ տեղի են ունենում կատարման փուլում և, ըստ էության, անկանխատեսելի (ամբողջ կոդը ստուգումներով ծածկելու փոխարեն կարելի ստուգել կոդը)։ օրինակ՝
NullPointerException
,ArrayIndexOutOfBound
,IllegalArgumentException
, և այլ։
Ստուգման ենթակա բացառությունները ստուգվում են կազզման ընթացքում, իսկ կառավարումը կատարվում է երկու եղանակով՝ բացառություն(ներ)ը «որսալու» փորձով (try-catch) կամ հայտարարելով։
- Try-catch
Բացառությունները «որսալու» նպատակով՝ պոտենցյալ բացառություն առաջացնող հատվածները պարփակվում են
try
բլոկով, որին անմիջապես պետք է հաջորդիcatch
բլոկը՝ ակնկալվող բացառությունների հայտարարմամբ (տվյալ օրինակում՝IOException
), որտեղ նշվում են բացառության դեպքում կատարվող գործողությունները։ Մեկից ավելի բացառությունների պարագայում կարելի է հայտարարել նաև առանձինcatch
բլոկեր։
byte[] data = stringData.getBytes(); Path path = Paths.get("./testfile.txt"); OutputStream out = null; try { out = Files.newOutputStream(p, CREATE, APPEND); out.write(data); // ... do some stuff out.close() // close file (I/O resource) } catch (IOException e) { // ... do some logging e.printStackTrace(); // print stacktrace in stderr }
Վերը նշված օրինակում առաջանում է ևս մեկ խնդիր։ Հարկավոր է ապահովել ֆայլային ռեսուրսի փակումը, քանի որ
try
բլոկում մինչև ռեսուրսի փակումը բացառություն առաջանալու դեպքում կատարումն անմիջապես կանցնիcatch
բլոկ և տվյալները չեն պահպանվի։ Այդ դեպքում կարելի է օգտագործել ոչ պարտադիրfinally
բլոկը, որը կատարվում է բոլոր դեպքերում։ Այնուամենայնիվ, ֆայլային ռեսուրսները փակելը ենթակա է նոր բացառության ստուգման, և, հետևաբար, պետք է պարփակվի ևս մեկ try-catch բլոկով։
OutputStream out = null; try { out = Files.newOutputStream(p, CREATE, APPEND); out.write(data); // ... may cause another EXCEPTION // out.close() is UNREACHABLE } catch (IOException e) { // ... do some logging e.printStackTrace(); // print stacktrace in stderr } finally { // check I/O resourses if (out != null) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } }
Ավելի ճկուն շարահյուսությամբ լեզուները (Java 7+) թույլ են տալիս ռեսուրսները հայտարարել հատուկ բլոկում, որն ապահովում է հավելյալ
finally
բլոկի ֆունկցիան և կատարվում է բոլոր դեպքերում։
// resourse block (resource-block) try (OutputStream out = Files.newOutputStream(path, CREATE, APPEND)) { out.write(data); } catch (IOException e) { // ... do some logging e.printStackTrace(); // print stacktrace in stderr }
- Բացառության հայտարարում
Ակնկալվող բացառությունները կարող են չպարփակվել try-catch բլոկով, եթե հայտարարվում են որպես պարփակող մեթոդի մաս։ Տվյալ բացառությունները «որսալու» պարտավորությունն այս դեպքում ուղղակիորեն հանձնվում է մեթոդը շահագործող կողմին։
private void writeToFile(String stringData) throws IOException { // ... do some stuff }
- Try-catch
3.7 Պրակտիկ (Java)
Նպատակն է ստեղծել մոդուլային հավելված, որի լավագույն գործիքներից է օբյեկտ֊օրիենտացված ծրագրավորումը։ Հավելվածը ստեղծվելու է հնարավոր զարգացման և վերաօգտագործման կոնտեքստում։ Այդ պատճառով նախագծումը պետք է կատարվի տվյալների (data, model) և արտաբերման գործիքների (view) առանձնացման տրամաբանությամբ։
Հավելվածի կոդին առցանց կարելի է ծանոթանալ հետևյալ հասցեով՝ GitHub։
Հավելվածը կարելի է նաև «կրկնօրինակել» (git clone
) համապատասխան գործիքներով կամ ներբեռնել որպես դասընթացների ընդհանուր պրոյեկտ (project)` GitHub:
Հավելվածը «փաթեթավորվում» է (build, package) Maven ծրագրով՝ հավելվածի հիմքային (կողմնորոշիչ՝ pom.xml
) հասցեում mvn package
հրամանի կատարմամբ։ Փաթեթավորման հաջողված ավարտից հետո ստեղծվում է ./target/<file-name>.jar
արխիվային ֆայլ, որն իրենից ներկայացնում է կազմված (compiled) ամբողջական հավելված։ Հավելվածը գործարկելու համար հարկավոր է կատարել java -jar <file-name>.jar
հրամանը։
Հետևյալ հղումով կարող եք ներբեռնել նախապես փաթեթավորված հավելվածը - JAR։
- Հղում ծանոթության համար - Enum, Annotations, String Formatting
3.8 Մուլտիպարադիգմ մոտեցում (Python)
Python ծրագրավորման լեզուն ի սկզբանե նախագծվել է որպես «մեկնաբանող» մեքենայի` Python Interpreter, և ընդհանուր կիրառման մուլտիպարադիգմ լեզվի համալիր։
Կան Python լեզվով ծրագրավորման տարբեր (նաև տարբեր միջավայրերում աշխատող) ինտերպրետատորներ, սակայն դասական և հիմնական տարբերակը CPython ինտերպրետատորն է, որն օֆիցյալ Python փաթեթի մասն է կազմում։ Ինտերպրետացիոն մեխանիզմները վիրտուալ մեքենայի աշխատանքից տարբերվում են կատարմամբ։ Վիրտուալ մեքենան ենթադրում է նախապես ստուգված և կազմված (compiled) հրահանգների կոդ, մինչդեռ ինտերպրետատորը ուղղակիորեն գործում է ըստ իր անվանման՝ հերթականությամբ մեկնաբանելով գրված կոդը։ Այս մոտեցումը գրեթե ամբողջությամբ բնորոշում է ծրագրավորման լեզվի առանձնահատկությունները։
Python 2 տարբերակը 2020 թվականից համարվում է «դադարեցված», այդ պատճառով օրինակները բերվում են միայն 3֊րդ տարբերակի համար։
- Հիմնական առանձնակատկությունները
- Տիպիզացիա
Այստեղ տիպիզացիան դինամիկ է և խիստ, այսինքն՝ չի հայտարարվում և ստուգվում է միայն կատարման պահին, սակայն տիպային անհամապատասխանությունների պարագայում (բացառությամբ նախորոշված դեպքերի) տեղի է ունենում կատարման խափանում՝ տիպային բացառություն
TypeError
: Բարդ կառուցվածքով տվյալները համարվում են նույնը, եթե ունեն նույնատիպ կառուցվածք ֊Duck typing
:
Առաջին հայացքից թվացող առավելությունը բավական խափուսիկ է, և «խնայված» տառանշանների գինը վաղ թե ուշ վճարվում է համաչափ, իսկ պրակտիկորեն՝ անհամաչափ, ռեսուրսներով։ Այդ իսկ պատճառով,
բազմաթիվ հեռուստադիտողներիհամայնքի (community) խնդրանքով, 3.5 տարբերակում ավելացվեցին տիպային «հուշումներ»՝ type hints։
- Խիստ հերթական կատարում
Մեկնաբանմամբ կատարումը ստիպում է նախագծել գծային տրամաբանությամբ։ Փոփոխականներին և ֆունկցիաներին հնարավոր չէ հղում անել մինչև դրանց հայտարարումը։ Հետևյալ կոդը կխափանի կատարումը, քանի որ
y
փոփոխականին հղումը, ըստ կատարման, տեղի է ունենում այն ժամանակ, երբ նման փոփոխական դեռ հայտարարված չէ։
x = y + 42 # NameError y = 5
Նույնը տեղի է ունենում ֆունկցիաների հայտարարման պարագայում, քանի որ
say_hello()
ֆունկցիային հղում է արվում մինչև նրա հայտարարումը։
# function call say_hello() # NameError # function declaration def say_hello(): print("Hello")
- Միջակայք (scope)
Ի տարբերություն ուլտիմատիվ օբյեկտ֊օրիենտացված լեզուների, որտեղ ցանկացած արտահայտություն մաս է կազմում որևէ կլասի և գտնվում է վերջինի միջակայքում, այստեղ արտահայտությունները կարող են ներդրված չլինել և կարող են կատարվել որպես հաջորդական հրահանգներ։ Միջակայքի ներդրվածության աստիճանը որոշում է ձախ լուսանցքի նկատմամբ խորության աստիճանը (indent, отступ ռուս․), որը պարտավոր է լինել նախորոշված միավորին պատիկ ամբողջ կոդի համար, օրինակ՝ չորս բացատ։
Միջակայքերը դինամիկ տիպիզացման պարագայում առաջացնում են հավելյալ խնդիր, երբ փոփոխականի հայտարարումը և փոփոխումը շարահյուսության տեսանկյունից չեն տարբերվում։ Եթե ստատիկ տիպիզացման դեպքում հայտարարումը ընդգծվում էր շարահյուսությամբ՝
int num = 5; // declare and assign a variable num = 42; // assign new value
Ապա դինամիկ տիպիզացման պարագայում փոփոխականի հայտարարումն ու փոփոխումն ակնհայտ չեն։ Հետևյալ կոդում ֆունկցիան հայտարարում է իր ներսում
num
անունով ամբողջովին նոր փոփոխական` առանց փոփոխելու նախկինը։
num = 5 # declare a variable def print42(): num = 42 # declare another variable print(num) print42() print(num)
42 5
Ընդհանուր (գլոբալ) միջակայքում հայտարարված փոփոխականի արժեքը փոխելու համար հարկավոր է նախապես հայտարարել տվյալ փոփոխականը որպես գլոբալ՝ օգտագործելով համանուն «բանալի֊բառ» (keyword)
global
:
num = 5 # declare a variable def print42(): global num # declare variable global num = 42 # assign new value print(num) print42() print(num)
42 42
- Առաջին կարգի ֆունկցիա
Առաջին կարգի (first-class) ֆունկցիաները ցանկացած ծրագրավորման լեզվում ամենաարդյունավետ գործիքներից են և տալիս են մի շարք «նոր» և ճկուն հնարավորություններ։ Ֆունկցիաները և ֆունկցիոնալ գործիքները դիտարկվում են հաջորդ դասընթացի ընթացքում։ Առաջին կարգի ֆունկցիաները առավել ցայտուն դիտարկվում են Ֆունկցիոնալ ծրագրավորմանը վերաբերվող դասընթացների ընթացքում։
- Անմիջական և հետաձգված կատարում
Հետաձգված մոդելներից են գեներատորները, որոնք հաճախակի են հանդիպում ժամանակակից լեզուներում։ Այդպես, օրինակ լեզվի մաս կազմող (built-in)
range
ֆունկցիան չի ստեղծում զրոյից մինչև մեկ միլիարդ միջակայքի բոլոր ամբողջ թվերի զանգվածը։ Փոխարենը, փոփոխականին է հանձնում «հետաձգված կատարում», որը կարող է հաջորդող կոդում տեղի ունենալ միայն մասնակի։
lots_of_integers = range(1_000_000_000) # same as range(0, 1000000000) print(lots_of_integers[42]) # goes until 42 and stops
42
- Օպերատորներ
Python լեզուն հաճախ խորհուրդ են տալիս որպես երեխաների առաջին ծրագրավորման լեզու, քանի որ արտահայտման մեխանիզմներն այստեղ շատ ավելի պարզեցված են, քան C լեզվաընտանիքի լեզուներում։ Օրինակ՝
&&
,||
,!
օպերատորների փոխարեն գործում են, համապատասխանաբար,and
,or
,not
օպերատորները։ Հետևյալ օրինակում երևում է նաևfor
ցիկլերի պարզեցման աստիճանը։
collection = [8,-6,24,9] # for-each loop for var in collection: print(var)
8 -6 24 9
- Տիպիզացիա
- Կառուցվածք
Ֆայլը տարբեր լեզուներում կարող է հանդես գալ որպես ծրագրային կառուցվածքի որոշակի բաղադրիչ, ինչպես, օրինակ, Java լեզվում ֆայլը ներկայացնում էր մեկ կամ ավելի կլաս։ Python լեզվում ֆայլը հանդես է գալիս որպես մոդուլ (
module
)։ Մոդուլը իր մեջ կարող է պարունակել. 1) գլոբալ միջակայքի հրահանգներ, 2) ֆունկցիաներ և 3) կլասեր։
Մոդուլներն իրենց հերթին ֆայլային համակարգում խմբավորվում են որպես «փաթեթ» (
package
)։ Python 3.3 և ավելի վաղ տարբերակներում ֆայլային համակարգի հասցեն (directory) համարվում է փաթեթ, եթե տվյալ հասցեում առկա է__init__.py
ֆայլ՝ որպես կողմնորոշիչ (բովանդակությունը պարտադիր չէ)։ Այնուամենայնիվ, նոր տարբերակներում այս ֆայլը կարող է օգտակար լինել փաթեթի մակարդակում ընդհանուր տվյալներ ունենալու տեսանկյունից, քանի որ ներառված կոդի դեպքում այն բեռնավորվում է փաթեթում գտնվող բոլոր մոդուլների (ֆայլերի) բեռնավորման կոնտեքստում և գործում է որպես ընդհանուր կոդ։
- Import
Մոդուլները ներմուծվում են
import
արտահայտությունների օգնությամբ։
import sys # import module import os as os_ # import module renamed from math import sin, pi # import specific part(s) directly from random import * # import all parts directly print(sys.platform) print(os_.cpu_count()) print(sin(pi/2)) print(randint(50, 100))
linux 12 1.0 80
- Հատուկ նշագրում (notation)
Ընդգծման նշագրումը (underscore notation) Python լեզվում ունի հատուկ նշանակություն։ Այդպիսի անվանակոչումների հիմնական նպատակը համակարգի (ներքին) օգտագործման անվանումների (ֆայլեր, փոփոխականներ, etc.) և ծրագրավորողի կողմից ստեղծվող անվանումների հնարավոր «ընդհարման» (collision) բացառումն է։ Կան նաև հատուկ նշումներ կլասի ատրիբուտների համար, քանի որ կլասի բաղադրիչները «պաշտպանված» չեն
private
,protected
կամ այլ կարգավորիչներով։
Կլասի կառուցվածքը դիտարկվում է հաջորդող դասընթացի ընթացքում։
_name
Ներքին օգտագործման նշան, որը հիմնականում անտեսվում է ինտերպրետատորի կողմից (բացառությամբ from <module> import *
կառուցվածքով ներմուծման դեպքերից)։name_
Բանալի֊բառերի (keywords) հետ ընդհարումից խուսափելու միջոց։ __name
Triggers name mangling when used in a class context. Enforced by the Python interpreter. __name__
Համակարգի (ներքին) օգտագործման անվանումների հետ ընդհարումից խուսափելու միջոց։ Եզակի ընդգծման նշանը առանց տառանշանների (
_
) օգտագործվում է որպես ժամանակավոր անանուն փոփոխական, որի արժեքի տվյալ կոնտեքստում չի օգտագործվում: Նաև օգտագործվում է ինտերակտիվ տերմինալում որպես նախորդ արտահայտության արտաբերման փոփոխական։
for _ in range(limit): # do some stuff iterating
>>> 2 + 2 4 >>> 3 + _ 7
- Import
- Հիմնական տվյալների տիպեր
- Numbers
Թվային արժեքները դինամիկ են տիպիզացված, սակայն ունեն որոշ առանձնահատկություններ․
- Ամբողջ թվերը չունեն մեքենայական բիթային դասակարգում և սահմանափակվում են միայն հիշողությամբ (անդրադառնալով, բնականաբար, արագագործության վրա),
- Բաժանման համար կա երկու օպերատոր`
/
- միշտ տասնորդական արդյունքով, և//
- միշտ ամբողջ թվի արդյունքով (կրճատելով տասնորդական մասը), - Թիվը աստիճան է բարձրացվում հիմքը և ցուցիչը կրկնակի բազմապատկման նշանի օգնությամբ անջատելով՝
2**8 = 256
:
Հանրահաշվական օպերատորները, կախված տվյալներից, կարող են լինել նաև պոլիմորֆ։ Ոչ թվային տվյալների նկատմամբ նույնպես կարելի է կիրառել որոշ օպերատորներ։
>>> 2 + 2.4 4.4 >>> 2 + 40 42 >>> 2 + "40" TypeError >>> 5 // 2 # truncate decimal part 2 >>> 6 / 3 # always decimal 2.0
- Ամբողջ թվերը չունեն մեքենայական բիթային դասակարգում և սահմանափակվում են միայն հիշողությամբ (անդրադառնալով, բնականաբար, արագագործության վրա),
- Lists
Զանգվածների դերը կատարում է մեկ ընդհանուր
list
տվյալի տիպը։ Լիստերն ունեն դինամիկ ծավալ և փոփոխվող բովանդակություն։ Տիպիզացիան նույնպես դինամիկ է, սակայն նման մոտեցում սովորաբար խորհուրդ չի տրվում՝ անկանխատեսելի վարքագիծ առաջացնելու պատճառով։ Լիստերը հայտարարվում են քառակուսի չակերտների[]
օգնությամբ։
Լիստերի ինդեքսացիան սկսվում է 0-ից, իսկ էլեմենտների հասանելիությունը կատարվում է զանգվածներին բնորոշ եղանակով։ Նոր էլեմենտներ կարելի է ավելացնել
append
(վերջում) կամinsert
(նշված ինդեքսով) ֆունկցիաների օգնությամբ՝ որպես լիստ տվյալ պարունակող փոփոխականի «մեթոդ»։ Ինդեքսային ցուցիչը կարող է լինել բացասական արժեք, օրինակ՝ վերջին էլեմենտի համար կարելի է նշել[-1]
ինդեքս։
lst = [1,2,3,4,5,6,7] newLst = lst newLst[0] = "one" print(lst)
['one', 2, 3, 4, 5, 6, 7]
Լիստերը նույնպես ենթարկվում են որոշ հանրահաշվական գործողությունների։
>>> [1,2] + [3,4,5,6,7] # concatenation [1,2,3,4,5,6,7] >>> 3 * [1,2,3] # concatenation [1,2,3,1,2,3,1,2,3]
- Strings
Տեքստային տվյալներն իրենցից ներկայացնում են տառանշանների (character) հերթականություն։ Նաև որպես փոփոխական կարող են կրել բայթերի հաջորդականություն։ Տառանշանների առանձին տիպ չկա, տառանշանը «մեկ տառ» ծավալով տեքստն է։
Տեքստային տվյալների հետ կարելի է աշխատել ինչպես ստանդարտ հավաքածուների (list), այն տարբերությամբ, որ տեքստային տվյալները բովանդակությամբ անփոփոխ են (immutable)։ Տեքստային տվյալները կարելի է հայտարարել եզակի
'
կամ կրկնակի"
չակերտներով։ Չակերտներից մեկով նշելու դեպքում՝ մյուսը անտեսվում է, և հատուկ կարգավորիչ նշանի (escape character) կարիք չի առաջանում։
s = "String declaration" # s[0] = "X" - produces TypeError (strings are immutable) dChar = s[7] print('7th lement of "s" is ' + dChar) # no escape
7th lement of "s" is d
Տեքստային տվյալները նույնպես ենթարկվում են որոշ հանրահաշվական գործողությունների։
>>> "Hello " + "Ajapnyak!" # concatenation Hello Ajapnjak! >>> 3 * "Hooray! " # concatenation Hooray! Hooray! Hooray!
- Tuples
Որոշակի քանակով և հերթականությամբ տվյալների խումբ, որը հայտարարվում է սովորական փակագծերի օգնությամբ և, ի տարբերություն լիստերի, բովանդակությամբ անփոփոխ է (immutable)։
t = (0, 'One', True) # t[0] = 1 - produces TypeError (tuples are immutable) print(t[1] + ", Two, Three...")
One, Two, Three...
- Dictionaries
Բանալի֊արժեք (key-value) զույգերի դասական հավաքածու, որտեղ արժեքի հասանելիությունը ապահովում է չկրկնվող (unique) բանալին։
d = {'a': 97, 'b': 98} print(d) d['c'] = 99 print(d) d['a'] = 1000 print(d)
{'a': 97, 'b': 98} {'a': 97, 'b': 98, 'c': 99} {'a': 1000, 'b': 98, 'c': 99}
- Sets
Չկրկնվող էլեմենտների հավաքածու առանց որոշակի հերթականության և ինդեքսացիայի։ Բացի սեփական մեթոդներից՝ ենթարկվում է հանրահաշվական և բուլյան որոշ գործողությունների։
s = {'a', 'b', 'c'} s.add('d') print(s) print({1,2,3,4} and {2,4,6}) print(s - {'a','b'})
{'b', 'a', 'd', 'c'} {2, 4, 6} {'d', 'c'}
Դատարկ փակագծերով
s = {}
հայտարարումը ստեղծում էdictionary
հավաքածու։
- Booleans
Բուլյան արժեքները կրկնում են դասական մոտեցումը, սակայն գրվում են գլխատառ՝
True
ևFalse
:
Բոլոր թվային, տեքստային և հավաքածուների տիպի օբյեկտները կարող են ենթարկվել պայմանային (consitionel) ստուգման՝ որպես բուլյան տիպ։ Զրոյական արժեքով թվային տվյալները և զրոյական ծավալով հավաքածուները (
0
,0.0
,""
,[]
,{}
) դիտարկվում են որպեսFalse
, բոլոր այլ արժեքների դեպքում`True
:
n = -256 l = ['a', 'b', 'c'] if n: print("n != 0") if l: print("l is not empty")
n != 0 l is not empty
Այնուամենայնիվ,
True
ևFalse
հատուկ անունները բանալի֊բառեր են և հավասար են համապատասխանաբար1
և0
արժեքների, այդ իսկ պատճառով5 == True
արտահայտությունը «ճիշտ չէ» (False)։
- Numbers
- Built-in helpers
Python ինտերպրետատորի միջավայրում նախապես ներբեռնված են բազմաթիվ ֆունկցիաներ, որոնք օգնում են ինտերակտիվ տերմինալում ներբեռնված փոփոխականները և ֆունկցիաները տեսնելու հարցում։
dir( name ) Արտաբերում է նախօրոք բեռնված և ներմուծված բոլոր մոդուլները և փոփոխականները type( name ) Արտաբերում է փոփոխականի տիպը և տեսակը (օր. ֆունկցիա լինելը) help( name ) Արտաբերում է դոկումենտացիան, եթե այդպիսին առկա է
3.9 Ֆունկցիոնալ գործիքներ (Python)
Ֆունկցիաները մուլտիպարադիգմ լեզուներում սովորաբար լինում են «ազատ» (free functions) կամ որևէ կլասի անդամ (մեթոդներ)։ Ներդրված (nested) և անանուն ֆունկցիաներն, իրենց հերթին, հավելյալ ճկունություն են հաղորդում լեզվին։
Արդեն ծանոթ print
ֆունկցիան նույնպես ազատ ֆունկցիա է։ Առկա են նաև տիպերի փոխարկման և ինիցիալիզացիայի համանուն ազատ ֆունկցիաներ՝ int()
, str()
, list()
, dict()
և այլն, որոնց օբյեկտ֊օրիենտացված լեզուների պարագայում (օրինակ՝ Java) փոխարինում են համանուն կլասերի ստատիկ մեթոդները, օրինակ՝ Integer.parseInt()
, String.valueOf()
և այլն։
Ազատ ֆունկցիաները և կլասերի մեթոդները մուլտիպարադիգմ լեզուներում ըստ էության կիրառվում են հավասարապես։
l = [4,5,6,7] print(l) # use class meber function (method) l.append(8) print(l) # declare a free function def appendToList(lst, item): lst.append(item) # use free function doing the same appendToList(l, 9) print(l)
[4, 5, 6, 7] [4, 5, 6, 7, 8] [4, 5, 6, 7, 8, 9]
Ֆունկցիան հայտարարվում է def
բանալի֊բառի (keyword) օգնությամբ, որին հաջորդում է ֆունկցիայի անվանումը։ Հայտարարելուց հետո ֆունկցիային կարելի է հղում անել ինչպես փոփոխականի՝ փոխանցել որպես արգումենտ, վերադարձնել մեկ այլ ֆունկցիայից կամ կցել մեկ այլ փոփոխականի։ C լեզվաընտանիքի լեզուների շարահյուսությամբ, որն այս կոնտեքստում ժառանգել է նաև Python լեզուն, ֆունկցիան ենթարկվում է կատարման կամ կիրառման (apply), երբ ֆունկցիայի անվանմանը հաջորդում են փակագծերը՝ համապատասխան արգումենտների փոխանցմամբ կամ առանց արգումենտների։
Որպես արգումենտ փոխանցվող ֆունցիաներն այդ կոնտեքստում կոչվում են callback, եթե կիրառվում են (apply) «ընդունող» ֆունկցիայի ներսում:
def add(x, y): return x + y # get a 'callback' function as an argument def doArg2(f, a1, a2): return f(a1, a2) # apply 'f' # if first argument is not a function - TypeError res = doArg2(add, 7, 8) # pass 'add' as an argument print(res) # assign function to variable do = doArg2 res = do(add, 12, 15) # reassign res variable print(res)
15 27
Python լեզվում առկա են բազմաթիվ ազատ ֆունկցիաներ, որոնք լռելյայն (by default) ներբեռնվում են բոլոր մոդուլներում (ֆայլերում)։ Այդ ֆունկցիաների ցանկը կարելի է տեսնել dir(__builtins__)
հրամանն ինտերակտիվ տերմինալ ներմուծելով (ֆունկցիայի, ինչպես և փոփոխականների, անունները սկսվում են փոքրատառ):
Տվյալների և ֆունկցիաների անվանումները, որպես համարժեք «սիմվոլ» (անվանում, որով գրանցվում է հղումը), նշագրմամբ չեն տարբերվում։ Այդ պատճառով կարիք է առաջանում ստուգելու՝ արդյոք սիմվոլը տվյալի հղում է, թե ֆունկցիայի։ Նման դեպքերում կարելի է օգտվել type( symbol )
ֆունկցիայից։
- Functions and arguments
Ֆունկցիաներն, առհասարակ, ունեն երեք կարևորագույն հատկանիշ՝ արգումենտներ, վերադարձվող արժեք և էֆեկտ (արտաքին միջավայրի հետ ներգործություն)։ Դինամիկ տիպիզացմամբ լեզուներում ֆունկցիաները տարբերակվում են մեծ հաշվով ըստ ընդունվող արգումենտների քանակի, քանի որ մինչև կատարման պահը տիպային տարբերակում չկա։
Որևէ արժեք կամ հղում ուղղակիորեն չվերադարձնելու դեպքում ֆունկցիան լռելյայն (by default) վերադարձնում է
None
, որն իրենից ներկայացնում է հղման և արժեքի բացակայություն (null
)։
def sayHello(): print("Hello!") # no return statement res = sayHello() print(res)
Hello! None
- Fixed (positional) arguments
Արգումենտները սովորաբար հայտարարվում են ուղղակիորեն՝ որպես «ներքին» փոփոխականներ, որոնք կիրառման պահին փոխարինվում են փոխանցված փոփոխականներով (հղումներով)։
def add3(n1, n2, n3): return n1 + n2 + n3 res = add3(2, 3, 4) print(res)
9
- Named arguments
Արգումենտները կարող են փոխանցվել կամայական հերթականությամբ, եթե հղում են արվում հայտարարված փոփոխականներին։
def greet(msg, name): print(msg + ", " + name + "!") greet(name="Varazdat", msg="Hello")
Hello, Varazdat!
- Variable number of arguments
Տարբեր լեզուներում հայտնի է նաև փոփոխական քանակի արգումենտներով ֆունկցիայի հայտարարման տարբերակ։ Python լեզվում դա նույնպես հնարավոր է
*
նախածանցի օգնությամբ։
def add(*ns): acc = 0 for n in ns: acc += n return acc print(add(2, 2018)) print(add(8, 7, 5, 10, 8, 4)) print(add())
2020 42 0
Փոփոխական քանակով արգումենտները հաջորդում են ֆիքսված արգումենտներին, եթե այդպիսիք հայտարարված են՝
def f(x, y, *args):
, հակառակ դեպքում, օրինակ՝def f(x, *args, y):
, հաջորդող արգումենտները պետք է փոխանցվեն միայն անվանական փոփոխականով`f(5, 6, 7, 8, y=9)
:
- Variable number of keyword arguments
Փոփոխական արգումենտները
**
նախածանցի օգնությամբ կարող են հայտարարվել նաև բանալի֊արժեք տրամանաբանությամբ՝ փոփոխական քանակով արգումենտների հայտարարմանը հաջորդող, եթե այդպիսիք հայտարարված են։ Նման արգումենտները փոխանցվում են խստորեն անվանապես։
def dimensions(**obj): print("Width: " + obj["w"] + "\nHeight: " + obj["h"]) dimensions(w="218mm", h="326mm")
Width: 218mm Height: 326mm
- Default arguments
Արգումենտները կարող են հայտարարվել նաև լռելյայն (default) արժեքով` ֆիքսված և փոփոխական քանակով արգումենտներից հետո, ինչը պրակտիկորեն կարող է փոխարինել ֆունկցիաների վերաբեռնավորումը (overloading)։
def greet(name, msg="Hello", opt="How are you?"): print(msg + ", " + name + "! " + opt) # fixed args only greet("Tigran") # pass 'msg' inplace, 'opt' is default greet("Tigran", "Hi") # 'msg' is default, pass 'opt' by name (otherwise casts 'msg') greet("Tigran", opt="")
Hello, Tigran! How are you? Hi, Tigran! How are you? Hello, Tigran!
Արդեն հայտնի
print
ֆունկցիան իրականում հայտարարված է մոտավորապես (բաց թողնելով որոշ դետալներ) հետևյալ կերպdef print(*args, sep=' ', end='\n', file=sys.stdout):
, այսինքն՝ կարելի է ուղղակիորեն փոխանցել մեկից ավելի արգումենտեր և փոփոխել լռելյայն արգումենտները, որոնք կարգավորում են համապատասխանաբար՝ մեկից ավելի արգումենտների բաժանարարը, տողի ավարտը (որն արդեն համանման կարգավորում ունի) և արտաբերման ֆայլը (որը կարելի է փոխել ցանկացած այլ ֆայլով)։
print(1, 2, 3) print(1, 2, 3, sep=", ") print(1, 2, 3, sep="") print("Bye", end=" ") print("Bye")
1 2 3 1, 2, 3 123 Bye Bye
- Fixed (positional) arguments
- Anonymous functions
Անանուն ֆունկցիաները
lambda
արտահայտության շնորհիվ կարող են հայտարարվել անհրաժեշտ տեղում կամ կցվել փոփոխականի՝ դառնալով անվանական։ Անանուն ֆունկցիայի բաժանարարն է:
նշանը, որից առաջ հայտարարվում են արգումենտները։ Անանուն ֆունկցիան վերադարձնում է բաժանարար նշանից աջ գտնվող արտահայտության կատարման արժեքը։
def do(f, a, b): # get function by argument return f(a, b) # apply function and return result # assign lambda to variable mult = lambda x, y: x*y # pass 'mult' as 'f' to 'do' with nums print(do(mult, 3, 12)) # pass lambda as 'f' to 'do' with nums print(do(lambda x, y: x**y, 2, 8))
36 256
- Nested functions
Ֆունկցիոնալ պարադիգմի լեզուներում հաճախ կարելի է հայտարարել նաև ներդրված ֆունկցիաներ։ Ներդրված ֆունկցիաները ուղղակիորեն հասանելի են միայն արտաքին պարփակող ֆունկցիայի համար, եթե չեն վերադարձվում վերջինի կողմից։ Վերաօգտագործման տեսանկյունից ներդրված ֆունկցիաները տարբերվում են յուրօրինակ «ինկապսուլյացիայով»։
- Closure
(Замыкание ռուս․) Երբ պարփակող ֆունկցիան վերադարձնում է իր ներքին միջավայրում ներդրված ֆունկցիան որպես սեփական կատարման արդյունք՝ ներդրված ֆունկցիայի հետ միասին անուղղակիորեն դուրս է բերվում նաև ներդրված ֆունկցիան պարփակող միջավայրը։
# enclosing function def outerFn(): # local variable of outer function msg = "Hey! " # nested function def innerFn(name): print(msg + name) # outer function returns inner function return innerFn # return and assign inner function greet = outerFn() greet("I'm closure!")
Hey! I'm closure!
Տվյալ դեպքում պարփակող «միջավայրում» ընդգրկվում և ներդրված ֆունկցիայի հետ մեկուսացվում են նաև պարփակող ֆունկցիայի արգումենտները։ Հետևյալ մեխանիզմը հետաձգված կատարման և ֆունկցիոնալ կոմպոզիցիայի օրինակ է։
# 'base' is also bound to closure def powerOf(base): # inner function may be anonymous return lambda p: base**p # composing new functions powerOfTwo = powerOf(2) powerOfThree = powerOf(3) print(powerOfTwo(8)) # замыкание print(powerOfThree(3)) # замыкание
256 27
- Generators
Վերը նշված մեխանիզմները կարող են ստեղծել նաև յուրoրինակ գեներատորներ, որոնք պահպանում և, միաժամանակ, մեկուսացնում են իրենց կցված վիճակը (state)։
Ներքին ֆունկցիայից պարփակող ֆունկցիայի փոփոխականը փոփոխելու համար հարկավոր է օգտագործել
nonlocal
բանալի֊բառը, հակառակ դեպքում վերահայտարարելու փորձ է արվելու։ Հետևյալ օրինակում վիճակի (state) փոփոխումը կատարվում էstate += 2
արտահայտությամբ, որը համարժեք էstate = state + 2
արտահայտությանը։ Հետևաբար արտահայտությունը կառաջացնիUnboundLocalError
բացառություն՝ ընդգծելով, որstate
փոփոխականին հղում է արվում մինչև հայտարարելը:
def makeEvenGenerator(): state = 0 def nextEven(): nonlocal state state += 2 return state return nextEven # make a generator evenGen = makeEvenGenerator() print(evenGen()) # next state print(evenGen()) # next state print(evenGen()) # next state print(evenGen(), end="\n\n") # next state # make another generator evenGen_ = makeEvenGenerator() print(evenGen_()) # next state of new generator
2 4 6 8 2
Կան գեներատորների և իտերատորների ստեղծման այլ օրինակներ, որոնք կդիտարկվեն հաջորդող դասընթացներում։
- Closure
3.10 Այլ պրակտիկ գործիքներ (Python)
«Բարձր մակարդակի» դինամիկ տիպիզացմամբ լեզուներն ըստ էության օժտված են մի շարք շարահյուսական և իմաստաբանական առավելություններով, որոնք փորձում են փոխհատուցել կատարման արագագործությունը։
- Yield
Նախորդ դասընթացում դիտարկված գեներատորները, որոնք ստացվում էին ներդրված ֆունկցիաների օգնությամբ, ունեն ևս կառուցման ավելի կանոնիկ եղանակ։ Այս դեպքում հիմնական ֆունկցիան, առանց ներդրված ֆունկցիայի առկայության, արդյունքը վերադարձնում է
yield
օպերատորի օգնությամբ և պահպանում է ընթացիկ վիճակը։
def makeEvenGenerator(): state = 0 while True: state += 2 yield state # no return statement # make generator object g = makeEvenGenerator() print(type(g)) # use 'next' function to generate next value print(next(g)) print(next(g)) print(next(g))
<class 'generator'> 2 4 6
Այս եղանակով ստացված գեներատորները կարելի է լիարժեք կիրառել ցիկլերում։
def makeEvenRange(n): state = 0 while state < n: state += 2 yield state # no return statement # make generator object for i in makeEvenRange(18): print(i, end=" ")
2 4 6 8 10 12 14 16 18
- Sequences
Հաջորդական տրամաբանությամբ տվյալները, օրինակ՝
Լist
ևString
), ունեն շարահյուսական մի շարք ճկուն մեխանիզմներ։
- Сomprehensions
Լիստերը կարելի է գեներացնել ներդրված արտահայտությունների օգնությամբ`
<statement>
<for loop>
<optional conditionel>
:
# creates list from 0 to 9 r = [x for x in range(10)] # creates hal-of-evens list from 0 to 15 d = [x/2 for x in range(16) if x % 2 == 0] # 2d list generation - a la TicTacToe t = [[x for x in range(3)] for y in range(3)] print(type(r), r) print(type(d), d) print(type(t), t)
<class 'list'> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] <class 'list'> [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0] <class 'list'> [[0, 1, 2], [0, 1, 2], [0, 1, 2]]
Նույն արտահայտությունները հասարակ փակագծերի
()
մեջ առաջացնում են «հետաձգված կատարմամբ» գեներատորներ:
# generate square-of-evens list from evens from 0 to 11 gen = (x**2 for x in range(12) if x % 2 == 0) print(type(gen)) for i in gen: print(i, end=" ")
<class 'generator'> 0 4 16 36 64 100
Կախված իրականացման տրամաբանությունից՝ միջակայքի հիման վրա հավաքածուներ ստեղծող ֆունկցիաները կարող են ներառել կամ չներառել նշվող արժեքները։ Օրինակ՝
range
ֆունկցիան չի ներառում միջակայքի «վերջնական» ինդեքսը (stop index), այդ պատճառովrange(10)
կիրառումը ստեղծում է 0֊ից մինչև 9 թվերի հերթականությունը։
- Slices
Հավաքածուներից որևէ «կտրվածք» ստանալու կամ տեղում փոփոխելու համար կարելի է օգտագործել հատուկ նշագրում, որը թույլ է տալիս քառակուսի փակագծերի մեջ ինդեքսի փոխարեն նշել միջակայք, որը նույնպես չի ներառում «վերջնական» (stop) ինդեքսի արժեքը։ Բացասական արժեքի դեպքում ինդեքսացիան հաշվի է առնվում վերջից՝ հակառակ ուղղությամբ։ Նոր կտրվածքները փոխանցվում են որպես նոր տվյալ և ելակետային հղում չեն պահպանում, սակայն կարող են օգտագործվել որպես հղում տվյալների փոփոխման համար։
l = [1,2,3,4,5,6,7] # create new list by slice s = l[2:4] r = l[2:-3] print(s) print(r) # modify initial list by slice del l[5:] print()
[3, 4] [3, 4]
Միջակայքը կարելի է նշել բաց թողնելով «սկզբնական» (
[:i]
) կամ «վերջնական» ([i:]
) արժեքները։ Այդ դեպքում բաց թողնված արժեքների փոխարեն ենթադրվում են համապատասխանաբար «սկզբնական» (start) և «վերջնական» (stop) ինդեքսները։ Առանց միջակայքի նշման ([:]
) կարելի է ամբողջությամբ կրկնօրինակել հավաքածուն որպես նոր տվյալ։
s = "Telephone" print(s[-5:])
phone
Միջակայքին կարելի է ավելացնել նաև «քայլերի» արժեք՝ ավելացնելով ևս մեկ
:
բաժանարար։ Այս դեպքում ֆիլտրվում են միայն երրորդ ցուցիչին համապատասխան արժեքները։ Երրորդ արգումենտի բացասական լինելու դեպքում քայլերը հաշվառվում են վերջից՝ հակառակ ուղղությամբ։
l = [x for x in range(24)] p = "AREPO" print(l[1:10:2]) # filter odds up to 10 print(p[::-1]) # make reverse
[1, 3, 5, 7, 9] OPERA
- Сomprehensions
- Multivariable statements
Միևնույն մեկնարկային արժեքով փոփոխականներ կարելի է հայտարարել «շղթայական» հայտարարման ձևաչափով։ Քանի որ
=
նշանն ունի աջ ասոցիատիվություն՝ տվյալ հայտարարումը համարժեք է հերթական հայտարարմանը։
x = y = z = 0 # Same as... # z = 0 # y = z # x = y
Փոփոխվող (mutable) տվյալների դեպքում (օրինակ՝
list
կամdict
) հղում է կատարվում միևնույն տվյալին, նույնիսկ եթե տվյալը հայտարարվել է առանց բովանդակության։ Հետևաբար՝ փոփոխականներից մեկի օգնությամբ տվյալի բովանդակությունը փոփոխելիս փոխվում է մեկ ընդհանուր տվյալ բոլոր հղումների համար։
a = b = 0 # assign 'a' and 'b' a = 100 # reassign 'a' only ('b' remains 0) print("a =", a) print("b =", b) l = m = [] # assign 'l' and 'm' to empty list l.append(42) # change content of 'l' only print(l) print(m)
a = 100 b = 0 [42] [42]
- Multple value assignments
Tuple
ևList
տվյալների տիպերը հանդես են գալիս ոչ միայն որպես տվյալների փաթեթավորման (wrap) յուրօրինակ մեխանիզմ է, այլ նաև մեծ դեր են կատարում շարահյուսական առումով։ Այսպես, օրինակ, նշված տիպերի օգնությամբ կարելի է հայտարարել միանգամից մի քանի փոփոխականներ։
t = (2, 4) # assign tuple to 't' (x, y) = (5, 10) # assign elements to variables [a, b] = [50, 100] # assign elements to variables print(t) print(x) print(y) print(a) print(b) # ValueError # (a, b) = ('a', 'b', 'c')
(2, 4) 5 10 50 100
Քանի որ
Tuple
տիպը որոշ դեպքերում (ոչ ներդրված) կարելի է հայտարարել նաև առանց փակագծերի, ապա փոփոխականների հայտարարման շարահյուսությունն ավելի ընկալելի կարող է դառնալ։
x, _, y = 7, 10, 50 # middle value is ignored n, l = "text", [1,2,3] print(x, y) print(n) print(l)
7 50 text [1, 2, 3]
- Multiple comparison
Նույն տրամաբանությամբ կարող են կառուցվել նաև շղթայական համեմատության արտահայտությունները՝ ըստ օպերատորի ասոցիատիվության։ Հետևյալ օրինակում շղթայական համեմատությունը համարժեք է
and
օպերատորի կիրառման, սակայն համեմատական արտահայտությունն այս դեպքում «արժևորվում» է (evaluate) միայն մեկ անգամ։ Այստեղ, նույնպես, առաջին մասի «սխալի» (False) դեպքում երկրորդ մասը կատարման ենթակա չէ։
from math import sin, pi if 0 < sin(pi/6) < 0.5: print("IEEE 754 makes sin(30°) < 1/2 -", sin(pi/6)) # Same as... # x = sin(pi/6) # if x >= 0 and x < 100:
IEEE 754 makes sin(30°) < 1/2 - 0.49999999999999994
- Multple value assignments
- Unpacking
Tuple
տիպը տալիս է բազմակի հայտարարման ևս մեկ մեխանիզմ՝ unpacking, որի շնորհիվ կատարվում է «ապափաթեթավորում»։
def listOfEvens(n1, n2): res = [x for x in range(n1, n2) if x % 2 == 0] return res x, y, *rest = listOfEvens(6, 24) print(x) print(y) print(rest)
6 8 [10, 12, 14, 16, 18, 20, 22]
Ի տարբերություն ֆունկցիայի արգումենտների նշագրման՝ այստեղ հատուկ նշանով (
*
) փոփոխականի տեղադիրքը կարող է լինել սկզբում կամ ֆիքսված փոփոխականների միջև։
*_, last = [x for x in range(24) if x % 2 == 0] print(last)
22
- Argument unpacking
Աստղանիշ (
*
) նախածանցով շարահյուսությունը կարելի է կիրառել նաև ֆունկցիայի արգումենտ փոխանցելիս և փոփոխական հայտարարելիս։ Այդ դեպքում ֆուկցիան ստանում է ոչ թե մեկ արգումենտ, այլ տվյալ արգումենտի (list, tuple, etc.) բոլոր էլեմենտները՝ որպես առանձին արգումենտ։
Այսպես, հավաքածուների էլեմենտները արտաբերելիս, կարելի է այն
print
ֆունկցիային փոխանցել «ապափաթեթավորված» (unboxed
) եղանակով։
l = [1,2,3,4] print(*l) # Same as... # print(l[0], l[1], l[2], l[3])
1 2 3 4
Տվյալ շարահյուսությունը կիրառելի է նաև բանալի֊արժեք (key-value) հավաքածուների պարագայում, եթե արգումենտներն անվանական փոխանցման դեպքում համընկնում են։
def testUnboxing(a, b, c): print(a, b, c) d = {'a': 97, 'b': 98, 'c': 99} testUnboxing(**d) # Same as... # testUnboxing(a=97, b=98, c=99)
97 98 99
Փոփոխական հայտարարելիս նույնպես կարելի է օգտագործել տվյալ շարահյուսությունը։
a = [*"String"] # Same as... # a = ['S','t','r','i','n','g'] print(a)
['S', 't', 'r', 'i', 'n', 'g']
- Argument unpacking
- Module entrypoint
Քանի որ ինտերպրետացիոն լեզուներում մոդուլները (ֆայլերը) ներբեռնելիս ենթակա են կատարման ամբողջությամբ՝ խնդիր է առաջանում առանձնացնել դեկլարատիվ կոդը կատարման ենթակա կոդից և մեկուսացնել կատարման ենթակա կոդը այլ մոդուլներ ներբեռնելու ընթացքում կատարվելուց։ Այդ նպատակով անմիջական կատարման ենթակա կոդը առանձնացվում է հատուկ ձևաչափով պայմանային արտահայտությամբ, որի իսկությունը դրական (
True
) արդյունք է ունենում միայն այն դեպքում, երբ տվյալ մոդուլը կատարման է ենթարկվում ուղղակիորեն։
Հետևյալ օրինակում
lib.py
մոդուլը ներմուծվում էtest.py
մոդուլ, սակայն անմիջական կատարման արտահայտությունները մեկուսացված են հատուկ միջակայքում և կատարման ենթակա են միայն մոդուլի ուղղակի գործարկման դեպքում, մինչդեռ ազատ հայտարարված ֆունկցիաները ներմուծվում են և հասանելի են։
# lib.py # declarations available for import def resPrint(res): print("Res:", res) # code running only on direct exec of module if __name__ == "__main__": # ... exec some code print("lib.py: I'm the main module and running directly!")
# test.py from demo import * if __name__ == "__main__": # use imported function resPrint(42)
Այս դեպքում
test.py
մոդուլը ուղղակիորեն գործարկելուց հասանելի են ներմուծվող մոդուլի ֆունկցիաները, սակայն մեկուսացված արտահայտությունները չեն կատարվում։
python test.py
Res: 42
Իսկ
lib.py
մոդուլի կատարման մասը հասանելի է դառնում միայն տվյալ մոդուլի ուղղակի գործարկման արդյունքում։
python lib.py
lib.py: I'm the main module and running directly!
Արտաքին միջավայրից փոխանցված արգումենտները հասանելի են
sys
մոդուլիargv
լիստ տիպի փոփոխականի միջոցով, որտեղ առաջին էլեմենտը կատարման ենթակա մոդուլի (ֆայլի) անունն է։
# test.py import sys if __name__ == "__main__": print(sys.argv)
python test.py argument1 argument2
['test.py', 'argument1', 'argument2']
- Կրկնություն
Օբյեկտ֊օրիենտացված ծրագրավորման փուլի վերջում տրվել էր հղում ծանոթության համար: Այդ թեմաների հետ զուգահեռներ անցկացնելու նպատակով տրվում են հավելյալ հղումներ Python լեզվի կոնտեքստում։
- Հղում ծանոթության համար - Built-in Functions, Decorators, String formatting, GIL, Async/Await
- Հղում ծանոթության համար - Built-in Functions, Decorators, String formatting, GIL, Async/Await
3.11 Օբյեկտ֊օրիենտացման գործիքներ (Python)
Այստեղ կդիտարկվեն միայն Python լեզվի օբյեկտ֊օրիենտացված մոտեցման առանձնահատկությունները, քանի որ բազային հասկացություններն արդեն դիտարկվել են նախորդող դասընթացների ընթացքում։
Օբյեկտ֊օրիենտացման մոտեցումը ինտերպրետացիոն լեզուներում հիմնականում ավելի ազատ է, քան կանոնիկ լեզուներում, առկա են տվյալների փոփոխման ավելի ճկուն մեխանիզմներ, սակայն այդ «ազատության» հետևանքներն ամբողջությամբ մնում են ծրագրավորողի պատասխանատվության տակ։
Կլասերը հայտարարվում են class
բանալի֊բառի օգնությամբ, իսկ կլասի անվանումը գրվում է գլխատառ՝ ֆունկցիաների հետ չշփոթելու համար։ Կլասի օրինակը (օբյեկտը) ստեղծվում է կլասի անվանմանը կցելով ֆունկցիայի կիրառման ()
նշագրումը։
Հետևյալ օրինակում EmptyClass
կլասն ունի միայն անվանում և լռելյայն կոնստրուկտոր, որի օգնությամբ ստեղծվում է կլասի օրինակ և կցվում է e
փոփոխականին։ Կլասն առանց բովանդակության հայտարարելու համար օգտագործվում է pass
օպերատորը, որը ոչ մի կատարում չունի և այս դեպքում դատարկ միջակայք է նշում (միջակայքը փակագծերով առանձնացնող լեզուների պարագայում դրա կարիքը չկա)։
# create an empty class class EmptyClass: pass # make an instance (object) of EmptyClass e = EmptyClass()
- Attributes
Քանի որ Python լեզվում, ինչպես ինտերպրետացիոն լեզուների մեծամասնության դեպքում, չկան հասանելիության
public
ևprivate
կարգավորիչներ՝ կլասերում հայտարարված բոլոր տվյալները հասանելի են ամբողջությամբ (նաև փոփոխման համար)։ Ավելին՝ կլասի օրինակին (օբյեկտին) կարելի է կցել կլասում չհայտարարված նոր տվյալ։ Հետևյալ օրինակում համատեղվել են նաև տեքստային տվյալների «ֆորմատավորման» (string formatting) տարբեր լուծումներ։
# create a class with class attributes only class TestClass: attr1 = "test attribute" attr2 = 0 # maken an instance tc = TestClass() # old 'printf' string formatting print("attr1: %s\nattr2: %s\n" % (tc.attr1, tc.attr2)) # set attributes tc.attr1 = "new attribute" tc.attr2 = 42 # new string formatting print("attr1: {0}\nattr2: {1}\n".format(tc.attr1, tc.attr2)) # set NEW attribute tc.attr3 = True # literal string formatting print(f"attr3: {tc.attr3}")
attr1: test attribute attr2: 0 attr1: new attribute attr2: 42 attr3: True
Ինչպես նշված է մեկնաբանությամբ՝ նման ձևով հայտարարվում են բացառապես կլասի տվյալներ, որոնք հասանելի են նաև կլասի օրինակի համար, ինչը միանշանակ չէ առաջին հայացքից։ Կլասի օրինակի կողմից սեփական համանուն փոփոխական հայտարարելու արդյունքում կլասի տվյալները «ստվերվում» են։
class TestClass: attr = "test attribute" # maken two instances tc1 = TestClass() tc2 = TestClass() print(f"tc1.attr: {tc1.attr}") print(f"tc2.attr: {tc2.attr}\n") # change class attribute TestClass.attr = "CLASS attribute" print(f"tc1.attr: {tc1.attr}") print(f"tc2.attr: {tc2.attr}\n") # create instance attribute tc2.attr = "INSTANCE attribute" print(f"tc1.attr: {tc1.attr}") print(f"tc2.attr: {tc2.attr}")
tc1.attr: test attribute tc2.attr: test attribute tc1.attr: CLASS attribute tc2.attr: CLASS attribute tc1.attr: CLASS attribute tc2.attr: INSTANCE attribute
- Constructor
Բացառությամբ կլասի մակարդակում տվյալ ունենալու տրամաբանության՝ վերը նշված օրինակը սովորաբար չի օգտագործվում, քանի որ կատարման վարքագիծը միանշական չէ։ Կլասի օրինակի տվյալները (ատրիբուտները) ընդունված է հայտարարել
__init__
կոնստրուկտորի օգնությամբ։
Ի տարբերություն С լեզվաընտանիքի՝ այստեղ կլասի միջակայքում տվյալների «նախնական» հայտարարում (
int age; String name;
) չկա, քանի որ այս միջակայքում հայտարարվող բոլոր փոփոխականները պատկանում են կլասին։ Փոխարենը, որպես մշտական առաջին արգումենտ, կոնստրուկտորի ֆունկցիայի համար հայտարարվում է պոտենցյալ ստեղծվող օրինակի (օբյեկտի) հղումը, որն ընդունված է անվանելself
: Այն օգտագործվում է բացառապես կլասի հայտարարման միջակայքում և փոխարինում է պոտենցյալ ստեղծվող օրինակի փոփոխականին։ Կլասի օրինակի ստեղծման ժամանակ տվյալ արգումենտը չի փոխանցվում։
class Ratio: # constructor with instance as first argument def __init__(self, divisor, divident): # creating instance attributes self.divisor = divisor self.divident = divident self.__num = 42 # creating instance without instance argument r = Ratio(3,4) print("Ratio[{0}/{1}]".format(r.divisor, r.divident)) # AttributeError # print(r.__x) - 'Ratio' object has no attribute '__x' print("Hidden attribute:", r._Ratio__num)
Ratio[3/4] Hidden attribute: 42
Տվյալների փոփոխականները տարբեր պատճառներով կարելի է թաքցնել (տես՝ հատուկ նշագրում) ուղղակի հասանելիությունից և տրամադրել համապատասխան
setter
ևgetter
մեթոդներ, սակայն պաշտպանել հնարավոր չէ։
- Methods
Կլասի օրինակի (օբյեկտի) մեթոդները կրկնում են կոնստրուկտորի տրամաբանությունը՝ հայտարարվում են պոտենցյալ օբյեկտի
self
առաջին արգումենտով, որը մեթոդի կիրառման ժամանակ չի փոխանցվում։
class Ratio: def __init__(self, divisor, divident): self.divisor = divisor self.divident = divident # all instance methods takes mandatory self def decimal(self): return self.divisor / self.divident r = Ratio(3, 4) print(r.decimal())
0.75
- Overloading
Python լեզվում կան կլասի հատուկ (
__<method>__
) մեթոդներ, որոնց օգնությամբ կարելի է վերաբեռնավորել տարբեր օպերատորներ և գործողություններ (operator overloading) կլասի օրինակների համար։
from math import gcd class Ratio: def __init__(self, divisor, divident): gcd_ = gcd(divisor, divident) self.divisor = divisor // gcd_ self.divident = divident // gcd_ # overloading '+' operator def __add__(self, other): if not isinstance(other, self.__class__): raise TypeError("operand is not 'Ratio' instance") newddt = self.divident * other.divident newdsr = other.divident * self.divisor + \ self.divident * other.divisor gcd_ = gcd(newddt, newdsr) # return new Ratio instance return Ratio(newdsr // gcd_, newddt // gcd_) # overloading '==' operator def __eq__(self, other): if self.__class__ != other.__class__: return False return self.divisor == other.divisor and \ self.divident == other.divident # overloading string representation on print def __str__(self): return f"Ratio[{self.divisor}/{self.divident}]" r1 = Ratio(6, 8) r2 = r1 + Ratio(1, 2) print(r1) print(r2) print(Ratio(1, 10) + Ratio(1, 5)) # 0.1 + 0.2 resolved print(Ratio(1, 2) == Ratio(3, 6)) # use __eq__ method print(Ratio(1, 2) is Ratio(1, 2)) # compares reference
Ratio[3/4] Ratio[5/4] Ratio[3/10] True False
- Iterator class
Հատուկ մեթոդների օգնությամբ կարելի է ստեղծել նաև որոշակի տրամաբանությամբ հետաձգված կատարմամբ ցիկլեր, որոնք ենթակա են
for
ցիկլերով անցման և հավաքածուների փոխարկման։
class Ranger: def __init__(self, end): self.start = 0 self.end = end def __iter__(self): return self def __next__(self): if self.start < self.end: start = self.start self.start += 1 return start else: raise StopIteration print(list(Ranger(8))) for n in Ranger(8): print(n, end=" ")
[0, 1, 2, 3, 4, 5, 6, 7] 0 1 2 3 4 5 6 7
- Iterator class
- Inheritance
Ժառանգականության տեսանկյունից կա մեկից ավելի կլասերից ժառանգելու հավելյալ ճկունություն, որը խորհուրդ չի տրվում չարաշահել, քանի որ այս հնարավորության վարքագիծը նույնպես միանշանակ չէ։
Ծնողական (parent) կլասերը հայտարարվում են ժառանգորդ կլասը հայտարարելիս՝ հասարակ փակագծերում և բաժանվում են ստորակետով։ Մեկից ավելի կլասերի դեպքում տվյալների և մեթոդների «փնտրումը» տեղի է ունենում ըստ հայտարարման՝ ձախից աջ։
Հետևյալ օրինակում
D
կլասը հայտարարվում է երկու ծնողական կլասի ժառանգականությամբ՝D(B, C)
: Կլասիd
փոփոխականին կցված օրինակով կիրառվում ենshow
ևshow_x
մեթոդները։ Քանի որD
կլասը չունիshow
մեթոդ՝ կլասի օրինակը մեթոդը փնտրում է հաջորդաբարB
ևC
կլասերում։B
կլասում մեթոդը չհայտնաբերելուց հետո միանգամից անցում է կատարվում հաջորդ ժառանկագան մակարդակ (B
->A
)։show_x
մեթոդը գտնվում է միայնC
կլասում, սակայն այս մեթոդում հղում ունեցողself.x
փոփոխական կլասում հայտարարված չէ։ Քանի որ տվյալի փնտրումը տեղի է ունենում սկզբնական ժառանգականության հաջորդականությամբ՝ այն վերցվում էA
կլասից։
class A: def __init__(self): self.x = 42 def show(self): print("Class A") class B(A): pass class C: def show(self): print("Class C") def show_x(self): print("Class C:", self.x) class D(B, C): pass d = D() d.show() d.show_x()
Class A Class C: 42
Վերը նշված կլասերի ժառանգականությունը կարելի է գրաֆիկորեն պատկերել հետևյալ կերպ՝
A [x, show] / / B C [show, show_x] \ / \ / D
- Պրակտիկ օրինակ
Նպատակն է ստեղծել բազմապլատֆորմ (cross-platform) գրաֆիկական ինտերֆեյսով (GUI) ցուցադրական հավելված՝ օգտագործելով Qt հայտնի համակարգը Python ծրագրավորման լեզվին փոխարկող PyQt ծրագրադարանը։ Ծրագրադարանի ներբեռնումը և միջավայրի կարգավորումը կազմակերպվում է
pipenv
հավելվածի օգնությամբ՝ ըստ այս պրոյեկտին կիցPipfile
ֆայլի բովանդակության:
Միջավայրի կարգավորման համար հարկավոր է, նախ,
pip install pipenv
հրամանի օգնությամբ տեղադրելpipenv
հավելվածը (pip
հավելվածն իր հերթին տեղադրվում է Python ծրագրավորման փաթեթի հետ միասին, տես՝ միջավայրի կարգավորում)։ Այնուհետև պրոյեկտի հասցեում հարկավոր է կիրառելpipenv install
հրամանը, որը կտեղադրիPipfile
ֆայլում նշված ծրագրադարանները։ Տեղադրումն ավարտելուց հետո կարելի է կատարել հավելվածի միակ ֆայլըpipenv run python main.py
հրամանի օգնությամբ։
Որոշ ինտեգրված ծրագրավորման միջավայրեր (օրինակ՝ PyCharm) թույլ են տալիս աշխատել վիրտուալ միջավայրերի կարգավորման հավելվածների հետ։
Հավելվածի կոդին առցանց կարելի է ծանոթանալ հետևյալ հասցեով՝ GitHub։
Հավելվածը կարելի է նաև «կրկնօրինակել» (git clone
) համապատասխան գործիքներով կամ ներբեռնել որպես դասընթացների ընդհանուր պրոյեկտ (project)` GitHub:
3.12 Ֆունկցիոնալ մոտեցում (Lisp)
Ֆունկցիոնալ ծրագրավորման առանձնահատկությունը կայանում է մաթեմատիկական տեսանկյունից ֆունկցիաների արժեքների հաշվարկման մեջ՝ օգտագործելով այլ ֆունկցիաների հաշվարկման արդյունքները, ինչը չի ենթադրում «վիճակի» (state) ուղղակի պահպանում։ Ի տարբերություն պրոցեդուրալ ծրագրավորման, որը հաջորդական կատարմամբ փոփոխում է ծրագրի «վիճակը»։
Վերը նշված համատեքստում միմյանց համապատասխանաբար հակադրվում են նաև դեկլարատիվ և իմպերատիվ մոտեցումները։
Ֆունկցիոնալ ծրագրավորման հիմնական առանձնահատկություններն են առաջին դասի ֆունկցիաները (first-class functions) և հղման թափանցիկությունը (referential transparency)։
- Lisp
Ֆունկցիոնալ ծրագրավորման կիրառական օրինակներից է Lisp (LISP - LISt Processor) ծրագրավորման լեզուն, որը «բարձր մակարդակի» ամենահին լեզուներից է (1958թ․)։
Բացի դինամիկ տիպիզացիայից՝ այս լեզուն հատկանշական է իր յուրօրինակ շարահյուսությամբ և պարզունակությամբ։ Որպես առանձնահատկություն՝ հատկանշական է նաև լեզվական «համասեռությունը» (homoiconicity), որը թույլ է տալիս կատարման ենթակա կոդը և տվյալները արտահայտել միևնույն շարահյուսությամբ։ Այսպիսով ամբողջ լեզվական շարահյուսությունը կարելի է բնութագրել, օրինակ, հետևյալ արտահայտությամբ`
(func arg1 arg2 arg3) ;; 3 args passed to function
․․․որտեղ փակագծերը համարժեք են արտահայտության որոշակի կատարման, առաջին սիմվոլը (symbol) կատարման ենթակա ֆունկցիան է, իսկ հաջորդող սիմվոլները ֆունկցիային փոխանցվող արգումենտներն են, որոնք կարող են լինել ներդրված արտահայտություններ։
Վերը նշված օրինակի համարժեքը C լեզվաընտանիքի շարահյուսությամբ կարող է լինել
func(arg1, arg2, arg3)
արտահայտությունը։
Համարժեք օրինակներ են նաև`(f)
-f()
,(f (g x))
-f(g(x))
արտահայտությունները։
Ի տարբերություն այլ լեզուների, այս նշագրումն օգտագործվում է բառացիորեն բոլոր արտահայտությունների համար։
;; Polish (prefix) notation (+ 2 5) ;; => 7 (- (+ 2 3 4) 2) ;; => 7 (> 7 2) ;; => T (True value) (if (> 7 2) "True" "Nil") ;; => True (let ((p (> 7 2)) (t "True") (f "False")) (if p t f)) ;; => True
Նույն շարահյուսությամբ են կազմվում տվյալները։
(list 1 2 3 4 5) ;; => '(1 2 3 4 5) '(1 2 3 4 5) ;; => '(1 2 3 4 5) (1 2 3 4 5) ;; => Error: 1 is not a function (car '(1 2 3 4 5)) ;; => 1 (cdr '(1 2 3 4 5)) ;; => '(2 3 4 5)
Այսպիսի շարահյուսության բացասական կողմերից հաճախ նշում են փակագծերի ընթեռնելիությունը, հատկապես փակվող փակագծերի հաջորդականության պարագայում։ Սակայն կան նաև ակնհայտ առավելություններ, ինչպիսիք են միջակայքի (scope) նշագրումը և կատարման սեմանտիկ հաջորդականությունը, որոնք արտահայտվում են միակ սահմանազատող նշանի՝ փակագծերի, և համապատասխան ներդրվածության օգնությամբ՝ բացառելով տարընթերցումը։
Շարահյուսական համասեռության շնորհիվ կոդը կարող է գեներացնել մեկ այլ կոդ։ Նման հատկություն ունեցող ֆունկցիաները կոչվում են մակրոսներ (macros plur.)։ Մակրոսների օգնությամբ հայտարարվում են այնպիսի արտահայտություններ, որոնք այլ լեզվական շարահյուսություններում կոչվում են «հատուկ սիմվոլներ» (special symbols) կամ «բանալի֊բառեր» (keywords)։ Դրանցից են, օրինակ, փոփոխականի կամ ֆունկցիայի հայտարարման մակրոս֊ֆունկցիաները։
;; define variable (defvar *x* 42) ;; * - idicates global ;; define function (defun func (a1 a2 a3) (if (= a1 *x*) ("forty two") ;; if true - then (write-to-string (+ a2 a3))))) ;; if false - else (func 42 10 2) ;; => "forty two" (func (-5) 10 2) ;; => "12" (defun print-hello () (write "Hello!")) ;; writes string to stdout, returns Nil (print-hello) ;; => Nil
Նմանօրինակ շարահյուսությունը հատուկ է AST (abstract syntax tree) կառուցվածքին, որը արտահայտությունների իմաստաբանական հաջորդականության արտահայտման ընդունված ձև է գրեթե բոլոր լեզունների համար, այդ թվում՝ բնական։
- Clojure
Lisp լեզվի դիալեկտներից առանձին դիտարկման է արժանի Clojure լեզուն, որը որպես կատարման միջավայր օգտագործում է JVM վիրտուալ մեքենան և ապահովում է Java ծրագրադարանների (libraries) հետ փոխգործելիություն։
Որպես բազային տիպեր այստեղ լռելյայն վերցվում են Java ծրագրավորման լեզվից, որից ուղղակի կերպով կարելի է «ներմուծել» (import) ցանկացած այլ կլաս կամ մոդուլ։
(type 42) ;; => java.lang.Long (type 1.618) ;; => java.lang.Double (type \a) ;; => java.lang.Character (type "Text") ;; => java.lang.String (type true) ;; => java.lang.Boolean
Զանգվածների և հավաքածուների պարագայում մոտեցումն այլ է։ Այստեղ կիրառվում են հատուկ նախագծված ընդլայնված տիպեր, որոնք ավելի կայուն են՝ persistent (փոփոխման դեպքում բնօրինակը մնում է նույնը, ստեղծվում է կրկնօրինակ), և, միաժամանակ, ռեսուրսների օգտագործման տեսանկյունից՝ օպտիմալ (փոփոխման արդյունքում միևնույն ծավալի կրկնօրինակ ստեղծելու փոխարեն կրկօրինակվում է միայն փոփոխվող մասը՝ պահպանելով բնօրինակի հղումը)։
(type '(1 2 3)) ;; => clojure.lang.PersistentList (type [1 2 3]) ;; => clojure.lang.PersistentVector (type #{1 2 3}) ;; => clojure.lang.PersistentHashSet ;; comma-separated notation is allowed (type '(1,2,3))
Lisp լեզվաընտանիքի մեկ այլ առանձնահատկություններից է «բանալի֊բառերի» տրամաբանությունը։ Այստեղ բանալի բառը փոխարինում է այլ լեզուներում կիրառվող տեքստային տվյալի, որն օգտագործվում է ծրագրային մանիպուլյացիաների համատեքստում։
(type :abc) ;; => clojure.lang.Keyword (type {:a 97 :b 98}) ;; => clojure.lang.PersistentArrayMap ;; defining persistent hash-map (def price {:base 180 :sale 165}) (:base price) ;; => 180 (:sale price) ;; => 165
Փոփոխման ենթակա տվյալներ հայտարարելու դեպքում պետք է այն ուղղակիորեն նշել՝ փոխանցելով բուն տվյալները
atom
ֆունկցիային։
;; defining shared synchronous variable 'n' (def n (atom 2)) (type n) ;; => clojure.lang.Atom (type @n) ;; => clojure.lang.Long (swap! n inc) ;; => increment n (println @n) ;; 3
- Functions
Որպես ֆունկցիոնալ լեզու՝ այստեղ կան ոչ միայն անվանական ֆունկցիաների այլ նաև անանուն ֆունկցիաների հայտարարաման ճկուն հնարավորություններ։
;; ordinary function declaration (defn square [n] (* n n)) ;; in-place anonymous function usage ((fn [x] (x + 1)) 6) ;; => 7 ;; shorter notation (% - arg placement) (#(+ % 1) 6) ;; => 7 (#(+ %1 %2) 5 37) ;; => 42
Ֆունկցիաների հայտարարման դեպքում նույնպես կան ընդլայնումներ։
;; in-place overloading (defn greet ([] (println "Hello!")) ([name] (println (format "Hello %s!" name)))) (defn string->integers ;; special symbols in name [^String text] ;; argument type notation (let [lst (atom [])] ;; local value definition (doseq [c text] ;; sequence for each element (swap! lst #(conj % (int c)))) lst)) ;; calling functions (see results below) (greet) (greet "Clojure") (string->integers "abcde")
Hello! Hello Clojure! [97,98,99,100,101]
- Interoperability
Java բազային ծրագրադարաններից կարելի օգտվել առանց վերջինների ուղղակի ներմուծման։
;; uasge of static method floor of Math class (Math/floor 3.9) ;; => 3.0 ;; get system locale from Java module (java.util.Locale/getDefault) ;; => en_US ;; call method of String - "text".toUpperCase() (.toUpperCase "text") ;; => TEXT
- Laziness
Ֆունկցիոնալ լեզուներում ընդունված մեխանիզմ է «ծույլ» կատարումը (lazy evaluation), որը Java միջավայրում կիրառվում է Stream API օգնությամբ (Java 8 տարբերակից սկսած), իսկ Python միջավայրում առկա է հատուկ ֆունկցիաների պարագայում միայն (
range
,map
,zip
, etc.)։
Այսպես, օրինակ, հետևյալ ֆունկցիոնալ կոմպոզիցիայում 97-65535 միջակայքի ամբողջ թվերով հավաքածու չի ձևավորվում։ Փոխարենը՝
range
,filter
ևmap
ֆունկցիաները հետաձգում են իրենց կատարումը և հաջորդաբար գեներացնում են վերադարձվող արժեքները ըստ պահանջի, տվյալ դեպքում՝take
ֆունկցիայի առաջին արգումենտին համապատասխան։
(take 5 (map #(char %) (filter odd? (range 97 (Math/pow 256 2)))))
(\a \c \e \g \i)
«Ծույլ» ֆունկցիաները կազմվում են նաև ռեկուրսիվ կոնստրուկցիաների օգնությամբ, որոնք ավելի մանրամասն դիտարկվում են հաջորդող երկու դասընթացների ընթացքում։
- Functions
3.16 Ցանցային հաղորդակցություն
Խորհուրդ է տրվում վերհիշել առաջին փուլի Ցանց (Network) ներկայացումը։
Ցանցային հաղորդակցությունը ենթադրում է մեկից ավելի բաղադրիչների միջև տեղեկատվության փոխանցում։ Տվյալ վերացականության մեջ ենթադրվում է, նվազագույնը, մեկ սերվեր (server), ինչը ծառայում է որպես տեղեկատվության «մատուցող» կողմ, և մեկ կլիենտ (client), ինչը ենթադրում է տեղեկատվության որոշակի հարցում և համարվում է տեղեկատվության սպառող կողմ։ Մեկից ավելի սերվերների պարագայում դրանք կարող են ծառայել նաև որպես կլիենտ և հարցում կատարել մեկ այլ սերվերի՝ գտնվելով «միջանկյալ» դերում։
Հարկ է նշել մեկ անգամ ևս, որ ցանցային հաղորդակցության վերացականությունը կարող է ծավալվել մեկ սարքավորման լոկալ շրջանակներում ծրագրային տարբեր բաղադրիչների միջև։
- Server
Տվյալ տերմինաբանությունը չունի որոշակիություն, և առանց հստակեցման դժվար է պատկերացնել քննարկման առարկան. կան պատկերացումներ ինչպես սարքավորման, այնպես էլ ծրագրային ապահովման համատեքստում։ Մինչդեռ սերվեր սարքավորումը ոչ այլ ինչ է, քան հատկացված (հիմնականում՝ հատուկ պարամետրերով) համակարգիչ, որում աշխատում է որոշակի տեղեկատվություն «մատուցող» ծրագրային հավելված։
Այսպես, սարքավորումը, որի հիմնական ֆունկցիոնալը առանձին ֆայլերի տրամադրման սերվերն է, նույնպես դիտարկվում է որպես ֆայլերի սերվեր։ Երկու դեպքում էլ գործ ունենք File server հասկացողության հետ, մի դեպքում՝ որպես հավելված (software), մյուս դեպքում՝ որպես սարքավորում (hardware)։ Միևնույն սարքավորման սահմաններում տարբեր սերվերային հավելվածների առկայության պարագայում՝ սարքավորման նշանակությունը ընդհանրացվում է։ Որոշ դեպքերում, գործող սերվերային հավելվածի պարագայում, սարքավորումը դիտարկվում է առաջնային ֆունկցիոնալի համատեքստում, ինչպես օրինակ կենցաղային ուղորդիչների (router) դեպքում, որոնք գրեթե առանց բացառության ունեն DHCP սերվեր հավելված։ Կորպորատիվ և ավելի մեծ մասշտաբներում սարքավորումները խմբավորվում են որպես մեկ ընդհանուր սերվեր՝ սերվերային սարքավորումների բլոկ:
DHCP սերվեր֊հավելվածի նպատակն է լոկալ ցանցին միացած սարքավորմանը, ի պատասխան համապատասխան հարցման, տրամադրել դինամիկ հասցե և գրանցել այն հասցեների սեփական աղյուսակում, եթե արդեն գրանցված չէ։ Օրինակ՝ ամեն անգամ սարքավորումը Wifi ցանցին կապակցելու պրոցեսում։
Սերվերների տարբերակումը կատարվում է ըստ տեղեկատվության հարցման և տրամադրման օգտագործվող «համաձայնագրերի» (պրոտոկոլ)՝ HTTP Server, FTP Server, DHCP Server, POP Server, SMTP Server․․․ կամ ըստ նպատակային նշանակության՝ Web Server, File Server, Media Server, Proxy Server․․․ Վերջիններն իրենցից ներկայացնում են հաճախ մեկից ավելի սերվեր֊հավելվածների կոմպոզիցիա։
- Client-Server
Կլիենտ֊սերվեր փոխհաղորդակցության ամենատարածված տարբերակն է միջին վիճակագրական ինտերնետ֊օգտատիրոջ և որևէ վեբկայքի փոխհամագործակցությունը, որը հիմնականում տեղի է ունենում HTTP պրոտոկոլի օգնությամբ։ Սերվերային մասն այս դեպքում ընդհանրացվում է որպես Web Server:
- HTTP (HyperText Transfer Protocol)
HTTP պրոտոկոլը որպես տրանսպորտային պրոտոկոլ է օգտագործում TCP պրոտոկոլը։ Ըստ այս պրոտոկոլի, ինչպես և հաճախ այլ պրոտոկոլների պարագայում, փոխանցվող տեղեկատվության բայթերի հաջորդականությունն ունի «գլխամաս» (header), որի մաս է կազմում հարցման (request) մեթոդը և վերադարձի (response) կոդը, և բուն տեղեկատվության «օգտակար բեռը» (payload)։
HTTP պրոտոկոլի միջոցով փոխհաղորդակցության ընդունված մոդելներից է REST (Representational state transfer) մոդելը, որը ունի հստակ սահմանափակումներ և պայմաններ։ Այս մոդելին համապատասխանող վեբ֊«ծառայությունները» (web services) կոչվում են RESTful։ HTTP հարցումներն, այսպիսով, հաճախ անվանում են նաև REST հարցումներ։ HTTP պրոտոկոլը համարվում է stateless, քանի որ կոնկրետ կապի կոնտեքստում «վիճակ» (state) չի պահպանում։ HTTP 1.1 տարբերակից սկսած հաստատվող կապը կարելի է նշել «պահպանվող» (Connection: keep-alive)` TCP պրոտոկոլի մակարդակում գործող կապը պահպանելու և վերաօգտագործելու նպատակով։
Այսօր վեբ ռեսուրսներից օգտվելու համար ավելի հաճախ օգտագործվում է HTTPS (HyperText Transfer Protocol Secure) պրոտոկոլը, որը HTTP պրոտոկոլի ընդլայնված տարբերակն է և օգտագործում է TLS (Transport Layer Security) կամ ավելի հին SSL (Secure Socket Layer) պրոտոկոլները՝ տեղեկատվության գաղտնագրման (encryption) և գաղտնազերծման (decryption) համար։
HTTP 1.0 պրոտոկոլն իսկզբանե ունեցել է 3 մեթոդ՝
GET
,HEAD
,POST
, որոնք 1.1 տարբերակում լրացվել են ևս 6 մեթոդով՝PUT
,DELETE
,CONNECT
,OPTIONS
,TRACE
,PATCH
:
HTTP հարցումների գերակշռող մեծամասնությունն այսօր կատարվում է վեբ֊բրոուզերի (Chrome, Firefox, և այլ) օգնությամբ, սակայն հարցումներ կարելի է կատարել նաև ժամանակակից գրեթե բոլոր ծրագրավորման լեզուների օգնությամբ, որոնք ունեն ՕՀ ռեսուրսներից օգտվելու հնարավորություն։ Հարցումը կատարվում է ըստ հասցեի և մեթոդի։
Հետևյալ հրամանը
curl
հավելվածի օգնությամբ կատարում էGET
հարցումհttps://docs.ingenium.am/counter.html
հասցեով առանց հավելյալ պարամետրերի (-i
արգումենտը վերադարձը արտաբերում է ամբողջությամբ՝ ներառելով «գլխամասը»)։
curl -i https://docs.ingenium.am/counter.html
HTTP/2 200 content-type: text/html content-length: 645 last-modified: Sun, 26 Jul 2020 19:55:54 GMT accept-ranges: bytes server: AmazonS3 date: Wed, 09 Dec 2020 09:32:07 GMT etag: "3b45c75f004de6ad2c5f1d41a219bde0" x-cache: RefreshHit from cloudfront via: 1.1 a492e3d7e1e07970b5b6e383c833d8a0.cloudfront.net (CloudFront) x-amz-cf-pop: SOF50-C1 x-amz-cf-id: tc616iLt4wU-dycGZzHCR2CH5LlT8RtmNMrDrUKXUqmRmjACtgPYoQ== <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title></title> <meta name="author" content="Levon Melikyan" /> <link rel="stylesheet" href="./counter/style.css" type="text/css" media="screen" /> <script type="text/javascript" src="./counter/counter.js"></script> </head> <body> </body> </html>
Հարցման վերադարձը (response of the request), որը պատկերված է վերևում, բաղկացած է երկու հատվածից։ Վերին հատվածը գլխամասն է (header), որով նշում են ստորին հատվածի` բուն տեղեկատվության (payload) չափորոշիչները և այլ մետատվյալներ։ Նույն հարցումը բրոուզերի օգնությամբ կատարելիս, այսինքն՝ համապատասխան դաշտում հասցեն մուտք անելով, վերը պատկերված տեղեկատվությունը հասանելի է դառնում բրոուզերին, որը, վերծանելով մետատվյալները և բուն տեղեկատվությունը, փորձում է արտաբերել այն համաձայն տեղեկատվության ձևաչափի՝ HTML, PDF, JPG, և այլ։
Հարցման պատասխանի մետատվյալների մեջ առաջնային դեր ունի վերադարձի կոդը - HTTP status code։ Հաճախ հանդիպող կոդերն են՝
200 OK 2xx - Success 304 Not Modified 3xx - Redirection 400 Bad Request 4xx - Client Error 403 Forbidden 404 Not Found 500 Internal Server Error 5xx - Server Error 502 Bad Gateway 503 Service Unavailable Միջին վիճակագրական ինտերնետ֊օգտատիրոջը այս ցուցակից ծանոթ է 404 կոդը, որը հաճախ արտաբերվում է բրոուզում, երբ հարցվող նյութը սերվերում չի գտնվում։
HTTP հարցումներ կատարելու համար կարելի է օգտագործել հատուկ հավելվածներ, ինչպիսիք են, օրինակ, Telnet տեքստային տերմինալի հավելվածը, կամ այլ գրաֆիկական/վեբ միջերեսով հավելվածներ (RESTED, POSTMAN, https://apitester.com/)։
- Static server (HTTP)
Վեբկայքերի սկզբնական շրջանում վեբ֊սերվերները տրամադրում էին սեփական պահոցներում տեղադրված ֆայլերը՝ հասցեների այն տրամաբանությամբ, որով կազմակերպված էր պահոցի ներքին դասավորվածությունը։
Ցուցադրական ստատիկ վեբ֊սերվեր հեշտությամբ կարելի է գործարկել սեփական համակարգչում օգտագործելով Python ծրագրավորման միջավայրի համապատասխան մոդուլը։ Ստեղծեք
./web-static
նոր հասցե (directory) հետևյալ պարունակությամբ՝
. ├── img │ └── example.jpg └── index.html
որտեղ
example.jpg
ֆայլը կարող եք ընտրել ըստ ցանկության, իսկindex.html
ֆայլի բովանդակությունը հետևյալն է՝
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Test HTML</title> </head> <body> <h2>Test Title</h2> <p>Test text paragraph.</p> <img src="img/example.jpg"/> </body> </html>
Նոր ստեղծված
./web-static
հասցեով Python ինտերպրետատորի օգնությամբ գործարկեքhttp.server
մոդուլը։
python -m http.server
Տերմինալում կհայտնվեն հատկացված պորտի (port) հաջորդող հարցումների մասին տեղեկատվություն։ Տվյալ դեպքում նշվում է
0.0.0.0
ներքին loopback IP հասցեն։ Սակայն սերվերը հասանելի է նաև127.0.0.1
ևlocalhost
ներքին հասցեներով, որոնք ընդունված են որպես ներքին IP հասցեավորում։
Այսպիսով, օրինակ,
8000
պորտը նշվելուց հետո, բրոուզերի օգնությամբ սերվերին կարելի է դիմելlocalhost:8000
հասցեով։ Առանց կոնկրետ ֆայլի հասցեն նշելու՝ լռելյայն հղում է արվումindex.html
ֆայլի համար։ Պահանջվող տեղեկատվությունը ստանալուց հետո (տվյալ օրինակում՝index.html
) բրոուզերը վերծանում է բովանդակությունը, և, ըստ պահանջի, հավելյալ հարցումներ է կատարում նշված հղումների օգնությամբ ներդրված ֆայլերը ստանալու (ներբեռնելու) համար։ Այս օրինակում կա մեկ հարաբերական հղումimg/example.jpg
, որի ամբողջական հասցեն ստացվում է կրող ֆայլի (index.html) նկատմամբ՝localhost:8000/img/example.jpg
ամբողջական տեսքով։
curl --head http://localhost:8000/img/example.jpg
HTTP/1.0 200 OK Server: SimpleHTTP/0.6 Python/3.9.0 Date: Wed, 09 Dec 2020 10:52:26 GMT Content-type: image/jpeg Content-Length: 11710 Last-Modified: Wed, 09 Dec 2020 10:18:10 GMT
Վերը նշված հրամանով
curl
հավելվածը--head
արգումենտի օգնությամբ արտաբերում է միայն գլխամասը, քանի որ բովանդակությունը տեքստային տերմինալում արտաբերման ենթակա չէ։
Հարկավոր է ուշադրություն դարձնել, թե որ պորտին են կցված սերվերի հարցումները, քանի, որ տվյալ օրինակում մոդուլ֊հավելվածը որոշակի տրամաբանությամբ է ընտրում այն։ Ցանկության դեպքում հրամանը կարելի է հավելել՝ նշելով կոնկրետ պորտ, օրինակ՝
python -m http.server 8442
, եթե ՕՀ կողմից այն չմերժվի արդեն հատկացված լինելու պատճառով։
- HTTP (HyperText Transfer Protocol)
3.17 Web ծրագրավորման բաղադրիչներ
Ի տարբերություն ստատիկ վեբ-կայքերի, որոնք գործում են ստատիկ տվյալներ տրամադրող սերվերի հիմքում, ժամանակակից վեբ-կայքերի գերակշռող մեծամասնությունը ենթադրում են անհատական սեսիա (session) և դինամիկ գեներացվող էջեր՝ ըստ համապատասխան հարցման և օգտատիրոջ։
Նման ծառայությունների նույնիսկ նվազագույն պահանջները, օրինակ՝ օգտատիրոջ սեսիա պահպանելը, HTTP սերվերի պատասխանատվությունից դուրս են (քանի որ, ինչպես նախորդ դասընթացի ընթացքում է նշվել, HTTP պրոտոկոլը չի պահպանում կապի մասին որևէ տեղեկատվություն և համարվում է stateless)։ Այդ պատճառով նախորդող հարցումների համատեքստում օգտատիրոջը նույնականացնելու և վերջինին հատուկ տեղեկատվություն գեներացնելու ֆունկցիան փոխանցվում է HTTP սերվերի հետ միևնույն օպերացիոն համակարգում կամ հեռավար գործող համապատասխան հավելվածին, որն անվանում են վեբ֊հավելված՝ Web Application։
Եթե նախկինում այդպիսի հավելվածները, օրինակ` CGIs (Common Gateway Interface scripts), ունեին նվազագույն ֆունկցիոնալ, այն է՝ պատասխան տեղեկատվության մեջ «ներարկել» ընթացիկ հարցման մասին տվյալներ, և հենց այդ պատճառով երկար ժամանակ կոչվում էին «սկրիպտ», ապա ժամանակակից վեբ֊հավելվածները ավտոմատացման օժանդակ գործիքներով ամբողջական ենթակառուցվածքներ են և ծախսում են հաշվարկային լուրջ ռեսուրսներ։ «Մնայուն» (persistent) տվյալները՝ օգտատերերի հաշիվներ, լոգեր, և այլ, միաժամանակ ենթակա են պահպանման տվյալների բազայում, որն առանձին սերվերային հավելված (միգուցե նաև սարքավորում) է ենթադրում։ Տվյալների բազայի կառավարման համակարգի հետ համագործակցության ծրագրային մասը, որպես կանոն, նույնպես վեբ֊հավելվածի մաս է կազմում։
Վեբ֊հավելվածի ծավալին ուղիղ համեմատական կարիք է առաջանում ծրագրային առումով «սպասարկել» նաև պոտենցյալ կլիենտ֊հավելվածը, որը միտված է օգնելու հավելյալ ֆունկցիոնալով և ենթակա է գործարկման կլիենտի կողմում (օգտվողի սարքավորմամբ)՝ client-side։ Այս հավելվածը նույնպես մաս է կազմում մեկ ընդհանուր վեբ֊հավելվածի, սակայն ֆունկցիոնալ տեսանկյունից առանձնացվում է որպես Front-end (դիմային պլանում գործող), ի հակադրություն սերվերային մասի, որը կոչվում է Back-end (ետին պլանում գործող)։
Վեբ֊հավելվածը կարող է չընդգրկել կլիենտին հատուկ հավելված (Front-end) և մատակարարել բացառապես հարցմանը համապատասխան սերիալիզացված տվյալներ (XML, JSON, և այլ․)։ Այդպիսի հավելվածները կոչվում են RESTful Web services և նախագծվում են REST (REpresentational State Transfer) ճարտարապետության սկզբունքներով։ Տրամադրելով սերիալիզացված տվյալներ՝ այս տեսակի վեբ֊հավելվածները առանց համապատասխանեցման կարող են ծառայել ցանկացած հավելվածի։
Կան բազմապիսի անվճար և վճարովի REST API ծառայություններ, որոնք պատրաստ են տրամադրել տարբեր բնույթի, որակի, և քանակի տվյալներ՝ պահպանման, վերլուծության և արտաբերման ենթակա։ Նման վեբ֊ծառայությունները (Google, Amazon, Facebook, Instagram, և այլ) հաճախ տրամադրում են տարբեր ծրագրավորման լեզուների ծրագրադարաններ՝ նախագծվող համակարգերի ավտոմատացման համար։
- Back-end
Ժամանակակից գրեթե բոլոր ծրագրավորման լեզուներում կան ցանցային համակարգերի հետ աշխատանքի համապատասխան ծրագրադարաններ (libraries), որոնք ենթադրում են տարբեր պրոտոկոլների և սերվերների հետ աշխատանքի հավելյալ վերացականություն՝ թաքցնելով ավտոմատացման ավանդական լուծումները։ Այս ենթաոլորտում համեմատաբար ավելի մեծ փորձ ունեն և համեմատաբար ավելի մեծ հեղինակություն են վայելում դինամիկ տիպիզացմամբ ինտերպրետացիոն միջավայրով այնպիսի լեզուներ, ինչպիսիք են, օրինակ, PHP և Python լեզուները, ինչպես նաև՝ ստատիկ տիպիզացմամբ բիզնես֊սպեցիֆիկացիաներին (օր․՝ Enterprise) համապատասխանող լեզուներ, ինչպիսիք են Java և C# լեզուները։ Այստեղ մեծ դեր են կատարում ինչպես լեզվական հնարավորությունները, այնպես էլ ժամանակով փորձված ծրագրադարանները (libraries) և «հենքերը» (frameworks)։
- Back-end ծրագրավորման լեզուների շարքում ներկայումս հայտնի է նաև JavaScript (JS) լեզուն, սակայն այս ենթաբաժնում միտումնավոր բաց է թողնված և հիշատակվում է հաջորդ ենթաբաժնում (տես՝ JavaScript)։
- Հիշատակվող ծրագրավորման լեզուները ակտուալ են այս դասընթացի սեղմագրի հրապարակման ժամանակահատվածի համար։
Վեբ֊հավելվալվածի սերվերային մասի առաջնային գործառույթը՝ տարբեր պրոտոկոլներով ներկայացված հարցումներին համապատասխան տվյալների գեներացումն է և, ըստ անհրաժեշտության, այդ հարցումներին պատասխան տրամադրելը։ HTTP պրոտոկոլով տրամադրվող պատասխանները հիմնականում HTML (HyperText Markup Language) տեքստային ֆայլեր են, որոնցում համակարգվում է հարցմանը համապատասխան էջի տեքստային և գրաֆիկական ձևավորումը, ինչպես նաև՝ սահմանվում են օժանդակ «գործիքներ» (տես՝ Front-end)։
- Routing (ՈՒղղորդում)
Այս մեխանիզմը ծառայում է հասցեական հարցումների «ուղղարդմանը»։ Տարբեր «հենքերի» (frameworks) միջավայրում այն սահմանվում է նախապես ընդունված կարգի համաձայն՝ ընդունված ձևաչափով։
Այսպես, օրինակ, Java Servlet API ընդունված ձևաչափն է հասցեական ուղորդումը կարգավորել
web.xml
ֆայլում, որը կոչվում է servlet mapping և գտնվում է վեբ֊հավելվածի հիմնական հասցեի նկատմամբ․/WEB-INF
հասցեով։
Հետևյալ օրինակում/game
և/game/*
(ցանկացած վերջածանցով) հասցեական հարցումները փոխանցվելու (ուղորդվելու) ենserver.servlets.GamaServlet
կլասին։
<!-- Example of a part of servlet mapping --> ... <servlet> <servlet-name>Game</servlet-name> <servlet-class>server.servlets.GameServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Game</servlet-name> <url-pattern>/game</url-pattern> <url-pattern>/game/*</url-pattern> </servlet-mapping> ...
Պատասխանատու ֆունկցիան կամ մեթոդը իր հերթին պետք է կարգավորված լինի համապատասխան հարցումների համար։ Տվյալ դեպքում՝ սերվլետը պետք է ժառանգի
HttpServlet
կլասից և ըստ պահանջի իրականացնի ծնողական կլասի մեթոդները։
// imports... public class GameServlet extends HttpServlet { @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // ... e.g. // if (request.getParameter("gameHex") == null) { // response.sendRedirect("/lobby"); // } } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { // ... } }
Ի հակադրություն վերը նշված եղանակի՝ Spring Boot «հենքում» (framework) հասցեական ուղղորդումը կարգավորվում է անմիջականորեն պատասխանատու կլասերում՝ նվազեցնելով կոդի կրկնօրինակումը և հնարավոր վրիպակների հավանականությունը։ Սակայն, ինչպես գիտենք, ավտոմատացման յուրաքանչյուր փորձ անխուսափելիորեն առաջացնում է վերացականության հավելյալ մակարդակ։ Բերված օրինակում անոտացիաների շնորհիվ կատարվում է հասցեավորման և պարամետրերի դուրսբերման ավտոմատ կարգավորում, սակայն, ինչպես նշվեց, առանց համապատասխան դոկումենտացիայի դժվար է պատկերացնել կազմավորվող տրամաբանությունը։
// imports... @RestController @RequestMapping("/game") class GameController { @GetMapping("/{gameHex}") @ResponseBody public Person getGame(@PathVariable String gameHex) { // ... } @PostMapping @ResponseBody public void startGame(@RequestParam String boardSize) { // ... } }
Վերը նշված և հաջորդող օրինակները չեն ձգտում լինել լեզվական կամ այլ միջավայրի համատեքստում կանոնիկ։ Ավելին՝ նույնիսկ միևնույն «հենքի» (framework) շրջանակներում կարող են կիրառվել նմանատիպ խնդիրների լուծման տարբեր մոտեցումներ։ Նպատակն է ընդգծել միևնույն խնդրի լուծման ձևաչափերի տարբերությունը։
Հետևյալ օրինակը Python լեզվական միջավայրում վեբ֊հավելվածների նախագծման Django «հենքի» (framework) միջոցով հասցեական ուղղորդման եղանակներից է, որտեղ կլասի փոխարեն անմիջականորեն հղում է արվում պատասխանատու ֆունկցիային։
# url.py from django.urls import path from . import views urlpatterns = [ path('game/', views.game), path('game/<str:gamehex>', views.new_game)) ]
# views.py def game(request, response): # ... def new_game(request, response): # ...
Հասցեների մեկից ավելի համընկնման դեպքում, օրինակ՝
/game/*
և/game/custom
, ընդունված է առաջնայնություն տալ «ամենաերկար» հասցեին (the longest matching URL pattern), սակայն չի բացառվում նաև որոշակի միջավայրին հատուկ այլ «համաձայնություն»։
- Web Template System (Վեբ֊շաբլոնավորման համակարգ)
Վեբ֊շաբլոնների մեխանիզմը թույլ է տալիս վերաօգտագործել վեբ֊էջերի (HTML) նախօրոք ձևավորված հատվածներ և, ներարկելով որոշակի տվյալներ, ամեն հարցմանն ի պատասխան գեներացնել համապատասխան էջ։
Այստեղ նույնպես՝ տարբեր «հենքերի» (frameworks) միջավայրում ձևաչափը և շարահյուսությունը սահմանվում է նախապես ընդունված շաբլոնավորման համակարգի համաձայն։ JSP (JavaServer Pages) տեխնոլոգիայի համաձայն, օրինակ, շաբլոնավորումը կատարվում է իրեն հատուկ նշագրման եղանակով՝ վեբ֊էջում համակցելով Java լեզվով ծրագրավորված կոդ, որը կազմվում է (compile) հատուկ ծրագրադարանի շնորհիվ։
Ի հակադրություն JSP տեխնոլոգիայի՝ կան շաբլոնավորման ունիվերսալ համակարգեր, որոնք ներդրված են վեբ֊ծրագրավորման ոլորտում հայտնի գրեթե բոլոր լեզուներում։ Այդպիսին է, օրինակ, Mustache համակարգը։ Շարահյուսությամբ նման համակարգ է Django «հենքի» (framework) շաբլոնավորման համակարգը, որը ներկայացված է հետևյալ օրինակում։
<!-- new_game.html - Django Template System --> {% extends 'game.html' %} {% block title %}{{ title }}{% endblock title %} {% block content %} <h1>{{ title }}</h1> <p>Hello {{ username }}</p> {% endblock content %}
Այստեղ հիմք է վերցվում
game.html
ֆայլը և կատարվում են տեղային (բլոկային) փոփոխություններ՝ «ներարկելով» նշված փոփոխականները։ Փոփոխականների արժեքները փոխանցվում են ուղղորդման (routing) համաձայն՝ հարցմանը պատասխան ձևավորելու համար պատասխանատու ֆունկցիաների կողմից։
# views.py from django.shortcuts import render def new_game(requests): title = get_title() username = get_username() return render(request, 'new_game.html', {'title': title, 'username': username})
- Back-end ծրագրավորման լեզուների շարքում ներկայումս հայտնի է նաև JavaScript (JS) լեզուն, սակայն այս ենթաբաժնում միտումնավոր բաց է թողնված և հիշատակվում է հաջորդ ենթաբաժնում (տես՝ JavaScript)։
- Front-end
Կլիենտի հարցմանն ի պատասխան ուղարկվող տվյալները (ֆայլերը), արդյունքում, կազմում են այն բովանդակությունը, որը սահմանված է հարցման միջոցով։ Բրոուզերի (Firefox, Chrome, etc.) օգնությամբ կատարվող հարցումներին ուղարկվող տվյալները, որպես կանոն, օժանդակ տվյալների օգնությամբ կազմում են նաև բովանդակության ձևն ու հավելյալ ֆունկցիոնալ տրամաբանությունը վեբ֊էջի (web page) տեսքով։
- HTML
Այսպես, HTML (HyperText Markup Language) ֆայլը, որը, որպես բրոուզերի առաջնային հարցում, սահմանում է բովանդակության վիզուալ արտաբերման ամբողջ տրամաբանությունը, սահմանում է նաև հավելյալ մեդիա֊էլեմենտների (image, video, audio, etc.) և օժանդակ ֆայլերի (styles, scripts, etc.) հղումները և ներդրման ձևաչափը։
Հետևյալ պարզագույն օրինակում ներդրված հատուկ թեգերի (tags -
body
,p
,img
, etc.) և ատրիբուտների (attributes -id
,class
,src
, etc.) օգնությամբ սահմանվում է վեբ֊էջի բովանդակությունը և, մասնակիորեն, ձևը։ Սակայն այստեղ կա հավելյալ մեդիա֊էլեմենտի հարաբերական հղում՝<img src=...
, որի համար հարկավոր է կատարել հավելյալ հարցում և առանց որի էջի բովանդակությունը թերի է։
Որպես XML (Extensible Markup Language) տվյալների վերացական ձևաչափի ենթատեսակ՝ HTML ձևաչափը, ի տարբերություն, սահմանում է կիրառման ենթակա բոլոր թեգերը (tags) և ատրիբուտները (attributes)։ Որոշակի համաձայնությամբ հնարավոր է կիրառել նաև կամայական ատրիբուտ։
Հատուկ հղումների և մետատվյալների նշման համար օգտագործվում է
head
թեգի տիրույթը, իսկbody
տիրույթում նշվում են վիզուալ արտաբերման ենթակա բովանդակությունը։ Արտաբերման թեգերը նույնականացնելու համար կիրառվում էid
ատրիբուտը, որը բացառության կարգով չպետք է կրկնվի ամբողջ էջի շրջանակում։
<!-- HTML5 example --> <!DOCTYPE html> <html> <head> <title>Example</title> </head> <body> <h1>Heading</h1> <p id="p1" class="text">First paragraph text</p> <p id="p2" class="text">Second paragraph text</p> <a href="https://www.google.com">Link to Google</a> <img src="img/image.jpg"> </body> </html>
- Բրոուզերի կողմից վեբ֊էջի վերծանման արդյունքում բոլոր ուղղակի և անուղղակի արտաքին հղումները ենթակա են հավելյալ հարցման օգնությամբ ներբեռնման։
- Թեգերի միջանկյալ դատարկ տեքստային տարածքները (space, tab, newline) անտեսվում են։ Տեքստային բովանդակության մեկից ավելի հաջորդական բացատները ձևավորում են մեկ բացատ։
- Բրոուզերի կողմից վեբ֊էջի վերծանման արդյունքում բոլոր ուղղակի և անուղղակի արտաքին հղումները ենթակա են հավելյալ հարցման օգնությամբ ներբեռնման։
- CSS
Վեբ֊Էջի բաղադրիչների ձևավորման համար կարելի է համապատասխան թեգին վերագրել
style
ատրիբուտը։ Սակայն, ավտոմատացման և ռելացիոն համակարգերի սկզբունքների համաձայն, հաճախ նպատակահարմար է խուսափել տեղային կիրառումից և դուրս հանել տրամաբանությունը։ Այստեղ օգնում է CSS (Cascading Style Sheets) ձևաչափը, որը կարելի է առանձնացնել հատուկ ֆայլի տեսքով կամ ներառել HTML ֆայլի մեջ՝ ըստ նպատակահարմարության։
Հետևյալ օրինակում առաջին պարագրաֆի տեքստը նշվում է կարմիր, երկրորդ պարագրաֆինը՝ կապույտ, նաև՝ երկու պարագրաֆների տեքստերը նշվում են կուրսիվ (italic)։ Գույները նշվում են համաձայն ընդունված անվանական արժեքների (HTML Color Names), սակայն կարելի է օգտագործել նաև RGB 8-bit միջակայքի (0-255) 16-ական (hexadecimal) նշագրման արժեքներ։ Տվյալ օրինակում արժեքները կլինեն, համապատասխանաբար,
#ff0000
և#0000ff
(ընդունելի է նաև կրկնվող բոլոր զույգերի կրճատ նշագրումը՝#f00
և#00f
)։
<!-- INLINE STYLES -->> <body> ... <p id="p1" class="text" style="color: red; font-style: italic;">First paragraph text</p> <p id="p2" class="text" style="color: blue; font-style: italic;">Second paragraph text</p> ... </body>
Հաջորդ օրինակում կիրառվում է առանձին CSS ֆայլ, որտեղ հատուկ նշագրմամբ հղում է արվում
id
ևclass
ատրիբուտներին։ Հաշվի առնելով այն, որ էջում առկա բոլոր պարագրաֆներն ունենtext
կլասի ատրիբուտ՝.text { ... }
սահմանումը կարելի է փոխարինել բոլոր պարագրաֆներն ընդգրկողp { ... }
թեգի սահմանմամբ։
/* styles.css - EXTERNAL CSS */ .text { font-style: italic; } #p1 { color: red; } #p2 { color: blue; }
Ձևավորման առանձին CSS ֆայլը HTML ֆայլում ներառելու համար գլխամասի
head
թեգի տիրույթում հարկավոր էlink
թեգի օգնությամբ նշել ֆայլի ձևաչափը և հղումը։
<!-- Link to EXTERNAL CSS --> <html> <head> <title>Example</title> <link rel="stylesheet" href="styles.css"> </head> <body> ... <p id="p1" class="text">First paragraph text</p> <p id="p2" class="text">Second paragraph text</p> ... </body> </html>
Ներդրված CSS սահմանումների դեպքում հարկավոր է ներառել այն
head
թեգի տիրույթում ներդրվածstyle
թեգի տիրույթում։
<!-- INTERNAL CSS --> <html> <head> <title>Example</title> <style> ... <!-- CSS definitions --> ... </style> </head> ... </html>
Ներդրման դեպքում ձևավորման սահմանումները ներբեռնվում են որպես առաջնային HTML ֆայլի մաս։ Այս դեպքում խնայում ենք օժանդակ ֆայլի հավելյալ հարցում, սակայն կորցնում ենք մեկ ընդհանուր ձևավորմանը հիմք ունենալու և տարբեր էջերից մեկ ձևավորման ֆայլի հղում անելու հնարավորությունը։
Տարբեր սարքերի (էկրանների) ֆիզիկական և ռաստերային չափսերի առկայության պարագայում էջի էլեմենտների բացարձակ (
px
,pt
,in
, etc.) միավորներով չափսերի սահմանումը հաճախ կորցնում է որոշակիությունը։ Այդ պատճառով կարիք է առաջանում սահմանել տարբեր հարաբերական CSS միավորներ (CSS Units)։ Այսպես, օրինակ, տոկոսային%
միավորով նշվում է ծնողական էլեմենտի նկատմամբ չափսը, իսկem
ևrem
միավորներով նշվում է, համապատասխանաբար, ծնողական և գլխավոր<html>
թեգերի տեքստային չափսերի նկատմամբ հարաբերական չափսերը (1.2em
= { font-size of parent tag } + 20%)։
CSS սահմանումների շնորհիվ կարելի է ստանալ նաև անիմացիոն դինամիկ էֆեկտներ (CSS Animation)` առանց JavaScript ծրագրավորման, որը ներկայացված է հաջորդ ենթաբաժնում։
- JavaScript (JS)
Այս լեզուն ի սկզբանե ստեղծվել է բրուզերի (Firefox, Chrome, etc.) վիրտուալ մեքենայում (օպերացիոն համակարգից իզոլացված) աշխատելու և վեբ֊էջի էլեմենտների (DOM - Document Object Model) հետ համագործակցելու նպատակով։ Սակայն տեխնոլոգիական զարգացմանը և ժամանակակից պահանջներին զուգահեռ այն մնում է դեռևս միակ ծրագրավորման լեզուն (բացառությամբ WebAssembly լեզվի, որը ենթակա է կատարման մեքենայական հրամանների տեսքով), որն ընդունելի է բրուզերների կողմից։ Համարվում է EcmaScript (ES) սպեցիֆիկացիայի (լեզվի) կրող։
Այսպես, օրինակ, նախորդ ենթաբաժնում ներկայացված CSS ձևավորումը կարելի է կցել որևէ գործողության (event), օրինակ՝ որևէ կոճակի սեղման (
onclick
event)։
<html> <head> ... <script src="script.js"></script> </head> <body> ... <p id="p1">First paragraph text</p> ... <button onclick="makeRed()">Button</button> ... </body> </html>
// script.js function makeRed() { // 'document' is a preloaded constant of DOM let p = document.getElementById('p1'); p.style = "color: red;" }
Ըստ նպատակահարմարության՝ կոդը, CSS սահմանումների նման, կարող է ներդրվել նաև վեբ֊էջի
script
թեգի միջակայքում (բացվող և փակվող թեգերի միջև)։ Այստեղ նույնպես կարող ենք խուսափել հավելյալ ֆայլ առանձնացնելու և հավելյալ հարցում կատարելու անհրաժեշտությունից, եթե այլ էջերի հետ ընդհանրացման կարիք չկա։ Ի տարբերությունstyle
թեգի՝script
թեգը կարող է ներդրվել նաևbody
թեգի միջակայքում, ինչը կարող է թեթևացնել էջի վիզուալիզացիան՝ հատկապես էջի վերջում տեղակայելու պարագայում, երբ անմիջապես կատարվող գործողություն չի պահանջվում։
JavaScript լեզվում ֆունկցիաները առաջին դասի օբյեկտ են։ Այսինքն կարող են փոխանցվել որպես արգումենտ, կցվել փոփոխականի, և այլն։ Վերը նշված օրինակում ֆունկցիան կարելի էր սահմանել որպես փոփոխականի հայտարարման արտահայտություն։ Տարբերությունն այն է, որ ֆունկցիաների հայտարարումները վիրտուալ մեքենայի կողմից բեռնվում են նախապես, իսկ արտահայտությունները՝ ըստ սահմանման հերթականության, այսինքն փոփոխականը որպես ֆունկցիա կարելի է գործարկել միայն հայտարարման տողից հետո։
// makeRed() - calling here will produce ReferenceError let makeRed = function () { // ... }
JavaScript լեզվի համակցմամբ վեբ֊էջը (DOM - Document Object Model) կարելի է ենթարկել ցանկացած փոփոխության՝ էլէմենտների ձևավորումից մինչև էլեմենտների ստեղծում և հեռացում։ Բացի այդ, կարելի է օգտագորցել բրոուզերի կողմից ներկայացվող բոլոր ինտերֆեյսներն ու մեթոդները՝ ցանցային համագործակցության նպատակով։
function getData() { let xhr = new XMLHttpRequest(); // Define response handler on ready state xhr.onreadystatechange = function () { let data = xhr.responseText; document.getElementById('p1').innerHTML = data; }; // Open and send the request xhr.open('GET', '/game', true); // true - asynchronous xhr.send(); }
Այս և այլ առօրյա նպատակների ավտոմատացման համար կան բազմապիսի ծրագրադարան֊փաթեթներ։ Դրանցից ամենահեղինակավորներից է JQuery փաթեթը, որը շարահյուսական հավելյալ գործիքակազմ է կրում։ Բոլոր փաթեթները անհրաժեշտ է ներառել այն վեբ֊էջում, որտեղ ակնկալվում է դրանց օգտագործումը։ JavaScript փաթեթների (ֆայլերի) հայտարարման հերթականությունը կարևոր է կախվածության տեսանկյունից։
<head> ... <!-- Get from JQuery CDN --> <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script> ... <script src="script.js"></script> ... </head>
// script.js $.ajax('/game', { success: function (data, status, xhr) { $('#p1').html(data); } });
Լինելով դինամիկ֊թույլ տիպիզացմամբ լեզու և ունենալով «պատրաստի» կատարման միջավայր, որն առկա է բոլոր անձնական օգտագործման համակարգիչներում, JavaScript լեզուն մեծ հեղինակություն է վայելում ծրագրավորման սկսնակ֊սիրողական մակարդակում։ «Արտադրական» մակարդակում ավելի հաճախ խուսափում են այս լեզվով ուղղակի ծրագրավորումից (հաճախ՝ նաև լեզվական ծանոթ միջավայրից դուրս չգալու նպատակով) և ընտրում են մեկ այլ լեզու՝ փոխադրման սկզբունքով (transpilation)։ Կան նաև հատուկ այդ նպատակով ստեղծված մի շարք լեզուներ, որոնք միտված են բարձրացնելու համեմատաբար մեծ պրոյեկտների արտադրական էֆեկտիվությունը՝ TypeScript, ClojureScript, Dart, Elm, և այլ։ Բացի դրանից, EcmaScript լեզվական նորույթները հաճախ երկար ժամանակ չեն իրականացվում բոլոր բրոուզերների կողմից։ Այդ պատճառով կիրառվում է նաև ES նոր տարբերակից համամատաբար հին տարբերակի փոխադրման պրակտիկա (օրինակ՝ ES7 -> ES5), որը ևս ենթադրում է հավելյալ գործիքակազմ։
JavaScript լեզուն ի սկզբանե նախագծված է կատարման սխալների առավելապես անտեսման սկզբունքով, այսինքն՝ կատարման բացառությունները (runtime exceptions), այդ թվում՝ հաշվարկային ուղղակի սխալները, չպետք է խոչնդոտ հանդիսանան ընդհանուր կատարման հոսքի համար։ Այս մոտեցումն արդարացված էր նրանով, որ բրոուզերի վիրտուալ մեքենայում կատարվող հրահանգներն այն ժամանակ մեծամասամբ վերբերվում էին պատկերման ենթակա էջի վիզուալ մանիպուլյացիաներին, և այդ համատեքստում բրոուզերի անխափան աշխատանքը ավելի կարևոր էր, քան հաշվարկային որևէ սխալանք։
2009թ․ ստեղծվել է Node.js պրոյեկտը, որը դուրս է հանել իզոլացված V8 (Google Chromium Project) վիրտուալ մեքենան և ադապտացրել է օպերացիոն համակարգերի հետ համագործակցությանը։ Ներկայումս այն իրենից ներկայացնում է ամբողջական էկոհամակարգ և ծրագրավորման միջավայր։ Այն դրական հատկությունները, որով ժամանակին աչքի էին ընկնում Node.js «հենքի» (framework) օգնությամբ ստեղծված վեբ֊սերվերները, այժմ հասանելի են նաև մի շարք այլ լեզվական միջավայրերում, սակայն JavaScript - Back-end ծրագրավորումը դեռևս մեծ հեղինակություն է վայելում լեզվական ապոլոգետների շրջանում (հաճախ՝ նույնպես լեզվական ծանոթ միջավայրից դուրս չգալու պատճառով)։
- SPA (Single֊Page Application)
Վերը նշված գործիքակազմը HTML վեբ֊էջերի հիմքում ստեղծում է գրեթե անսահմանափակ հնարավորություններ GUI (Graphical User Interface) մոդելավորման համար։ Այդ իսկ պատճառով, չնայած բրոուզերի կողմից էջի վերծանման և արտաբերման (render) արագագործության խնդիրների, հետզհետե ավելի մեծ հեղինակություն են վայելում վեբ֊հավելվածները։ Միտված լինելով փոխարինել «առանձին» (stand-alone) հավելվածները՝ վեբ֊հավելվածները ձգտում են վերացնել վիզուալ֊էրգոնոմիկ անջրպետը, օրինակ՝ տարբեր էջերի հաջորդական ներբեռնումը մեկ հավելվածի շրջանակում։
Նշված խնդիրները չեզոքացնելու նպատակով հաճախ նպատակահարմար է ստեղծել մեկ էջի սահմաններում գործող հավելված, որը նոր էջ ներբեռնելու փոխարեն ձևափոխում է գործող էջի մոդելը։ Այդպիսի հավելվածները կոչվում են SPA (Single֊Page Application)։ Նման էջերի հիմքում, որպես կանոն, գործում են «հենքեր»՝ Angular, React, Vue.js և այլ, որոնք պատասխանատու են վեբ֊էջերի ամբողջական մոդելավորման, ղեկավարման և դինամիկ ներբեռնման համար։
Օգտվողի տեսանկյունից՝ SPA հավելվածները գրեթե չեն տարբերվում համակարգչում տեղադրված լոկալ֊գործող այլ հավելվածներից։ Առհասարակ, եթե անտեսել քեշի (cache) առկայությունը բրոուզերում (Firefox, Chrome, etc.), ապա կարելի է պնդել, որ կլիենտն ամեն անգամ սերվերից ստանում է իրեն նախատեսված հավելվածը՝ լոկալ կամ հեռավար աշխատանքի նպատակով։
Electron «հենքը» (framework) թույլ է տալիս նմանօրինակ վեբ-հավելվածները Chromium բրոուզերի հետ միասին փաթեթավորել մեկ ամբողջական «շարժական» հավելվածի տեսքով, որը կարելի է օգտագործել որպես լոկալ֊տեղադրված հավելված։ Այս տեխնոլոգիայի միջոցով են տրամադրվում Skype, Slack, Visual Studio Code, Discord և այլ հայտնի հավելվածներ՝ չնայած աշխատանքային կայունության հետ կապված խնդիրների և այն փաստի, որ մեկ֊երկու նման հավելվածներ կարող են զբաղեցնել ամբողջական օպերացիոն համակարգի հիշողություն։
- HTML
3.18 Պրակտիկ
Նպատակն է ստեղծել վեբ֊հավելված, որը կմեկտեղի անցած բոլոր տեխնոլոգիաները՝ լեզու, ալգորիթմներ, տվյալների բազա, ցանց, կլիենտ֊սերվեր փոխհամագործակցություն, և այլ։
Տվյալ օրինակում միտումնավոր կերպով չեն օգտագործվում ավտոմատացման այլ համակարգեր և «հենքեր» (frameworks)` տեխնոլոգիական աբստրակցիաները այս շրջանակում հնարավորինս ցածր մակարդակում պահպանելու և դիտարկելու համար։
Պրոյեկտը իրենից ներկայացնում է երկու հոգու համար նախատեսված սեղանի խաղի վեբ֊հավելված, որտեղ խաղային ամբողջ տրամաբանությունը տեղի է ունենում սերվերային մասում (back-end), իսկ օգտատերերը համագործակցում են սերվերից անուղղակիորեն ներբեռնվող և բրոուզերում աշխատող հավելվածի օգնությամբ (front-end)։
Հավելվածի աշխատանքը պատկերված է հետևյալ սխեմայում` Client-Server Diagram (սխեման վեկտորային է և ենթակա է անկորուստ մասշտաբայնացման, համակարգչով դիտելու դեպքում՝ Ctrl +
, Ctrl -
կամ Ctrl <scroll>
)։
Lուծումները տարբեր հատվածներում տարբեր ձևով են ներկայացված՝ տարբեր մոտեցումներ ընդգրկելու համար։ Օրինակ սերվլետների (Servlet) դեպքում, երբ վիճակից ելնելով վերջինս կարող է հղում անել կոնկրետ URL-ի, օրինակ՝ (response.sendRedirect("/game...")
), կամ հարցմանը ետ ուղարկել տեքստային տվյալ՝ ուղղակի կերպով նշելով բովանդակության տեսակը (Content Type), HTTP պրոտոկոլի համապատասխան ստատուսի կոդը (օրինակ՝ 200 կամ 404) և բուն բովանդակություն։
Հավելվածը լոկալ համակարգչում փորձարկելու և ծրագրային մասի հետ աշխատելու համար հարկավոր է տեղադրել IntelliJ IDEA հավելվածի Ultimate լիցենզիոն տարբերակը, քանի որ սերվերային մասը գրված է Java Servlet կոմպոնենտների օգնությամբ, իսկ անվճար Community տարբերակը JSP (JavaServer Pages) ֆայլերի հետ աշխատելու հնարավորություն չի տալիս։ Լիցենզիոն տարբերակը, բարեբախտաբար, կարելի է օգտագործել 30֊օրյա «փորձնական» ժամկետով։
Հավելվածի աշխատանքային միջավայրի ամբողջական կարգավորման համար հետևեք ստորև ներկայացված ցուցումներին։
- Development Environment Setup
Տեղադրեք անհրաժեշտ ծրագրային բաղադրիչները․
- Տեղադրեք JDK 8 (Java Development Kit) կամ ավելի նոր տարբերակի փաթեթը՝ ըստ ցուցումների։
- Տեղադրեք SQLite տվյալների բազայի կառավարման համակարգը՝ ըստ ցուցումների։
- Տեղադրեք Git հավելվածը՝ ըստ ցուցումների։
- Տեղադրեք Tomcat 8.5 սերվերային հավելվածը՝ ըստ ցուցումների։
- Տեղադրեք IntelliJ IDEA ծրագրավորման ինտեգրված միջավայրի Ultimate տարբերակը՝ թողնելով տեղադրման ընթացիկ կարգավորումները լռելյայն։
Եթե նշված բաղադրիչները հաջողությամբ տեղադրված են՝ անցեք հաջորդ մասին։
- Տեղադրեք JDK 8 (Java Development Kit) կամ ավելի նոր տարբերակի փաթեթը՝ ըստ ցուցումների։
- Application Deployment Setup
- Լոկալ համակարգչում կրկնօրինակեք դասընթացների ծրագրային հավելվածների պահոցը.
- Եթե պահոցը արդեն կրկնօրինակել եք՝ այդ դիրեկտորիայում կատարեք
git pull
հրամանը, որպեսզի սինքրոնիզացնեք պահոցում առկա փոփոխություններն ու ավելացումները, - Եթե պահոցը դեռ չեք կրկնօրինակել՝ նախապես անցեք համապատասխան հասցեով (որտեղ ենթադրվում է կրկնօրինակումը) և տերմինալի օգնությամբ գործարկեք
git clone https://github.com/ingenium-am/cs-s3-2020
հրամանը,
- Եթե պահոցը արդեն կրկնօրինակել եք՝ այդ դիրեկտորիայում կատարեք
- Կարգավորեք IntelliJ IDEA միջավայրը.
- Բացեք (Open) կրկնորինակված պահոցի
3.18/sample-game
դիրեկտորիան, - Եթե IDEA-ն առաջարկում է (ներքևի աջ անկյունում) ներբեռնել անհրաժեշտ ծրագրադարանները, ապա համաձայնվեք՝ սեղմելով Import հղմանը,
- Կարգավորեք պրոյեկտի կառուցվածքը՝ File - Project Structure…,
- Prօject էջում տեղադրված JDK-ներից ընտրեք Project SDK: (1.8 կամ ավելի նոր), իսկ Project language level: լեզվի մակարդակը ընտրեք 8 (Lambdas, type Annotations, etc.),
- Սեղմեք OK,
- Prօject էջում տեղադրված JDK-ներից ընտրեք Project SDK: (1.8 կամ ավելի նոր), իսկ Project language level: լեզվի մակարդակը ընտրեք 8 (Lambdas, type Annotations, etc.),
- IDEA-ի պատուհանի աջ եզրից բացեք Maven պանելը, այնուհետև հավելվածի Lifecycle ենթաբաժինը և գործարկեք package հրամանը (double֊click),
- ՈՒշադրություն դարձրեք, որ, IDEA-ի կարգավորման և «կազմման» (build) ֆայլերից (
/<project>/target
) բացի, պրոյեկտի «ծառում» (ձախ պանել) ստեղծվում են նաև/sqlite/sample_game.db
ևsrc/main/webapp/WEB-INF/db.properties
ֆայլերը, որոնք ծրագրված են ծառայել կարգավորված միջավայրի շրջանակներում (հատուկ են լոկալ համակարգչի միջավայրին) և ենթակա չեն սինքրոնիզացման (տես՝ .gitignore ֆայլ),
- ՈՒշադրություն դարձրեք, որ, IDEA-ի կարգավորման և «կազմման» (build) ֆայլերից (
- Գործիքների պանելից սեղմեք Add Configurations… (կամ Run - Edit Configurations… մենյուից),
- «Պլյուս» [+] նշանի օգնությամբ ավելացրեք Tomcat Server - Local,
- Server էջում կարգավորեք Application Server դաշտը,
- Եթե առաջին անգամ եք կարգավորում՝ սեղմեք Configure… կոճակը։ Այնուհետև «պլյուս» [+] նշանի օգնությամբ ավելացրեք համակարգում առկա Tomcat սերվերային հավելվածներից մեկը՝ Tomcat Home: դաշտում նշելով հավելվածի դիրեկտորիան (
<path>/apache-tomcat-<version>
), - Սերվերը նշելուց հետո պատուհանի ներքևում հայտնվելու է Warning: No artifacts marked for deployment գրությունը։ Սեղմեք դիմացի Fix կոճակը և ընտրեք sample-game:war, որից հետո պետք է բացվի Deployment Էջը։
- Եթե առաջին անգամ եք կարգավորում՝ սեղմեք Configure… կոճակը։ Այնուհետև «պլյուս» [+] նշանի օգնությամբ ավելացրեք համակարգում առկա Tomcat սերվերային հավելվածներից մեկը՝ Tomcat Home: դաշտում նշելով հավելվածի դիրեկտորիան (
- Deployment էջում Application context: դաշտը փոփոխեք որպես
/
, - Սեղմեք OK, կոնֆիգուրացիայի կոճակը գործիքների պանելում կստանա համապատասխան տեսք։
- «Պլյուս» [+] նշանի օգնությամբ ավելացրեք Tomcat Server - Local,
- Բացեք (Open) կրկնորինակված պահոցի
- Գործարկեք կարգավորված հավելվածը.
- Գործիքների պանելում, նոր ստեղծված կոնֆիգուրացիայի անվանման կողքից, գործարկեք Run կամ Debug հրամանները։ Breakpoint (նշումներ, որտեղ ծրագրի աշխատանքը կանգ է առնում) օգտագործելու պարագայում նախընտրելի է երկրորդը։
- Սերվերի աշխատանքը դադարեցնելու համար գործարկեք Stop կոճակը։
Պրոյեկտին սկսեք ծանոթանալ
pom.xml
(Maven - արտաքին ծրագրադարանների և կազմման ավտոմատացում) ևsrc/main/webapp/WEB-INF/web.xml
(Tomcat - Deplyment Descriptor, Servlet Mapping) ֆայլերի օգնությամբ։
IntelliJ IDEA Ultimate տարբերակում առկա է նաև առանձին կառավարման պանել և տվյալների բազաների հետ աշխատանքի հավելյալ գործիքներ (աջ եզրում)։
Պրոյեկտի
dbservices.dao
Java փաթեթում առկա են SQL շարահյուսությամբ արտահայտություններ, որոնք մկնիկի սլաքի տակ նշվում են «չկարգավորված»՝ SQL Dialect is not configured… այս դեպքում պետք է նույն գրության միջոցով ընտրել Change dialect to… և Generic SQL դաշտը փոխել SQLite:
Շարահյուսությունը կարգավորելուց հետո IDEA-ն փորձելու է կապ հաստատել տվյալների բազայի հետ և ընդգծելու է SQL արտահայտությունը.
Կարող եք օգտվել տվյալների բազաների կառավարման գործիքներից
- Նշեք արտահայտությունը սկզբնամասում և հուշումների «կարմիր լամպի» օգնությամբ գործարկեք Configure data source հրամանը,
- Այնուհետև՝ Database - [+] - Data Source - SQLite,
- Կարգավորման պատուհանի File դաշտում նշեք տվյալների բազայի ֆայլը
<project>/sqlite/sample-game.db
և սեղմեք Test Connection կոճակը, - Եթե առաջարկվում է ներբեռնել անհրաժեշտ մոդուլներ՝ համաձայնվեք,
- Եթե տեստի արդյունքը դրական է՝ սեղմեք OK
Կարող եք օգտվել տվյալների բազաների կառավարման գործիքներից համապատասխան պանելի օգնությամբ։
Պրոյեկտում փոփոխություններ կատարելուց և սերվերային համակարգը գործարկելուց հետո բրուզերում (client - Firefox, Chrome, etc.) հաճախ օգտագործվում է ստատիկ ֆայլերի (front-end - *.html, *.js, *.css, etc.) քեշավորված (cached) հին տարբերակը:
Խնդիրների դեպքում խորհուրդ է տրվում զրոյացնել էջին պատկանող քեշը (cache)
Ctrl-Shift-R
գործողությամբ, կամ բրոուզերի համապատասխան կարգավորումներում, ինչպես նաև՝ ամբողջությամբ մաքրել վերակազմության հետքերը (Maven - Livecycle - clean)։
Սերվերային կարգավորումների արդյունքում Deployment ֊ Application context: պարամետրը, որը պատասխանատու է հավելվածի հասցեի (URL) համար, ավտոմատ կերպով նշում է ծրագրի անվանման վերջածանցով՝
/<app-name>
, ինչը խնդիրներ կարող է առաջացնել։ Ինչպես նշված է կարգավորրումների բաժնում՝ պրոյեկտի շրջանակներում այս պարամետրը պետք է լինի առանց վերջածանցի՝/
արժեքով։
Ընդունված է հասցեների բոլոր կարգավորումները կատարել հարաբերականորեն՝ կցելով Application context պարամետրին (ինչպես, օրինակ, JSP ֆայլերում է կցվում
request.getContextPath()
մեթոդի արդյունքին)։ Սակայն այս պրոյեկտում տվյալ մոտեցումը լիարժեք կերպով կիրառված չէ։
- Գործիքների պանելում, նոր ստեղծված կոնֆիգուրացիայի անվանման կողքից, գործարկեք Run կամ Debug հրամանները։ Breakpoint (նշումներ, որտեղ ծրագրի աշխատանքը կանգ է առնում) օգտագործելու պարագայում նախընտրելի է երկրորդը։
- Լոկալ համակարգչում կրկնօրինակեք դասընթացների ծրագրային հավելվածների պահոցը.
ԸՆԴՀԱՆՈՒՐ ՀՂՈՒՄՆԵՐ
Միջավայրի կարգավորում
Python
Միջավայրի կարգավորման համար, հարկավոր է ներբեռնել ծրագրավորման լեզվի ամբողջական փաթեթը, որը պարունակում է նաև ծրագրավորման ինտեգրված միջավայր` IDE (Integrated Development Environment)։
Windows համակարգերում հավելվածի տեղադրման գրաֆիկական ինտերֆեյսով տարբերակներում հարկավոր է նշել Add Python <version> to PATH
այնուհետև ընտրել Customize installation
տարբերակը, որտեղ հարկավոր է նշել pip
և tcl/tk and IDLE
, եթե նշված չէ։
Ներբեռնելու համար անցեք հետևյալ հղմամբ՝
Python (Downloads)
GNU/Linux համակարգերի դեպքում նախընտրելի է փաթեթը տեղադրել հասանելի package-manager-ի օգնությամբ։ Օրինակ՝ apt
հրամանով կամ Ubuntu Software Center ծրագրի օգնությամբ (Debian/Ubuntu based), yum
(Red Hat based) և pacman
(Arch based) հրամաններով, և այլ։
- IDLE - Integrated Development and Learning Environment
- Windows
- Ծրագրերի ցանկում փնտրեք Python խումբը, և այդ ենթախմբում՝ IDLE ։
- GNU/Linux
- Հարկավոր է ստեղծել ծրագրային «պիտակ» (shortcut)
idle
հրամանի համար։
Համակարգում պետք է տեղադրված լինիtk
ծրագրային փաթեթը։
- Տերմինալի միջոցով
python
հրամանը գործարկելուց կարող է ենթադրվել Python 2 ։ Որոշ օպերացիոն համակարգերում 3-րդ սերնդի համար հարկավոր է գործարկելpython3
հրամանը։ - Տարբերակը տեսնելու համար հարկավոր է գործարկել
python --version
հրամանաը։
- Jupyter Notebook (formerly known as the IPython Notebook)
- PyCharm
Java
Միջավայրի կարգավորման համար հարկավոր է ներբեռնել Java լեզվի ծրագրավորման փաթեթը՝ JDK (Java Development Kit)։
- Պաշտոնական կայքի գլխավոր էջերում ներբռնման (Java Download) հղում է արվում հիմնականում JRE (Java Runtime Environment) փաթեթին՝ առանց դրա մասին տեղեկացնելու, ինչը ենթադրում է արդեն առկա ծրագրի կատարման համար անհրաժեշտ հավելվածների նվածագույն տարբերակ` ներառյալ JVM (Java Virtual Machine)։ Տվյալ տարբերակը չի կարող ծառայել որպես ծրագրավորման միջավայր։
Խորհուրդ է տրվում ներբեռնել և օգտագործել «բաց֊աղբյուրով» (open-source) և GPL լիցենզավորմամբ OpenJDK տարբերակը։
- Windows
- Խորհուրդ է տրվում ներբեռնել AdoptOpenJDK փաթեթը, որը ենթադրում է ավտոմատ տեղադրում և կարգավորում։
- Ներբեռնման էջում առաջարկվում է ընտրել տարբերակը և JVM վիրտուալ մեքենան։ Խորհուրդ է տրվում ընտրել HotSpot վիրտուալ մեքենա։ Տարբերակը՝ ըստ հարմարության։
- Խորհուրդ է տրվում ներբեռնել AdoptOpenJDK փաթեթը, որը ենթադրում է ավտոմատ տեղադրում և կարգավորում։
- Linux/MacOS
- Խորհուրդ է տրվում օգտվել փաթեթների տեղադրման առկա հավելվածներիծ (e.g. Apt for Debian, Homebrew for MacOs):
- Խորհուրդ է տրվում օգտվել փաթեթների տեղադրման առկա հավելվածներիծ (e.g. Apt for Debian, Homebrew for MacOs):
OpenJDK փաթեթը կարող եք տեղադրել նաև հետևալ կերպ․
- Ընտրեք և ներբեռնեք գործող տարբերակներից որևէ մեկը հետևյալ հղմամբ՝ Download OpenJDK։
- Zip արխիվային ֆայլը ներբեռնելուց հետո ապաարխիվացրեք համակարգի ծրագրային որևէ հասցեով (օր․ Windows:
C:\Users\Public\
, GNU/Linux, macOS:/opt/
)։ Ապաարխիվացնելուց հետո ընտրված հասցեում կստեղծվիjdk-<version>
նոր դիրեկտորիա (<version>
= տարբերակի թողարկման համարը)։
Windows օպերացիոն համակարգում օգտատիրոջ կողմից գործարկվող հավելվածներին թույլ չի տրվում ուղղակիորեն (առանց թույլտվության հաստատման - UAC Prompt) փոփոխություն կատարել «համակարգային» (system) դիրեկտորիաներում (օր․՝ C:\Program Files\
կամ C:\Program Files (x86)\
)։ Այդ պատճառով տարբեր հավելվածներ նշված հասցեով տեղակայվելու դեպքում իրենց ֆունկցիոնալը աբողջությամբ չեն կարողանում կիրառել, ինչը տարբեր սխալանքների պատճառ է դառնում։
- Կատարեք միջավայրի հետևյալ փոփոխություններ (Windows համակարգերում՝ Advanced System Settings - Environment Variables - System variables).
PATH
փոփոխականին ավելացրեք ապաարխիվացման հասցեն՝ ավելացնելովbin
դիրեկտորիան (օրինակ՝C:\Users\Public\Java\jdk-<version>\bin
)։- Ստեղծեք
JAVA_HOME
նոր փոփոխական` ապաարխիվացման հասցեի արժեքով՝ ԱՌԱՆՑbin
դիրեկտորիայի (օրինակ՝C:\Users\Public\Java\jdk-<version>
)։
- Տեղադրեք նախընտրելի խմբագիր կամ IDE (օրինակ` IntelliJ IDEA) և կարգավորեք JDK֊ի հասցեն։
Կարգավորումները փորձարկելու համար կարող եք տերմինալի միջոցով կատարել java -version
հրամանը։
Git
- Windows
- Ներբեռնեք տեղադրման փաթեթը օֆիցյալ էջից։
- Տեղադրման ընթացքում Configuring the line ending conversions էջի կարգավորումը հարկավոր է փոխել՝ Checkout as is, commit as is, ընթացիկ այլ կարգավորումները կարող եք թողնել լռելյայն։ Այս տարբերակում առկա է նաև GitGUI հավելված։
- Փորձարկեք կարգավորումը GitBash տերմինալում
git --version
հրամանը գործարկելով (Command Prompt հավելվածը օգտագործել խորհուրդ չի տրվում)։
- Ներբեռնեք տեղադրման փաթեթը օֆիցյալ էջից։
- Linux/MacOS
- Խորհուրդ է տրվում օգտվել փաթեթների տեղադրման առկա հավելվածներիծ (e.g. Apt for Debian, Homebrew for MacOs):
- Ապաարխիվացրեք և տեղադրեք որևէ հասցեով (օր․
С:\Users\<user>
կամC:\Users\Public
)։ - Փորձարկեք կարգավորումը տերմինալում
git --version
հրամանը գործարկելով։
- Խորհուրդ է տրվում օգտվել փաթեթների տեղադրման առկա հավելվածներիծ (e.g. Apt for Debian, Homebrew for MacOs):
SQLite
- Windows
- Ներբեռնման էջում Precompiled Binaries for Windows եմթաբաժնից ընտրեք sqlite-tools-<version>.zip ֆալյը։
- Ապաարխիվացրեք և տեղադրեք որևէ հասցեով (օր․
С:\Users\<user>
կամC:\Users\Public
)։ - Կատարեք միջավայրի հետևյալ փոփոխություններ (Windows համակարգերում՝ Advanced System Settings - Environment Variables - System variables).
PATH
փոփոխականին ավելացրեք նախորդ կետին համապատասխան ապաարխիվացման հասցեն։
- Ներբեռնման էջում Precompiled Binaries for Windows եմթաբաժնից ընտրեք sqlite-tools-<version>.zip ֆալյը։
- Linux/MacOS
- Խորհուրդ է տրվում օգտվել փաթեթների տեղադրման առկա հավելվածներիծ (e.g. Apt for Debian, Homebrew for MacOs):
- Խորհուրդ է տրվում օգտվել փաթեթների տեղադրման առկա հավելվածներիծ (e.g. Apt for Debian, Homebrew for MacOs):
Կարգավորումը փորձարկելու համար կարող եք տերմինալի միջոցով կատարել sqlite3 --version
հրամանը։
Tomcat Server
- Ներբեռնեք Tomcat հավելվածը՝ անցնելով համապատասխան տարբերակի էջ։ Հղումների Core: ենթաբաժնից ներբեռնեք արխիվային ֆայլը։ Windows ՕՀ դեպքում՝ համակարգի բիթայնության համապատասխան Windows zip տարբերակը (Windows Service Installer ֆայլը պետք ՉԷ ներբերռնել)։
- Ապաարխիվացրեք և տեղադրեք որևէ հասցեով (օր․
С:\Users\<user>
կամC:\Users\Public
)։ - Հավելվածը պատրաստ է օգտագործման համար։
Ինտեգրված ծրագրավորման միջավայրների ցանկ - IDEs
Առցանց (Online) համակարգեր
Name | Languages | Notes |
---|---|---|
AWS Cloud9 IDE | C++, Java, Python, Haskell, Web stack, etc. | Support level may differ |
Repl.it | C/++/#, Java, Python, Web stack, etc. (62) | Language list |
Eclipse Che | C/++/#, Java, Python, Web stack, etc. | Supports LSP (Language Server Protocol) |
Codeanywhere | C/++/#, Java, Python, Web stack, etc. (100+) | Pricing (Free Trial for 7 days) |
Ծրագրային հավելվածներ
Name | Languages | OS | Notes |
---|---|---|---|
Visual Studio | C/++/#, Java, Python, Java (Android), etc. | Windows, MacOS | Platform install support1, language support by plugins |
Visual Studio Code2 | Language-independent | Windows, MacOS, Linux | Language support by plugins |
Xcode | Language-independent | MacOS | Mac-oriented, language support by plugins |
Emacs2 | Language-independent | Windows, MacOS, Linux | Language support by plugins |
Sublime Text2 | Language-independent | Windows, MacOS, Linux | Language support by plugins |
IntelliJ IDEA | Java, JVM Languages, Java Frameworks, Web stack, etc. | Windows, MacOS, Linux | JVM-oriented, language support by plugins |
PyCharm | Python, Python Frameworks, Web stack, etc. | Windows, MacOS, Linux | Python-oriented, language support by plugins |
1. Language platforms could be installed with IDE
2. Source-code editor with IDE capabilities
Հավելվածներ
1-Byte Counter
Արտասովոր հիմքերով (երկուական, տասնվեցական) թվերի ընկալման համար դասընթացների մատյանի շրջանակներում տեղադրված է 1 բայթ «կրողունակությամբ» վիզուալ հաշվիչ։
Գրականություն և այլ հղումներ
Գրքեր
- SICP - Structure and Inerpratation of Computer Programs
ISBN: 978-0262510875 (2nd edition) - Amazon
- P.Seibel - Practical Common Lisp
ISBN: 978-1590592397 - Amazon
- P.Graham - ANSI Common Lisp
ISBN: 978-0133708752 - Amazon
- B.Kernighan, D.Ritchie - C Programming Language
ISBN: 978-0131103627 (2nd edition) - Amazon
- D.Griffiths - Head First C
ISBN: 978-1449399917 - Amazon
- B.Stroustrup - Tour of C++, A
ISBN: 978-0321958310 - Amazon
- P.Deitel, H.Deitel - Java How To Program (Early Objects)
ISBN: 978-0133807806 (10th edition) - Amazon
- K.Sierra, B.Bates - Head First Java
ISBN: 978-0596009205 (2nd edition) - Amazon
- J.Bloch - Effective Java
ISBN: 978-0134685991 (3rd edition) - Amazon
- M.Lutz - Learning Python
ISBN: 978-1449355739 (5th edition) - Amazon
- Z.Shaw - Learn Python 3 the Hard Way
ISBN: 978-0134692883 - Amazon
- M.Lipovaca - Learn You a Haskell for Great Good
ISBN: 978-1593272838 - Amazon
- V.Bragilevsky - Haskell in Depth
ISBN: 978-1617295409 - Amazon
- D․Higginbotham - Clojure for the Brave and True
ISBN: 978-1593275914 - Amazon
ՏԵՐՄԻՆՆԵՐԻ ԲԱՌԱՐԱՆ
A
ALU
Arithmetic Logic Unit - Ենթապրոցեսոր՝ կենտրոնական պրոցեսորի (CPU) հիմնական մասերից, որը կատարում է թվաբանական և տրամաբանական գործողություններ, ինչպիսիք են՝ գումարումը, հանումը, բազմապատկումը, բաժանումը, և այլ։ Տես նաև՝ FPU։
API
(Apllication Programming Interface abbrev., Интерфейс Прикладного Программирования ռուս․) Ծրագրային տարբեր հավելվածների փոխինտեգրման միջոց, որը բնութագրում է երկու ծրագրային հավելվածների միջև փոխհաղորդակցման ձևաչափերն ու այլ համաձայնությունները։
B
Bare-metal
Դատարկ, «մերկ» սարքավորում՝ առանց վիրտուալիզացիայի և օպերացիոն համակարգերի։ ~ server ամբողջական սերվերային միավոր՝ որպես մեկ ֆիզիկական սարքավորում (ի տարբերություն վիրտուալիզացված համակարգերի, որտեղ մեկ ֆիզիկական միավորը կարող է ընդգրկել մեկից ավելի վիրտուալ համակարգեր)։
By Default
Տես՝ Default
Bottleneck
Ֆենոմեն, ըստ որի՝ ամբողջ համակարգի արտադրողականությունը և կարողությունները խիստ սահմանափակվում են մեկ կոմպոնենտի կարողությունների սահմաններում։
C
Case sensitivity
Բնորոշում է մեծատառ և փոքրատառ տառերի տարբեր (case-sensitive) և նույնական (case-insensitive) լինելը։ Օրինակ՝ տարբեր ֆայլային համակարգերում Test.zip
և test.zip
ֆայլերի անվանումները կարող են դիտարկվել որպես տարբեր, կամ՝ որպես նույնական և, արդյունքում, միևնույն հասցեով տեղակայվելու պարագայում՝ հակադրվել միմյանց։
Circuit
Սխեմա: Electronic ~ էլեկտրոնային սխեմա, որը բաղկացած է առանձին էլէկտոնային մասերից, ինչպիսիք են՝ տրանզիստոր, կոնդենսատոր, դիոդ, դիմադրություն, և այլ։
CISC
Complex Instruction Set Computer - Կոմպլեքս հրամանների ցանկով համակարգիչ։ Ավելի հաճախ հանդիպում է x86 ընտանիքի պորոցեսորների տեսքով։ Տես նաև՝ RISC։
CLI
(Command-Line Interface abbrev.) Console, Terminal Syn. - Համակարգչի հետ համագործակցության տեքստային ինտերֆեյս, որը թույլ է տալիս հրամանների տողի միջոցով ներմուծել հրամաններ և ստանալ վերջինների արտաբերման արդյունքը։ Առավել հաճախ հանդիպում է որպես օպերացիոն համակարգերի առաջնային ինտերֆեյս, օրինակ՝ sh, bash (UNIX-like) և cmd (Windows):
D
Default
(По умолчанию ռուս․) Լռելյայն։ Պարամետրերի նախորոշված նշանակություններ, որոնք ծրագրային համակարգն օգտագործում է իր աշխատանքում, մինչև օգտվողի կողմից փոփոխության ենթարկելը։
Dependency
(Зависимость ռուս․) Ծրագրային հավելվածի կամ համակարգի կախվածություն մեկ այլ ծրագրային հավելվածից կամ փաթեթից։ Տես՝ Dependency hell։
DHCP
(Dynamic Host Configuration Protocol abbrev.) Ցանցային կառավարման «համաձայնագիր» (protocol), որտեղ DHCP սերվերը, օրինակ՝ ցանցային ուղորդիչներում (Router) գործող, ցանցին միացող բոլոր սարքվորումներին դինամիկ կերպով տրամադրում է IP հասցեներ և ցանցային կարգավորման այլ պարամետրեր։
DLL
(Dynamic-link library abbrev.) Microsoft Windows օպերացիոն համակարգերում ընդհանուր օգտագործման «դինամիկ֊կցմամբ» ծրագրադարաններ, որոնք ունեն ֆայլային անվանման .dll վերջածանց և կրում են .exe (executable) ֆայլերի ձևաչափը։ Գոյություն ունեն նույն վերջածանցով տվյալների հավաքածուներ, որոնք օգտագործվում են որպես ծրագրային տարբեր ռեսուրսներ։
DRY
(Don't Repeat Yourself abbrev.) «Մի՛ կրկնվիր»։ Ծրագրավորման սկզբունք, որն ուղղված է ծրագրում կոդի կրկնությունների կրճատմանը՝ նոր աբստրակցիաների կիրառման շնորհիվ։
E
EOF
(end-of-file abbrev.) Վիճակ օպերացիոն համակարգում, երբ տվյալների աղբյուրից տվայլներ այլևս չեն ներմուծվում։ Ստանդարտ մուտք֊ելքի (input-output) ֆունկցիաները վերադարձնում են արժեք, որը հավասար է "EOF" սիմվոլիկ հաստատունի` նշելու համար ֆայլի վերջը։ Իրական արժեքը բացասական ամբող թիվ է՝ կախված համակարգից (հիմնականում՝ -1), ինչը բացառում է տառանշային կոդի հետ համընկնումը։ Ստեղնաշարի օգնությամբ "EOF" մուտք անելու համար կարելի է օգտագործել կանխանծված կոմբինացիաներ՝ Ctrl-D
(UNIX-like) և Ctrl-Z
(Windows):
EOL
(end of line abbrev.) Newline, line ending, line feed, line break - Հատուկ տառանշան կամ դրանց հաջորդականություն տառանշային կոդավորման սպեցիֆիկացիայում (օր․ ASCII), որը նշում է տողի ավարտը և նոր տողի սկիզբը։ Տեքստային խմբագրման հավելվածները ↵ Enter
սեղմելուց ավելացնում են համակարգին հատուկ համապատասխան "EOL"։ Տառանշանային արժեքները կախված համակարգից տարբերվում են, օրինակ՝ \n
(LF - Line Feed) UNIX-like և UNIX-like-like համակարգերի համար, \r\n
(CR+LF - Carriage Return and Line Feed) Windows համակարգերի համար։
F
Float
C լեզուների ընտանիքում ընդունված եզակի ճշգրտության (Single precision) տվյալի տիպ (data type)։ Երկուական ձևաչափում բաղկացած է 32 բիթից (4 բայթ)՝ 24 բիթ մանտիսայով (7 տասնորդական թվանշան)։
Floating-point
(Плавающая точка/запятая ռուս․) Լողացող կետ (կամ ստորակետ` կախված տասնորդական թվի բաժանարարի ընդունված նշանի)։ Իրական թվերի (R) ներկայացման ձև, որտեղ թիվը բաղկացած է մանտիսայից և էքսպոնենտից (աստիճանի ցուցիչից)։ Օրինակ՝ 1,0 x 106 կամ 1.0e106։ ~ arithmetic լողացող կետով թվերով թվաբանություն, որն ունի հարաբերական ճշգրտություն։ Տեղ ունի այնպիսի համակարգերում, որտեղ հարաբերական ճշգրտությունը փոխհատուցվում է արագ կատարմամբ։
FPU
Floating-Point Unit - Ենթապրոցեսոր՝ կենտրոնական պրոցեսորի (CPU) հիմնական մասերից, որը կատարում է համանման թվաբանական գրոծողություններ, ինչպիսին ALU-ն, սակայն լողացող կետով թվերով։ Տես՝ Floating-point։
G
GNU/Linux
FSF (Free Software Foundation) կողմից կազմված "GNU" գրեթե ամբողջական օպերացիոն համակարգի և "Linux" օպերացիոն համակարգի միջուկի (kernel) համադրություն, որը տարբեր պատրաստի համակարգերի տեսքով (Debian, Ubuntu, RedHat, Arch, etc.) տարածվում է որպես ամբողջական Օպերացիոն Համակարգ։
Գոյություն ունեն նաև "Linux" միջուկով այլ օպերացիոն համակարգեր (առանց՝ "GNU" ծրագրային մասի), օրինակ՝ Alpine Linux կամ Android ՕՀ֊երը։
I
IRQ
Ընդհատման պահանջ (Interrupt request անգլ․)։ Սարքային մակարդակում կենտրոնական պրոցեսորին տրվող ազդանշան (IRQ միացման օգնությամբ), որով ժամանակավորապես դադարեցվում է հիմնական կատարման ընթացքը և անցում է կատարվում նախորոշված հասցեում գտնվող Interrupt handler ծրագրային բաղադրիչի կատարման։
L
Lazy evaluation
«Ծույլ» (lazy անգ․) կատարումները ենթադրում են հավաքածուների կամ ռեկուրսիվ ֆունկցիաների ոչ ամբողջական կատարում՝ ցպահանջ։ Այսպիսով, ենթական ֆունկցիան (ծույլ) կատարման է ենթարկվում այնքան, որքան պահանջում է ծնողական ֆունկցիան, ինչպես գեներատոր ֆունկցիաների դեպքում։ Օրինակ` (pseudocode) take(2, range(1, 10^10))
արտահայտությամբ range
ֆունկցիան չի գեներացնի 1֊ից մինչև 1010 բոլոր թվերի հաջորդականությամբ հավաքածու, քանի որ take
ֆունկցիան առաջին արգումենտով` 2
, նշում է հավաքածույի միայն առաջին 2 էլեմենտները վերադարձնելու պահանջը։
Հակադրվում է «խիստ» Strict evaluation կատարմանը։
M
Memory leak
Ծրագրավորողի և ծրագրի կողմից համակարգչի հիշողություն կառավարման սխալների արդյունքում առաջացած խնդիր, երբ հատկացված որոշակի հիշողության բաժինն այլևս չի օգտագործվում որևէ պրոցեսսի կողմից, սակայն որպես ռեսուրս ազատված չէ հետագա օգտագործման համար։
Օ
OCR
(Optical Charater Recognition abbrev.) Պատկերային տառանշանների փոխակերպումը տեքստային տարբերակի։ Օրինակ՝ սկանավորված կամ լուսանկարահանված ռաստերային ձևաչափով ֆայլերում առկա տեքստային բովանդակության վերծանում և փոխակերպում տեքստային ձևաչափի (txt, rtf, doc/docx, etc.)։
P
Pseudocode
(Псевдокод ռուս․) Ֆորմալ շարահյուսությամբ լեզու (հիմնականում՝ գոյություն ունեցող որևէ ծրագրավորման լեզվի նմանությամբ), որի օգնությամբ բնութագրվում է որոշակի ալգորիթմի կամ ծրագրային հավելվածի ընդհանուր տրամաբանությունը՝ հաճախ բաց թողնելով կատարման համար կենսական նշանակություն ունեցող որոշ բովանդակություն։
R
REPL
(Read-Eval-Print Loop abbrev.) «Կարդալ֊կատարել֊տպել» ցիկլ։ Ծրագրավորման միջավայր, որտեղ որոշակի լեզվական համակարգում ընդունում է օգտվողի կողմից մուտքագրված տվյալները, անմիջապես կատարում է և տպում է կատարման արդյունքը, այնուհետև վերադառնում է մուտքագրման պատրաստ վիճակի՝ պահպանելով կատարման միջավայրի փոփոխվող վիճակը։
RISC
Reduced Instruction Set Computer - Կրճատված հրամանների ցանկով համակարգիչ։ Ավելի հաճախ հանդիպում է ARM պրոցեսորների տեսքով՝ հիմնականում սմարթֆոններում և պլանշետներում։ Տես նաև՝ CISC։
S
SDK
(Software Development Kit abbrev.) Որոշակի ծրագրային միջավայրում ծրագրավորման համար անհրաժեշտ հավելվածների փաթեթ` ծրագրավորման «էկոհամակարգ» (compiler, debugger, etc.), որը տրամադրվում է տվյալ տեխնոլոգիայի «մատակարարի» (distributor) կողմից։
Standalone
~ application ծրագրային «ինքնուրույն» հավելված, որը չունի արտաքին ծրագրային կամ ցանցային կախվածություն։
State
(Состояние ռուս․) Համակարգչային կամ հաշվարկային սարքավորման այնպիսի «վիճակ», որը ժամանակի կտրվածքում հատուկ է որոշակի ծրագրային բաղադրիչներին և տեսականորեն վերարտադրելի է։
- Stateful
- State ունեցող, ~ system սարքավորման, ծրագրային կամ կոմպլեքս համակարգ, որի փոփոխված վիճակը մնայուն է համապատասխան միջավայրում։ Օրինակ՝ կոշտ սկավառակ (HDD) կամ տվյալների բազա (Database):
- Stateless
- State չունեցող. ~ system երբ համակարգը փոփոխության չի ենթարկվում, կամ փոփոխության ենթարկվելը տևում է որոշակի ժամանակ, որից հետո վերականգնվում է նախնական «վիճակը» (State)։ Օրինակ՝ համակարգչի օպերատիվ հիշողություն (RAM) կամ կոնտեյներիզացված (իզոլացված) ծագրային հավելված։
T
TDD
Test Driven Development - Ծրագրավորման պրոցես, որը ենթադրում է նախօրոք կազմվող թեստեր, որից հետո ստեղծվում է թեստերի պահանջները բավարարող հնարավոր մինիմալ կոդը։
U
UI
User Interface - Ծրագրային հավելվածի արտապատկերման այն ամբողջությունը, որի միջոցով կատարվում է օգտվողի հետ հիմնական փոխազդեցությունը, օրինակ՝ այն պատուհանը որի մեջ արտապատկերված կոճակների օգնությամբ որոշակի հրամաններ է գործարկում և պարամետրեր է փոփոխում, կամ՝ հատուկ առանձնացված դաշտերում տեքստ է մուտքագրում կամ գրաֆիկական պատկերներ է գեներացնում։
V
Variable extraction
Փոփոխականի ընդհանրացում այն դեպքերում, երբ փոփոխականը հայտարարվում է միևնույն արժեքով կամ ուղղակիորեն փոխանցվում է միևնույն արժեքի տեսքով մեկից ավելի դեպքերում։ Այդ պարագայում փոփոխականի հայտարարումը մասնավոր հատվածներից «դուրս է հանվում» ընդհանուր միջակայք (Scope)։
VCS
Version control system ֊ (Система управления версиями ռուս․) Ծրագրային «տարբերակների» ղեկավարման համակարգ։
Void
Դատարկ, փուչ։ ~ function ֆունկցիա կամ մեթող, որը ոչինչ չի վերադարձնում իրեն գործարկող ֆունկցիային, մեթոդին կամ արտահայտությանը։
X
x86
Intel կազմակերպության կողմից նախագծված ISA (Instruction Set Architecture), որը հիմնված Intel 8086 պրոցեսորների վրա. «x86» նշումը կապված է Intel կազմակերպության կողմից ստեղծված ապրանքային շարքին, որոնք հաջորդում են 8086 պրոցեսորը և որոնց անվանումն ավարտվում է «86»-ով (80186, 80286, 80386, 80486).
x86-64
(Հայտնի է նաև որպես x64, x86_64, AMD64 և Intel 64) Intel կազմակերպության կողմից ստեղծված x86 «ճարտարապետության» 64-bit տարբերակ, որը ներկայացնում է գործողությունների երկու «վիճակ» (mode)՝ 64-bit և «համատեղելիության» (compatibility).