--- contributors: - ["Louie Dinh", "http://pythonpracticeprojects.com"] - ["Steven Basart", "http://github.com/xksteven"] - ["Andre Polykanine", "https://github.com/Oire"] - ["Zachary Ferguson", "http://github.com/zfergus2"] - ["evuez", "http://github.com/evuez"] - ["Rommel Martinez", "https://ebzzry.io"] - ["Roberto Fernandez Diaz", "https://github.com/robertofd1995"] - ["caminsha", "https://github.com/caminsha"] - ["Stanislav Modrak", "https://stanislav.gq"] - ["John Paul Wohlscheid", "https://gitpi.us"] translators: - ["lucii7vel", "https://github.com/lucii7vel"] filename: learnpython-by.py --- Python быў створаны Гвіда ван Росумам у пачатку 90-х. Цяпер гэта адна з самыя папулярных моў праграмавання. Я закахаўся ў Python за яго сінтаксічную празрыстасць. Гэта літаральна выканальны псеўдакод. ```python # Аднарадковыя каментарыі пачынаюцца знакам рашоткі. """ Шматрадковыя каментарыі можна рабіць выкарыстоўваючы тры ", яны часта выкарыстоўваюцца ў якасці дакументацыі. """ #################################################### ## 1. Прымітыўныя тыпы даных і аператары. #################################################### # Лічбы 3 # => 3 # Відавочныя матэматычныя аперацыі 1 + 1 # => 2 8 - 1 # => 7 10 * 2 # => 20 35 / 5 # => 7.0 # Вынік цэлалікавага дзялення акругляецца ў напрамку мінус бесканечнасці 5 // 3 # => 1 -5 // 3 # => -2 # Працуе таксама на лічбах з плаваючай кропкай. 5.0 // 3.0 # => 1.0 -5.0 // 3.0 # => -2.0 # Вынік дзялення — заўсёды лічба з плаваючай кропкай. 10.0 / 3 # => 3.3333333333333335 # Дзяленне па модулю 7 % 3 # => 1 # У выніку i % j атрымаецца значэнне са знакам j -7 % 3 # => 2 # Узвядзенне ў ступень 2**3 # => 8 # Прыярытэт аперацый праз дужкі 1 + 3 * 2 # => 7 (1 + 3) * 2 # => 8 # Лагічныя значэнні з'яўляюцца прымітывамі # (Звярніце ўвагу на рэгістр) True # => True False # => False # Адмаўленне праз not not True # => False not False # => True # Лагічныя аператары # Звярніце ўвагу, "and" і "or" чуллівыя да рэгістра True and False # => False False or True # => True # True і False на самай справе 1 і 0, толькі з іншымі ключавымі словамі. True + True # => 2 True * 8 # => 8 False - 5 # => -5 # Параўнальныя аператары звяртаюцца да лічбавых значэнняў True і False. 0 == False # => True 2 > True # => True 2 == True # => False -5 != False # => True # None, 0 і пустыя радкі/спісы/слоўнікі/картэжы/мноства адпавядаюць False. # Усе іншыя значэнні адпавядаюць True. bool(0) # => False bool("") # => False bool([]) # => False bool({}) # => False bool(()) # => False bool(set()) # => False bool(4) # => True bool(-6) # => True # Выкарыстоўванне лагічных аператараў на цэлалікавых значэннях ператварае # іх у boolean для вылічэнняў, але вяртае значэнне іх зыходнага тыпу. # Не блытайце з bool(int) і пабітавымі and/or (&, |). bool(0) # => False bool(2) # => True 0 and 2 # => 0 bool(-5) # => True bool(2) # => True -5 or 0 # => -5 # Роўнасць == 1 == 1 # => True 2 == 1 # => False # Няроўнасць != 1 != 1 # => False 2 != 1 # => True # Больш параўнанняў 1 < 10 # => True 1 > 10 # => False 2 <= 2 # => True 2 >= 2 # => True # Праверка значэння на ўваход у дыяпазон 1 < 2 and 2 < 3 # => True 2 < 3 and 3 < 2 # => False # Звязванне выглядае прыгажэй 1 < 2 < 3 # => True 2 < 3 < 2 # => False # (is супраць ==) is правярае, ці спасылаюцца дзве пераменныя на адзін і той жа # аб'ект, а == правярае, ці маюць дзве пераменныя аднолькавыя значэнні. a = [1, 2, 3, 4] # a спасылаецца на новы спіс [1, 2, 3, 4] b = a # b спасылаецца туды ж, куды і a b is a # => True, a і b спасылаюцца на адзін і той жа аб'ект b == a # => True, аб'екты a і b аднолькавыя b = [1, 2, 3, 4] # b спасылаецца на новы спіс [1, 2, 3, 4] b is a # => False, a і b спасылаюцца на розныя аб'екты b == a # => True, аб'екты a і b аднолькавыя # Радкі ствараюцца праз " ці ' "Гэта радок." 'Гэта таксама радок.' # Радкі можна складваць "Вітаю, " + "свет!" # => "Вітаю, свет!" # Радковыя літаралы (але не пераменныя) магчыма злучаць без выкарыстоўвання '+' "Вітаю, " "свет!" # => "Вітаю, свет!" # Радок можна успрымаць як спіс сімвалаў "Вітаю, свет"[0] # => 'В' # Ёсць магчымасць знайсці даўжыню радка len("Гэта радок") # => 10 # З версіі Python 3.6 магчыма выкарыстоўваць f-радкі # або фарматаваныя радковыя літаралы. name = "Рэйко" f"Яна сказала, што яе завуць {name}." # => "Яна сказала, што яе завуць Рэйко" # Любы дзейны Python-выраз унутры гэтых дужак вяртаецца ў радок. f"Даўжыня {name} — {len(name)} сімвалаў." # => "Даўжыня Рэйко — 5 сімвалаў." # None — гэта аб'ект None # => None # Не выкарыстоўвайце знак роўнасці '==' для параўнання аб'ектаў з None. # Замест гэтага карыстайцеся 'is'. Ён правярае аб'екты на ідэнтычнасць. "etc" is None # => False None is None # => True #################################################### ## 2. Пераменныя і калекцыі #################################################### # У Python ёсць функцыя print print("Я Python. Рады бачыць!") # => Я Python. Рады бачыць! # Па змаўчанні print таксама пераводзіць на новы радок у канцы. # Выкарыстоўвайце апцыянальны аргумент end каб змяніць канцоўку радка. print("Вітаю, свет", end="!") # => Вітаю, свет! # Просты спосаб атрымаць уваходныя даныя з кансолі input_string_var = input("Увядзіце даныя: ") # Вяртае даныя ў якасці радка # Ніякіх аб'яўленняў, толькі прызначэнні пераменных. # Пераменныя заведзена называць у стылі snake_case. some_var = 5 some_var # => 5 # Звяртанне да непрызначаннай пераменнай прыводзіць да выключэння. # Падрабязнасці пра апрацоўку выключэнняў у раздзеле "Паток кіравання". some_unknown_var # Выкідвае NameError # if можа быць выкарыстаны ў якасці выражэння # Эквівалент цернарнага аператара '?:' з C "Так!" if 0 > 1 else "Не!" # => "Не!" # Спісы захоўваюць паслядоўнасці li = [] # Вы можаце стварыць запоўнены спіс other_li = [4, 5, 6] # Дадаць нешта ў канец спіса праз append li.append(1) # li цяпер [1] li.append(2) # li цяпер [1, 2] li.append(4) # li цяпер [1, 2, 4] li.append(3) # li цяпер [1, 2, 4, 3] # Выдаліць з канца праз pop li.pop() # => 3 li цяпер [1, 2, 4] # Пакладзём назад li.append(3) # li цяпер зноў [1, 2, 4, 3] # Звяртайцеся да спіса як да звычайнага масіву li[0] # => 1 # Зварот да апошняга элемента li[-1] # => 3 # Зварот за межы спіса выкідвае IndexError li[4] # выклідвае IndexError # Магчыма звяртацца да дыяпазонаў праз адсячэнні. # Пачатковы індэкс уключаецца ў дыяпазон, а канчатковы не # (матэматыкі сярод вас ведаюць гэта як напаўадкрыты адцінак). li[1:3] # Вярнуць спіс з індэкса 1 па 3 => [2, 4] li[2:] # Вярнуць спіс з індэкса 2 => [4, 3] li[:3] # Вярнуць спіс да індэкса 3 => [1, 2, 4] li[::2] # Вярнуць спіс, абіраючы элементы з крокам 2 => [1, 4] li[::-1] # Вярнуць спіс у адваротным парадку => [3, 4, 2, 1] # Выкарыстоўвайце іх у рознай камбінацыі, каб ствараць лепшыя адсячэнні # li[пачатак:канец:крок] # Зрабіць копію глыбінёй у адзін слой выкарыстоўваючы адсячэнні li2 = li[:] # => li2 = [1, 2, 4, 3] але (li2 is li) верне false. # Выдаліць элемент са спіса па пазіцыі праз "del" del li[2] # li цяпер [1, 2, 3] # Выдаліць першае знойдзенае значэнне li.remove(2) # li цяпер [1, 3] li.remove(2) # Выкідвае ValueError, бо ў спісе няма элемента са значэннем 2 # Уставіць элемент па дадзенаму індэксу li.insert(1, 2) # li цяпер зноў [1, 2, 3] # Атрымаць індэкс першага элемента з дадзеным значэннем li.index(2) # => 1 li.index(4) # Выкідвае ValueError, бо ў спісе няма элемента са значэннем 4 # Магчыма складваць спісы. # Заўвага: значэнні li і other_li не змяняюцца. li + other_li # => [1, 2, 3, 4, 5, 6] # Аб'яднанне спісаў праз "extend()" li.extend(other_li) # li цяпер [1, 2, 3, 4, 5, 6] # Праверка на наяўнасць элемента ў спісе праз "in" 1 in li # => True # Атрымаць даўжыню спіса праз "len()" len(li) # => 6 # Картэжы падобныя на спісы, але не змяняюцца tup = (1, 2, 3) tup[0] # => 1 tup[0] = 3 # Выкідвае TypeError # Звярніце ўвагу, што картэжы даўжыні 1 павінны мець коску пасля # апошняга элемента, але картэжы іншай даўжыні, нават 0, не. type((1)) # => type((1,)) # => type(()) # => # Большасць аперацый для спісаў працуюць таксама на картэжах len(tup) # => 3 tup + (4, 5, 6) # => (1, 2, 3, 4, 5, 6) tup[:2] # => (1, 2) 2 in tup # => True # Вы можаце распакоўваць картэжы (або спісы) у пераменныя a, b, c = (1, 2, 3) # a цяпер 1, b цяпер 2 і c цяпер 3 # Таксама ёсць пашыраная распакоўка a, *b, c = (1, 2, 3, 4) # a цяпер 1, b цяпер [2, 3] і c цяпер 4 # Картэжы ствараюцца па змаўчанні, калі апусціць дужкі d, e, f = 4, 5, 6 # картэж 4, 5, 6 распакоўваецца ў d, e, f, # адпаведна, d = 4, e = 5 і f = 6. # Цяпер паглядзіце, як лёгка абмяняць значэнні дзвюх пераменных e, d = d, e # d цяпер 5, e цяпер 4 # Слоўнікі змяшчаюць пары ключ/значэнне empty_dict = {} # Так выглядае папярэдне запоўнены слоўнік filled_dict = {"адзін": 1, "два": 2, "тры": 3} # Звярніце ўвагу, што ключы ў слоўніках павінны быць нязменных тыпаў. Гэта для # таго, каб пераканацца, што ключ заўсёды створыць аднолькавы хэш для пошуку. # У нязменныя тыпы ўваходзяць цэлалікавыя значэнні, # значэнні з плаваючай кропкай, радкі і картэжы. invalid_dict = {[1,2,3]: "123"} # => Вікідвае TypeError: unhashable type: 'list' valid_dict = {(1,2,3):[1,2,3]} # Значэнні, аднак, могуць быць любых тыпаў. # Пошук значэнняў праз [] filled_dict["адзін"] # => 1 # Атрымаць усе ключы ў якасці itterable-аб'екта праз "keys()". Нам трэба # абгарнуць вызаў у list(), каб ператварыць вынік у спіс. Паразмаўляем аб # гэтым пазней. Заўвага, для версій Python, ніжэйшых за 3.7, парадак ключоў # слоўніка не гарантуецца, вашыя вынікі могуць не адпавядаць прыкладам ніжэй. # Аднак, з версіі Python 3.7, элементы слоўніка захоўваюць парадак, у якім яны # былі ўстаўлены. list(filled_dict.keys()) # => ["тры", "два", "адзін"] для Python <3.7> list(filled_dict.keys()) # => ["адзін", "два", "тры"] для Python 3.7+ # Атрымаць усе значэнні ў якасці itterable-аб'екта праз "values()". Зноў жа, # нам трэба абгарнуць вызаў у list(), каб атрымаць спіс. Тая ж заўвага пра # парадак, што і вышэй. list(filled_dict.values()) # => [3, 2, 1] для Python <3.7 list(filled_dict.values()) # => [1, 2, 3] для Python 3.7+ # Праверка на наяўнасць ключа ў слоўніку праз "in" "адзін" in filled_dict # => True 1 in filled_dict # => False # Пошук неіснуючага ключа выкідвае KeyError filled_dict["чатыры"] # KeyError # Выкарыстоўвайце метад "get()", каб пазбегнуць KeyError filled_dict.get("адзін") # => 1 filled_dict.get("чатыры") # => None # get() падтрымлівае прадвызначаны аргумент, калі значэнне адсутнічае ў слоўніку filled_dict.get("адзін", 4) # => 1 filled_dict.get("чатыры", 4) # => 4 # "setdefault()" устаўляе ў слоўнік толькі калі дадзенага ключа не існуе filled_dict.setdefault("пяць", 5) # filled_dict["пяць"] цяпер 5 filled_dict.setdefault("пяць", 6) # filled_dict["пяць"] усё яшчэ 5 # Дадаванне ў слоўнік filled_dict.update({"чатыры":4}) # => {"адзін": 1, "два": 2, "тры": 3, "чатыры": 4} filled_dict["чатыры"] = 4 # іншы спосаб дадаць у слоўнік # Выдаленне ключоў са слоўніка праз del del filled_dict["адзін"] # выдаляе ключ "адзін" з запоўненага слоўніка # З версіі Python 3.5 таксама існуюць дадатковыя спосабы распакоўкі {'a': 1, **{'b': 2}} # => {'a': 1, 'b': 2} {'a': 1, **{'a': 2}} # => {'a': 2} # Мноства змяшчаюць... Ну, мноства empty_set = set() # Ініцыялізваць мноства з кучы значэнняў some_set = {1, 1, 2, 2, 3, 4} # some_set цяпер {1, 2, 3, 4} # Адпаведна ключам слоўніка, элементы мноства павінны быць нязменнымі invalid_set = {[1], 1} # => Выкідвае TypeError: unhashable type: 'list' valid_set = {(1,), 1} # Дадаць яшчэ адзін элемент у мноства filled_set = some_set filled_set.add(5) # filled_set цяпер {1, 2, 3, 4, 5} # Мноства не змяшчаюць паўторных элементаў filled_set.add(5) # застаецца ранейшым {1, 2, 3, 4, 5} # Перасячэнне мностваў праз & other_set = {3, 4, 5, 6} filled_set & other_set # => {3, 4, 5} # Аб'яднанне мностваў праз | filled_set | other_set # => {1, 2, 3, 4, 5, 6} # Рознасць мностваў праз - {1, 2, 3, 4} - {2, 3, 5} # => {1, 4} # Сіметрычная рознасць мностваў праз ^ {1, 2, 3, 4} ^ {2, 3, 5} # => {1, 4, 5} # Праверыць, ці з'яўляецца мноства злева надмноствам мноства справа {1, 2} >= {1, 2, 3} # => False # Праверыць, ці з'яўляецца мноства злева падмноствам мноства справа {1, 2} <= {1, 2, 3} # => True # Праверка на наяўнасць у мностве праз in 2 in filled_set # => True 10 in filled_set # => False # Зрабіць копію глыбінёй у адзін слой filled_set = some_set.copy() # filled_set цяпер {1, 2, 3, 4, 5} filled_set is some_set # => False #################################################### ## 3. Паток кіравання і ітэрабельныя аб'екты #################################################### # Давайце зробім пераменную some_var = 5 # Так выглядае інструкцыя if. Водступы маюць значэнне ў Python! # Заведзена выкарыстоўваць чатыры прабелы, не табуляцыю. # Гэта выводзіць "some_var меньшая за 10" if some_var > 10: print("some_var цалкам большая за 10.") elif some_var < 10: # гэты elif неабавязковы. print("some_var меньшая за 10.") else: # гэта таксама неабавязкова. print("some_var насамрэч 10.") """ Ітэраванне спісаў праз цыкл for выводзіць: сабакі — млекакормячыя каты — млекакормячыя мышы — млекакормячыя """ for animal in ["сабакі", "каты", "мышы"]: # Вы можаце выкарыстоўваць format() для ўводу фарматаваных радкоў print("{} — млекакормячыя".format(animal)) """ "range(number)" вяртае ітэрабельны аб'ект з лічбаў ад 0 да дадзенай лічбы (не ўключна) выводзіць: 0 1 2 3 """ for i in range(4): print(i) """ "range(lower, upper)" вяртае ітэрабельны аб'ект з лічбаў ад ніжэйшай(lower) да вышэйшай(upper) лічбы выводзіць: 4 5 6 7 """ for i in range(4, 8): print(i) """ "range(lower, upper, step)" вяртае ітэрабельны аб'ект з лічбаў ад ніжэйшай да вышэйшай лічбы з дадзеным крокам. Калі крок не вызначаны, прадвызначаным значэннем з'яўляецца 1 выводзіць: 4 6 """ for i in range(4, 8, 2): print(i) """ Прайсці цыклам праз спіс, каб атрымаць індэкс і значэнне кожнага элемента: 0 сабака 1 кот 2 мыш """ animals = ["сабака", "кот", "мыш"] for i, value in enumerate(animals): print(i, value) """ Цыклы while працуюць пакуль умова не парушана prints: 0 1 2 3 """ x = 0 while x < 4: print(x) x += 1 # Скарачэнне x = x + 1 # Апрацоўка выключэнняў праз блок try/except try: # Выкарыстоўвайце "raise" каб выкінуць памылку raise IndexError("Гэта памылка індэкса") except IndexError as e: pass # Не рабіце так, забяспечце аднаўленне. except (TypeError, NameError): pass # Некалькі выключэнняў можна апрацоўваць сумесна. else: # Неабавязковая частка блока try/except. Павінна быць # пасля ўсіх блокаў except. print("Усё добра!") # Выконваецца толькі калі код унутры try не выкідвае # выключэнняў finally: # Выконваецца пры ўсіх абставінах. print("Тут можна пачысціць рэсурсы") # Замест try/finally для ачысткі рэсурсаў магчыма выкарыстоўваць with with open("myfile.txt") as f: for line in f: print(line) # Запіс у файл contents = {"aa": 12, "bb": 21} with open("myfile1.txt", "w") as file: file.write(str(contents)) # запісвае радок у файл import json with open("myfile2.txt", "w") as file: file.write(json.dumps(contents)) # запісвае аб'ект у файл # Reading from a file with open('myfile1.txt', "r") as file: contents = file.read() # чытае радок з файла print(contents) # выводзіць: {"aa": 12, "bb": 21} with open('myfile2.txt', "r") as file: contents = json.load(file) # чытае json аб'ект з файла print(contents) # выводзіць: {"aa": 12, "bb": 21} # Python прапануе фундаментальную абстракцыю # пад назвай Iterable ("ітэрабельны аб'ект" далей). # Ітэрабельны аб'ект — гэта аб'ект, які можна разглядаць як паслядоўнасць. # Аб'ект, які вяртаецца функцыяй range, з'яўляецца ітэрабельным. filled_dict = {"адзін": 1, "два": 2, "тры": 3} our_iterable = filled_dict.keys() print(our_iterable) # => dict_keys(['адзін', 'два', 'тры']). Гэта аб'ект, # які рэалізуе інтэрфейс Iterable. # Мы можам прайсці па яму цыклам for i in our_iterable: print(i) # Выводзіць адзін, два, тры # Аднак, да элементаў нельга звяртацца па індэксу our_iterable[1] # Выкідвае TypeError # Ітэрабельны аб'ект ведае, як стварыць ітэратар our_iterator = iter(our_iterable) # Наш ітэратар з'яўляецца аб'ектам, які можа запамінаць # стан падчас нашага праходу праз яго. # Мы можам атрымаць наступны аб'ект з дапамогаю "next()" next(our_iterator) # => "адзін" # Ён утрымлівае стан, пакуль мы ітэруем next(our_iterator) # => "два" next(our_iterator) # => "тры" # Калі ітэратар вярнуў усе дадзеныя, ён выкідвае выключэнне StopIteration next(our_iterator) # Выкідвае StopIteration # Мы таксама можам прайсці па яму цыклам, # насамрэч, "for" ускосна гэта і робіць our_iterator = iter(our_iterable) for i in our_iterator: print(i) # Выводзіць адзін, два, тры # Вы можаце захапіць усе элементы ітэрабельнага аб'екта або ітэратара # праз вызаў list() list(our_iterable) # => Вяртае ["адзін", "два", "тры"] list(our_iterator) # => Вяртае [], бо стан захоўваецца #################################################### ## 4. Функцыі #################################################### # Выкарыстоўвайце "def" для стварэння новых функцый def add(x, y): print("x = {}, а y - {}".format(x, y)) return x + y # Вяртайце значэнні праз return # Вызаў функцый з параметрамі add(5, 6) # => выводзіць "x = 5, а y = 6" і вяртае 11 # Таксама магчыма вызываць функцыі з найменнымі аргументамі add(y=6, x=5) # Найменныя аргументы можна выкарыстоўваць у любым парадку # Вы можаце вызначыць функцыю, якая прымае зменлівую колькасць # пазіцыйных аргументаў def varargs(*args): return args varargs(1, 2, 3) # => (1, 2, 3) # Таксама, вы можаце вызначаць функцыі, якія прымаюць зменлівую колькасць # найменных аргументаў def keyword_args(**kwargs): return kwargs # Давайце вызавем яе і паглядзім, што будзе keyword_args(big="foot", loch="ness") # => {"big": "foot", "loch": "ness"} # Вы можаце выкарыстоўваць два спосабы адначасова, калі хочаце def all_the_args(*args, **kwargs): print(args) print(kwargs) """ all_the_args(1, 2, a=3, b=4) выводзіць: (1, 2) {"a": 3, "b": 4} """ # Вызываючы функцыі, вы можаце зрабіць адваротнае args/kwargs! # Выкарыстоўвайце * для разгортвання пазіцыйных аргументаў (картэжаў) # і ** для разгортвання найменных аргументаў (слоўнікаў) args = (1, 2, 3, 4) kwargs = {"a": 3, "b": 4} all_the_args(*args) # адпавядае: all_the_args(1, 2, 3, 4) all_the_args(**kwargs) # адпавядае: all_the_args(a=3, b=4) all_the_args(*args, **kwargs) # адпавядае: all_the_args(1, 2, 3, 4, a=3, b=4) # Вяртанне некалькіх значэнняў (з прызначэннем картэжаў) def swap(x, y): return y, x # Вяртае некалькі значэнняў у выглядзе картэжу без дужак. # (Заўвага: дужкі апускаюцца, але могуць выкарыстоўвацца) x = 1 y = 2 x, y = swap(x, y) # => x = 2, y = 1 # (x, y) = swap(x,y) # Зноў жа, выкарыстоўваць дужкі неабавязкова # глабальная вобласць x = 5 def set_x(num): # лакальная вобласць пачынаецца тут # лакальная пераменная x адрозніваецца ад глабальнай x = num # => 43 print(x) # => 43 def set_global_x(num): # global пазначае, што пераменная знаходзіцца ў глабальнай вобласці global x print(x) # => 5 x = num # глабальная пераменная x цяпер 6 print(x) # => 6 set_x(43) set_global_x(6) """ выводзіць: 43 5 6 """ # Python падтрымлівае функцыі першага класа def create_adder(x): def adder(y): return x + y return adder add_10 = create_adder(10) add_10(3) # => 13 # Замыканні ва ўкладзеных функцыях: # Мы можам выкарыстоўваць ключавое слова nonlocal для працы з пераменнымі # ўнутры ўкладзенай вобласці, якія не павінны быць аб'яўлены ва ўнутраных # функцыях. def create_avg(): total = 0 count = 0 def avg(n): nonlocal total, count total += n count += 1 return total/count return avg avg = create_avg() avg(3) # => 3.0 avg(5) # (3+5)/2 => 4.0 avg(7) # (8+7)/3 => 5.0 # Таксама існуюць ананімныя функцыі (lambda x: x > 2)(3) # => True (lambda x, y: x ** 2 + y ** 2)(2, 1) # => 5 # Існуюць убудаваныя функцыі вышэйшага парадку list(map(add_10, [1, 2, 3])) # => [11, 12, 13] list(map(max, [1, 2, 3], [4, 2, 1])) # => [4, 2, 3] list(filter(lambda x: x > 5, [3, 4, 5, 6, 7])) # => [6, 7] # Для прыгажосці, замест map і filter мы можам выкарыстоўваць спісачныя выразы # Спісачныя выразы захоўваюць вынік у выглядзе спіса (які сам па сабе можа # быць укладзеным). [add_10(i) for i in [1, 2, 3]] # => [11, 12, 13] [x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7] # Таксама вы можаце стварыць адпаведныя выразы для мностваў і слоўнікаў {x for x in 'abcddeef' if x not in 'abc'} # => {'d', 'e', 'f'} {x: x**2 for x in range(5)} # => {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} #################################################### ## 5. Модулі #################################################### # Вы можаце імпартаваць модулі import math print(math.sqrt(16)) # => 4.0 # Вы можаце ўзяць дакладныя функцыі з модуля from math import ceil, floor print(ceil(3.7)) # => 4 print(floor(3.7)) # => 3 # Вы можаце імпартаваць усе функцыі з модуля. # Заўвага: не рэкамендуецца так рабіць. from math import * # Вы можаце скарачаць імёны модуляў import math as m math.sqrt(16) == m.sqrt(16) # => True # Модулі ў Python з'яўляюцца звычайнымі Python файламі. Вы можаце напісаць # свае і імпартаваць іх. Імя модуля адпавядае імені файла. # Вы можаце даведацца, якія функцыі і атрыбуты вызначаны ў модулі import math dir(math) # Калі ў вас ёсць Python-скрыпт з назвай math.py у той жа папцы, # што і бягучы скрыпт, файл math.py будзе загружаны замест убудаванага # Python-модуля. Гэта адбываецца таму, што лакальная папка мае большы # прыярытэт, чым убудаваныя Python-бібліятэкі. #################################################### ## 6. Класы #################################################### # Мы выкарыстоўваем інструкцыю "class" для стварэння класаў class Human: # Атрыбут класа. Яго першапачатковае значэнне пашыраецца # паміж усімі экзэмплярамі класа. species = "H. sapiens" # Базавы канструктар, вызываецца пры стварэнні экзэмпляраў класа. # Звярніце ўвагу, што двайное падкрэсліванне абазначае аб'екты або # атрыбуты, якія выкарыстоўвае Python, але яны існуюць у прасторах назваў, # якія кантралюе карыстальнік. Метады(або аб'екты ці атрыбуты), такія як # __init__, __str__, __repr__ і г.д., называюцца спецыяльнымі метадамі, # або магічнымі метадамі. Вам не варта ствараць такія імёны самастойна. def __init__(self, name): # Прызначэнне аргумента атрыбуту name экзэмпляра класа self.name = name # Ініцыялізацыя ўласцівасці self._age = 0 # папярэдняе падкрэсліванне абазначае, што ўласцівасць # "age" створана для ўнутранага выкарыстання, # але гэта ніяк не кантралюецца, а з'яўляецца # звычайнай падказкай для іншых распрацоўшчыкаў. # Метад экзэмпляра. Усе метады прымаюць "self" у якасці першага аргумента. def say(self, msg): print("{name}: {message}".format(name=self.name, message=msg)) # Іншы метад экзэмпляра def sing(self): return 'ёў... ёў... праверка мікрафона... раз два... раз два...' # Метад класа пашыраецца паміж усімі экзэмплярамі. # Яны вызываюцца з указаннем вызываючага класа ў якасці першага аргумента. @classmethod def get_species(cls): return cls.species # Статычны метад вызываецца без спасылкі на клас або экзэмпляр @staticmethod def grunt(): return "*рохкае*" # property зусім як гетэр # гэты дэкаратар ператварае метад age() у аднайменны атрыбут, # даступны толькі для чытання. # У Python не трэба пісаць трывіяльныя гетэры і сэтэры, дарэчы. @property def age(self): return self._age # Гэта дазваляе ўстанавіць уласцівасць @age.setter def age(self, age): self._age = age # Гэта дазваляе выдаліць уласцівасць @age.deleter def age(self): del self._age # Калі інтэрпрэтатар Python чытае зыходны файл, ён выконвае ўвесь код. # З дапамогай гэтай праверкі, блок кода выконваецца толькі калі модуль # з'яўляецца асноўнай праграмай. if __name__ == '__main__': # Стварэнне экзэмпляра класа i = Human(name="Ігар") i.say("вітан") # "Ігар: вітан" j = Human("Янка") j.say("вітаю") # "Янка: вітаю" # i з j з'яўляюцца экзэмплярамі тыпу Human, г.з., яны аб'екты Human # Вызаў метаду класа i.say(i.get_species()) # "Ігар: H. sapiens" # Змена агульнага атрыбута Human.species = "H. neanderthalensis" i.say(i.get_species()) # => "Ігар: H. neanderthalensis" j.say(j.get_species()) # => "Янка: H. neanderthalensis" # Вызаў статычнага метаду print(Human.grunt()) # => "*рохкае*" # Статычны метад магчыма вызваць таксама з экзэмпляра print(i.grunt()) # => "*рохкае*" # Абнавіць уласцівасць для гэтага экзэмпляра i.age = 42 # Атрымаць уласцівасць i.say(i.age) # => "Ігар: 42" j.say(j.age) # => "Янка: 0" # Выдаліць уласцівасць del i.age # i.age # => гэта выкіне AttributeError #################################################### ## 6.1 Наследаванне #################################################### # Наследаванне дазваляе вызначаць новыя вытворныя класы, якія наследуюць # метады і пераменныя сваіх базавых класаў. # Выкарыстоўваючы клас Human, вызначаны раней, у якасці базавага або # класа-папярэдніка, мы можам вызначыць вытворны клас Superhero, які наследуе # пераменныя класа(species, name, age) і метады(sing, grunt) з класа Human, # але таксама мае свае ўнікальныя ўласцівасці. # Каб выкарыстаць перавагі файлавай модульнасці, вы можаце змясціць класы # ў асобныя файлы, напрыклад, human.py # Каб імпартаваць функцыі з іншых файлаў, выкарыстоўвайце наступны фармат # from "імя-файла-без-пашырэння" import "функцыя-або-клас" from human import Human # Пазначце клас-папярэднік ў якасці параметра ў вызначэнні вытворнага класа class Superhero(Human): # Калі вытворнаму класу трэба толькі ўнаследаваць усе вызначэнні # класа-папярэдніка без мадыфікацый, вы можаце выкарыстаць ключавое # слова "pass" (і нічога больш), але ў гэтым выпадку яно закаментавана, # каб мець магчымасць стварыць унікальны клас # pass # Вытворныя класы могуць перавызначыць атрыбуты папярэднікаў species = 'Суперчалавек' # Вытворныя класы аўтаматычна наследуюць канструктары папярэднікаў разам # з аргументамі, але таксама могуць вызначаць дадатковыя аргументы або # вызначэнні, і перавызначаць метады, такія як канструктар класа. # Гэты канструктар наследуе аргумент name з Human # і дадае superpowers і movie: def __init__(self, name, movie=False, superpowers=["суперсіла", "куленепрабівальнасць"]): # дадаць дадатковыя атрыбуты класа: self.fictional = True self.movie = movie # сцеражыцеся прадвызначаных значэнняў зменных тыпаў, # паколькі яны абагульняюцца self.superpowers = superpowers # Функцыя "super" дазваляе атрымаць доступ да метадаў папярэдніка, # якія былі перавызначаны ў вытворным класе, у гэтым выпадку # да метаду __init__. # Вызаў канструктара класа-папярэдніка: super().__init__(name) # перавызначыць метад sing def sing(self): return 'Шчучыншчына!' # дадаць дадатковы метад экзэмпляра def boast(self): for power in self.superpowers: print("Я маю такую моц, як {pow}!".format(pow=power)) if __name__ == '__main__': sup = Superhero(name="Клешч") # Праверка тыпу экзэмпляра if isinstance(sup, Human): print('Я — чалавек') if type(sup) is Superhero: print('Я — супергерой') # Атрымаць "Парадак Вырашэння Метаду"(Method Resolution Order), які # выкарыстоўваюць getattr() і super() # (парадак, у якім адбываецца пошук атрыбутаў або метадаў у класе). # Гэты атрыбут дынамічны і можа абнаўляцца. print(Superhero.__mro__) # => (, # => , ) # Вызывае метад папярэдніка, але выкарыстоўвае ўласны атрыбут класа print(sup.get_species()) # => Суперчалавек # Вызывае перавызначаны метад print(sup.sing()) # => Шчучыншчына! # Вызывае метад з Human sup.say('Лыжка') # => Клешч: Лыжка # Вызывае метад, які існуе толькі ўнутры Superhero sup.boast() # => Я маю такую моц, як суперсіла! # => Я маю такую моц, як куленепрабівальнасць! # Унаследаваны атрыбут класа sup.age = 31 print(sup.age) # => 31 # Атрыбут, які існуе толькі ўнутры Superhero print('Я магу атрымаць Оскар? ' + str(sup.movie)) #################################################### ## 6.2 Множнае наследаванне #################################################### # Вызначэнне іншага класа # bat.py class Bat: species = 'рукакрылачка' def __init__(self, can_fly=True): self.fly = can_fly # У гэтым класе таксама ёсць метад say def say(self, msg): msg = '... ... ...' return msg # І свой уласны метад таксама def sonar(self): return '))) ... (((' if __name__ == '__main__': b = Bat() print(b.say('вітаю')) print(b.fly) # І вызначэнне яшчэ аднаго класа, які наследуецца ад Superhero і Bat # superhero.py from superhero import Superhero from bat import Bat # Вызначыць Batman у якасці вытворнага класа, # які наследуецца ад Superhero і Bat. class Batman(Superhero, Bat): def __init__(self, *args, **kwargs): # Звычайна, каб унаследаваць атрыбуты, вам трэба вызваць super: # super(Batman, self).__init__(*args, **kwargs) # Аднак, мы маем справу з множным наследаваннем, а super() працуе # толькі з наступным базавым класам у спісе MRO. # Таму, замест гэтага мы напрамую вызываем __init__ # для кожнага з папярэднікаў. # Выкарыстанне *args і **kwargs дазваляе ахайна перадаць аргументы, # якія папярэднікі будуць разбіраць слой за слоем. Superhero.__init__(self, 'ананім', movie=True, superpowers=['Багаты'], *args, **kwargs) Bat.__init__(self, *args, can_fly=False, **kwargs) # перавызначэнне значэння атрыбута name self.name = 'Сум Афлек' def sing(self): return 'шчу шчу шчу шчу Шчучыншчына!' if __name__ == '__main__': sup = Batman() # Парадак Вырашэння Метаду(MRO) print(Batman.__mro__) # => (, # => , # => , # => , ) # Вызывае метад папярэдніка, але выкарыстоўвае ўласныя атрыбуты print(sup.get_species()) # => Суперчалавек # Вызывае перавызначаны метад print(sup.sing()) # => шчу шчу шчу шчу Шчучыншчына! # Вызывае метад з Human, бо парадак наследавання мае значэнне sup.say('згодны') # => Сум Афлек: згодны # Вызывае метад, які існуе толькі ў другім папярэдніку print(sup.sonar()) # => ))) ... ((( # Унаследаваны атрыбут класа sup.age = 100 print(sup.age) # => 100 # Унаследаваны атрыбут другога папярэдніка, прадвызначаныя значэнні # якога былі пераназначаны print('Я ўмею лятаць? ' + str(sup.fly)) # => Я ўмею лятаць? False #################################################### ## 7. Дадаткова #################################################### # Генератары дапамагаюць пісаць лянівы код def double_numbers(iterable): for i in iterable: yield i + i # Генератары эфектыўна выкарыстоўваюць памяць, таму што загружаюць толькі # даныя, патрэбныя для апрацоўкі наступнага кроку ітэрацыі. Гэта дазваляе # ім выконваць аперацыі з вялікімі дыяпазонамі даных, якія ў іншых выпадках # былі б недапушчальнымі. # Заўвага: `range` замяняе `xrange` у Python 3. for i in double_numbers(range(1, 900000000)): # `range` гэта генератар. print(i) if i >= 30: break # Адпаведна спісачным выразам, магчыма таксама ствараць генератарныя выразы. values = (-x for x in [1,2,3,4,5]) for x in values: print(x) # выводзіць -1 -2 -3 -4 -5 у кансоль/тэрмінал # Таксама вы можаце ператварыць генератарны выраз прама ў спісак. values = (-x for x in [1,2,3,4,5]) gen_to_list = list(values) print(gen_to_list) # => [-1, -2, -3, -4, -5] # Дэкаратары з'яўляюцца формай сінтаксічнага цукру. # Нягледзячы на дзіўны сінтаксіс, яны робяць код лягчэйшым для прачытання. # Абгорткі — адзін з відаў дэкаратараў. # З іх дапамогай вельмі зручна дадаваць лагіраванне ў існуючыя функцыі без # неабходнасці іх мадыфікаваць. def log_function(func): def wrapper(*args, **kwargs): print("Уваход у функцыю", func.__name__) result = func(*args, **kwargs) print("Выхад з функцыі", func.__name__) return result return wrapper @log_function # адпаведнік: def my_function(x,y): # def my_function(x,y): return x+y # return x+y # my_function = log_function(my_function) # Дэкаратар @log_function кажа, што падчас прачытання вызначэння функцыі # my_function, яна будзе абгорнута ў log_function. # Калі вызначэнні функцый доўгія, можа быць цяжка апрацаваць неабгорнутыя # прызначэнні ў канцы вызначэнняў. my_function(1,2) # => "Уваход у функцыю my_function" # => "3" # => "Выхад з функцыі my_function" # Але ёсць праблема. # Што калі мы паспрабуем атрымаць якую-небудзь інфармацыю пра my_function? print(my_function.__name__) # => 'wrapper' print(my_function.__code__.co_argcount) # => 0. argcount у выніку 0 таму, што абодва аргументы ў сігнатуры wrapper() з'яўляюцца апцыянальнымі. # Таму, што наш дэкаратар адпавядае my_function = log_function(my_function), # мы замянілі інфармацыю аб my_function інфармацыяй з абгорткі. # Выправіць гэта праз functools from functools import wraps def log_function(func): @wraps(func) # Гэта гарантуе, што дакументацыйны радок (docstring), імя # функцыі, спіс аргументаў і інш., капіруюцца ў выніковую # функцыю замест іх замены інфармацыяй з абгорткі. def wrapper(*args, **kwargs): print("Уваход у функцыю ", func.__name__) result = func(*args, **kwargs) print("Выхад з функцыі ", func.__name__) return result return wrapper @log_function def my_function(x,y): return x+y my_function(1,2) # => "Уваход у функцыю my_function" # => "3" # => "Выхад з функцыі my_function" print(my_function.__name__) # => 'my_function' print(my_function.__code__.co_argcount) # => 2 ``` ### Бясплатныя анлайн-рэсурсы * [Automate the Boring Stuff with Python](https://automatetheboringstuff.com) * [The Official Docs](https://docs.python.org/3/) * [Hitchhiker's Guide to Python](https://docs.python-guide.org/en/latest/) * [Python Course](https://www.python-course.eu) * [Free Interactive Python Course](http://www.Kikodo.io) * [First Steps With Python](https://realpython.com/learn/python-first-steps/) * [A curated list of awesome Python frameworks, libraries and software](https://github.com/vinta/awesome-python) * [30 Python Language Features and Tricks You May Not Know About](https://sahandsaba.com/thirty-python-language-features-and-tricks-you-may-not-know.html) * [Official Style Guide for Python](https://www.python.org/dev/peps/pep-0008/) * [Python 3 Computer Science Circles](https://cscircles.cemc.uwaterloo.ca/) * [Dive Into Python 3](https://www.diveintopython3.net/index.html) * [A Crash Course in Python for Scientists](https://nbviewer.jupyter.org/gist/anonymous/5924718) * [Python Tutorial for Intermediates](https://pythonbasics.org/) * [Build a Desktop App with Python](https://pythonpyqt.com/)