Атрымаць зыходны код: learnpython-by.py
Python быў створаны Гвіда ван Росумам у пачатку 90-х. Цяпер гэта адна з самыя папулярных моў праграмавання. Я закахаўся ў 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)) # => <class 'int'>
type((1,)) # => <class 'tuple'>
type(()) # => <class 'tuple'>
# Большасць аперацый для спісаў працуюць таксама на картэжах
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__) # => (<class '__main__.Superhero'>,
# => <class 'human.Human'>, <class 'object'>)
# Вызывае метад папярэдніка, але выкарыстоўвае ўласны атрыбут класа
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__) # => (<class '__main__.Batman'>,
# => <class 'superhero.Superhero'>,
# => <class 'human.Human'>,
# => <class 'bat.Bat'>, <class 'object'>)
# Вызывае метад папярэдніка, але выкарыстоўвае ўласныя атрыбуты
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
Маеце параду? Ці, можа, папраўкі? Адкрыйце Issue у GitHub-рэпазіторыі або зрабіце pull request самастойна!
Першапачатковы аўтар Louie Dinh, абноўлена 9 аўтарамі.