Post main image

Основы

Python — интерпретируемый язык. Его можно встраивать в C/C++ программы. Официальное руководство говорит, чтобы исполняющиеся скрипты создавались посредством bash.

#!/usr/bin/env python3
print("Hello" "{}world".format(" "))

Затем задать права chmod a+x hello.py и добавить в PATH (PATH=$PATH:DIRNAME)

Для получения справки используется встроенная функция help.

help('print')

Комментарии со знака решетки

# this is help function
help('print')

Числа

Числа бывают целые, с плавающей точкой и комплексные с помощью j

(1-1j)

Дробные литералы MEp, где M - мантисса, E - E, p - порядок

print(1.2E-4)

Двоичные объявляются через 0b. Восьмиричные объявляются с нуля и латинской буквы «o», 0o. Шестнадцатеричные объявляются через 0x. Для операций с действительной дочностью используются объекты Decimal и модуля decimal.

from decimal import *
print(1.0 - 0.1 - 0.3) # 0.6000000000000001
print(Decimal('1.0') - Decimal('0.1') - Decimal('0.3')) # 0.6

Для дробей используется тип Fraction из модуля fractions.

from fractions import *
print(Fraction(1, 2)) # 1/2

Функции преобразования int (с системой счисления), float, bin, oct, hex, round (с количеством точек после запятой), abs, pow, max, min, sum (последовательность), div (возвращает кортеж x// y, x%y).

print(12)
print(1.4E-2)
print(1-1j)
/usr/bin/python /test.py
12
0.014

У типа float усть методы методы is_integer, as_integer_ration — возвращает кортеж числителя и знаменателя дроби.

Строки

Строки указываются в одинарных и двойных кавычках, они никак не отличаются.

print("test")
print('test')

Тройные двойные или одинарные кавычки действуют как HEREDOC.

print(""" First line"" And second """)

Объединить строки можно поставив их одну за одной. print(“Hello” “ “ “World”) Вывод с помощью print. Ввод с помощью input.

input = input("Enter some string") print(input)

Точка с запятой нежелательна

print("Hello" " " "World"); # Bad print(2)

Метод format позволяет составить строку на основе каких-либо данных.

print("Say {}".format("Hi"))
print("My name is {0}. And the second is {1}".format("Pavel", "Murtazin"))
print("Your name is {name}".format(name="Vasya"))

А так же с уточнениями. (см. http://www.python.org/dev/peps/ pep-3101) Все строки в UTF-8. Для объявления кодировки применяется специальный комментарий

# -*- coding: utf-8 -*-

Строки позволяют работать с ними, как с коллекциями, то есть выбирать символ и брать срезы.

print("A very long message"[0:6]) # A very Конкатенация через плюс. Причем строка всегда является строкой.
print("1" + "2") # 12

bytes и bytearray являются строковыми типами данных. Чтобы использовать несколько строк в одной, необходимо использовать слэш. Для использования слэша в конце строки, его необходимо экранировать.

# print("Hello\")  # SyntaxError: EOL while scanning string literal
print("Hello\\") # Hello\

Что отлючить спецсимволы в строке, нужно перед строкой разместить модификатор r.

print(r"Hello\n") # Hello\n

Если строку не передать в аргумент, то она автоматически попадет в переменную doc текущего объекта. Строка — неизменяемая последовательность, можно получить символ по индексу, но нельзя изменить. Узнать длину строки можно с помощью функции len.

print(len("Hello")) # 5

Операция умножения повторяет строку, а in и not in осуществляет проверку на вхождение.

print("A" * 3) # AAA

Оператор форматирования - это процент. Специальная строка имеет формат %[key][flag][width][.accuracy]<type>.

  • key — ключ словаря, тогда правым операндом должен быть передан словарь.
  • flag — флаг преобразования
    • # — восьмиричное значение
    • 0x — количество ведущих нулей
    • - — выравнивание по левой границе
    • пробел — вставляет пробел перед положительным числом
    • + — обязательный ввод знака для положительных и отрицательных чисел
  • width — минимальная ширина поля
  • accuracy — количество знаков после точки для вещественных чисел. Можно указать как * и передать значения внутри кортежа.
  • type - тип преобразования
    • s — строка
    • r — строка с помощью repr
    • a — строка с помощью ascii
    • c — символ
    • d, i — целое число
    • o - восьмиричное
    • x, X - шестнадцатиричное в нижнем и верхнем регистре
    • f и F — вещественное число
    • e и E — вещественное число в экспоненциальной форме
    • g и G — вещественное чсило в наиболее короткой форме
print("""
My name is %(name)s.
I am %(age)i age old.
I live in %(city)-10s.
My body's temperature is %(temp)010.5G """ % {
"name": "Alex", "age": 10,
"city": "London", "temp": 36.63145123412
})
    # My name is Alex.
    # I am 10 age old.
    # I live in London    .
    # My body's temperature is 000036.631

В качестве альтернативы используется метод format. Для этого метода символы {} являются специальными, вместо них подставляются соответствующие аргументы.

print("My name is {1}. I am {0} age old".format(10, "Paul"))

Аргументы могут быть именованными или же являться словарем.

print("My name is {name}. I am {age} age old".format(age=10, name="Paul"))
print("My name is {name}. I am {age} age old".format(**{"age": 10, "name": "Paul"}))

Внутри специальной строки можно получить доступ к элементам массива.

print("My name is {data[name]}. I am {data[age]} age old".format(data={'age': 10, 'name': "Paul"}))

Через восклицательный знак можно указать функцию-обработчик. - s - str - r - repr - a - ascii

print("My name is {data[name]!a}. I am {data[age]} age old".format(data={'age': 10, 'name': "Павел"}))

В конце через двоеточие можно указать форматирование в формате. - Заполнитель с выравниванием по левому (<) и правому (>) краю, или по-центру (^).

print(
    "My name is {name:!>10}." \
        .format(
            **{"age": 10, "name": "Paul"}
        ) # My name is !!!!!!Paul.
)
  • Минимальную ширину строки.

    • Указать знак для чисел. + — с выводом всех знаков, - — только отрицательных, пробел — пробел для положительных.
    • Указать преобразование.
      • b — двоичное число. print(““.format(100)) # 1100100
      • c — целое число в символ print(““.format(47)) # /
      • d — десятичное число
      • n — как d, но учитывает настройки локали
      • o — восьмиричное число
      • x — шестнадцатеричное значение в нижнем регистре
      • X — шестнадцатеричное значение в верхнем регистре
      • f и F — вещественное число в десятичном представлении
      • e и E — вещественное число в экспоненциальном представлении
      • g и G — f или e, что будет короче
      • % — преобразует в процент Строки имеют следующие методы.
    • expandtabs — заменяет символы табуляции на пробелы (можно указать количество пробелов).
    • center - выравнивает строку по центру внутри поля указанной длины.
    • ljust/rjust — выравнивает строку по левому/правому краю внутри поля указанной длины.
    • zfill — выравнивает строку по правому краю внутри поля указанной длины, дополняя 0.
    • strip — удаляет символы с начала и конца строки (если аргумент не передан, то пробельные символы).
    • lstrip, rstrip — удаление символов слева/справа.
    • split — разбивает строку по указанному разделителю.
    • rsplit — тоже, но поиск разделителя справа-налево.
    • splitlines — разбивает строку на подстроки. Если передать False, то в результате будет только первая строка.
    • partition — находит первое вхождение символа-разделителя и возвращает кортеж из фрагмента перед разделителем, разделитель и фрагмент после.
    • rpartition — тоже, но поиск справа-налево.
    • join — преобразует последовательность в строку.
    • upper — в верхний регистр.
    • lower — в нижний регистр.
    • swapcase — меняет регистр местами.
    • capitalize — первая буква в верхний регистр.
    • title — первая буква каждого слова в верхний регистр.
    • casefold — как и lower, но преобразует диактрические знаки в латиницу.
    • find — ищет подстроку в строке.
    • index — тоже, что и find, но с исключением.
    • rfind — find справа-налево.
    • rindex — тоже для index.
    • count — количество вхождений подстроки в строку.
    • startswith — начинается ли строка с подстроки.
    • endswith — заканчивается ли строка с подстроки.
    • replace — заменяет все подстроки, входящие в строку.
    • translate — заменяет все символы в соответствии с таблицей символов. В качестве ключей код символа.
    • maketrans — статический метод, помогающий создать таблицу символов.
    • isalnum — проверяет, что строка собержит только буквы и цифры.
    • isalpha — только буквы.
    • isdigit — только цифры.
    • isdecimal — только десятичные цифры.
print("Hello".rjust(20, '0'))
print("Hello".zfill(20))
print("ß".casefold()) # ss
print("Hello".translate({ord("H"): "M" })) # Mello
print("Hello".translate( str.maketrans({"H": "M"}))) # Mello

Определить кодировку можно с помощью метода detect модуля chardet.

print(chardet.detect(result.read())) # {'confidence': 0.99, 'encoding': 'utf-8'}

Bytes и bytearray

Эти типы данных подходят для обработки изображений. Можно создать с помощью одноименных функций, передав последовательность или челое число для инициализации последовательности переданной длины. Bytes можно создать, начав строку с b.

b"Foo-bar"

Есть методы append, extend, insert, pop, remove, reverse, decode. Метод decode преобразует в указанную кодировку. С помошью модуля pickle (методы dumps и loads) можно сериализовать и десериализовать объекты в последовательность байтов.

import pickle
fb = pickle.dumps("Foo-bar") print(pickle.loads(fb))

Взаимодействие с файловой системой

Открыть файл можно с помощью функции open.

for line in open(__file__):
    num += 1
    print(str(num) + " " + line)

Метод readline возвращает текущую строку. Метод close закрывает файл. Чтобы записать в файл используется функция print с аргументом file. Но для этого необходимо открыть файл в режиме записи (аргумент mode).

file = open('./sources/index.txt', 'w')

for i in range(0, 20):
    print("Line N" + str(i), file=file)

file.close()

Также для записи существует метод write.

file = open('./sources/index.txt', 'w')

for i in range(0, 20):
    print("Line N" + str(i), file=file)
    file.write("Last %s" % "Line")

file.close()

Для записи/чтения из стандартного потока используются объекты sys.stdout и sys.stdin

import sys
line = sys.stdin.readline()
sys.stdout.write("{}\r...\nOk".format(line))

Типы данных

  • bool - логический.
  • NoneType - отсутствие значение. Объявляется как None.
  • int - целое число. Ограничено оперативной памятью.
  • float - число с плавающей точкой.
  • complex - комплексное число.
  • str - строка.
  • bytes - неизменяемая последовательность байтов.
  • bytearray - изменяемая последовательность байтов.
  • list - список. Последовательность.
  • tuple - кортежи.
  • range - диапазон. От и до для чисел.
  • dict - словарь. Ассоциативный массив.
  • set - множество. Набор уникальных значений.
  • frozenset - неизменяемое множество. Набор уникальных значений. ellipsis - обозначается тремы точками.
  • function - функция.
  • module - модуль.
  • type - сами типы являются этим типом.

Определить тип можно с помощью функции type.

print(type(...)) # <class 'ellipsis'>

Приведение типов производится с помощью одноименной с типов функции. Чтобы проверить тип данных, нужно сравнить результат функции type и имени типа.

print(type(1) == int) # True

Преобразование типов

Преобразования к строке производится с помощью функций str, repl, ascii и format.

class Person:
    pass

print(str(23))
print(repr(Person()))

Преобразования с помощью методов str, int.

print(str(1)) # "1"
print(int("12")) # 12

Остальное

Переменные объявляются с определения.

eggSize = 10

При присваивании в переменной хранится ссылка на объект, а не сам объект. Это необходимо учитывать при групповом присваивании.

x = y = {
    "one": 1,
    "two": 2
}

y["one"] = 3

print(x, y, sep="\n")
# {'two': 2, 'one': 3}
# {'two': 2, 'one': 3}

Python кэширует малые числа и строки, так что они ссылаются на одну облать в памаяти. Чтобы узнать, что переменные ссылаются на один и тот же объект используется оператор is.

a = 2 b = 1 + 1
print(a is b) # True

Обратной операцией является is not.

print(2 is not 3) # True

Количество ссылок можно узнать с помощью функции getrefcount модуля sys.

print(sys.getrefcount(2)) # 116

Как только количество ссылок равно нулю, область памяти очищается. Список ключевых слов можно найти в модуле keyword.kwlist. Встроенные идентификаторы можно переопределить. Все типы являются объектами. Логическая строка в Python — одна инструкция. По-умолчанию одна строка — одна инструкция. Чтобы разместить на одной физической строке несколькое логических используется точка с запятой. Чтобы разбить логическйю строку на физические используется обратный слэш.

eggSize = \
    10
print(eggSize)

Логическими типами являются True и False. В Python крайне важны отступы. Набор предложений, идущих одно за одним, с одинаковыми отступами называется блоком. Блоки высокого уровня указывают на вложенные с помощью двоеточия. Для использования пустого блока используется оператор pass.

if True:
    pass

Удаление происходит с помощью оператора del.

a = 50
del a
# print(a) NameError: name 'a' is not defined

Регулярные выражения

Регулярные выражения лежат в модуле re. Создать регулярное выражение можно с помощью функции compile. Первым аргументом является регулярное выражение, а вторым флаги.

  • L — учитывать настройки локали.
  • I — ignorecase
  • M — поиск в строке, состоящей из нескольких строк.
  • S — включить, что точка — любой символ, ^ — начало строки, $ — конец строки.
  • X — пробельные символы и переноса строки будут проигнорированы. Добавляет возможность комментариев.
  • A — символы \w \W \d и прочие теряют свое предназначение.
re.compile("""
    ^ # Start of line
    .* # Any symbol
    $ # End of line
""", re.X)

Методы.

  • match — проверяет соответствие с началом строки.
  • search — проверка на соответствие.
  • fullmatch — соответствие строки целиком.
  • findall - ищет все совпадения.
  • findinter — возвращает итератор.
  • sub — осуществляет замену.
  • split — разбивает по шаблону.

Эти методы возвращают объект типа Match. Он имеет полезные методы и свойства.

  • re — ссылка на регулярное выражение. У регулярного выражения имеются свойства.
    • groups — количество групп в шаблоне.
    • groupindex — словарь с именами и номерами групп.
    • pattern — строка регулярки.
    • flags — флаги.
  • string — переданная строка, в которой происходит поиск.
  • pos и endpos — значения одноименных аргументов в функциях, которые были использованы (match или search).
  • lastindex — номер последней совпавшей группы или None.
  • lastgroup — для именованных групп.
  • group(index) — фрагмент совпавшей группы.
  • groupdict — словарь с группами и их значениями.
  • groups — все группы.
  • expand — производит замену в строку.

Всем методам есть одноименные функции. Также есть функция escape, которая экранирует переданную строку.

Операторы и выражения

Стандартные + - / * % и дополнительные ** (возведение в степень) и // (целая часть от деления)

print(1 + 1) # 2
print("one" + "one") # oneone print(1 - 1) # 0
print(4 / 2) # 2
print(2 * 2) # 4
print("one" * 2) # oneone print(4 % 3) # 1
print(2 ** 3) # 8
print(5 // 3 ) # 1

Побитовые « » & (and) | (or) ^ (xor) ~ (not)

print(0b1001 << 2) # 0b0100100 == 36 <=> n << x (n * (2 ** x))
print(0b1001 >> 2) # 0b0010 == 2
print(0b110 & 0b011) # 0b010 == 2
print(0b110 | 0b001) # 0b111 == 7
print(0b110 ^ 0b011) # 0b101 == 5
print(~ 0b011) # -0b100 == -4

Логические not or and

print(0 and 1) # 0
print(0 or 1) # 1
print(not 0) # True

Математические операции присваивания могут быть в краткой форме.

a = 10
a += 10
print(a) # 20

Все операторы левоассоциативны. Оператор in проверяет на вхождение в последовательность.

print("a" in "abc") # True

Оператор not in проверяет на НЕ вхождение в последовательность.

print("d" not in "abc") # True

Условные операторы

Булевое значение возвращают операторы <, >, ==, != или <>, <=, =>, is, is not, in, not in Оператор if называется if-{block}.

if 1:
    print('Block' ' 1')

Используется вместе с необязательными elif-{block} и else-{block}

age = int(input("Enter your age\n"))

if age < 18:
    print("Учись")
elif age < 60:
    print("Работай")
else:
    print("Отдыхай")
    exit("Ok")

Есть цикл while-{block} для обхода последовательностей.

while True:
    age = int(input("Enter your age\n"))
    if age < 18:
        print("Учись")
    elif age < 60:
        print("Работай")
    else:
        print("Отдыхай")
        exit("Ok")

Может использоваться с else-{block}. Он выполнится, если не было операции break.

a = True

while a:
    a = bool(raw_input("Press Enter"))
else:
    exit("Enter pressed")

Цикл for-in-{block} также может использовать else-{block}. Цикл позволяет обходить коллекции.

for i in range(1, 12): # [1, 11]
    print(i)
else:
    print("Bye-bye")

Для прерывания цикла используется break, а для перехода к следующей итерации continue

for i in range(1, 100):
    if i > 10:
        break
    if i < 5:
        continue
    print i

Функции

Именные функции

Объявляется с помощью ключевого слова def.

def say_hi_to(person_name):
    print("Hi, " + person_name)

say_hi_to("Mike") # Hi, Mike

Область видимости локальна. Глобальныю переменную можно указать с помощью global. Функции можно вкладывать друг в друга. Чтобы указать переменную как переменную из внешней фукнции используется ключевое слово nonlocal.

x = 1

def glob_test():
    global x
    print(x)

def outer():
    y = 10

def inner():
    nonlocal y
    y = 30

print(y) # 10
inner()
print(y) # 30
glob_test() # 1
outer()

Функция globals возвращает словарь глобальных переменных, а locals — локальных. Значения аргументов по-умолчанию через знак равенства.

def egg(count = 10):
    print("You have {} eggs".format(count))

egg() # You have 10 eggs

Параметры могут быть ключевыми. То есть при вызове можно указать имя параметра.

egg(count=20) # You have 20 eggs

Можно определить функции с переменным числом параметров с помощью одинарной и двойной звездочки.

def echo(*argv, **named):
    for arg in argv:
        print(arg)

    for name in named:
        print("{name}:{value}".format(name=name, value=named[name]))

echo("Arg1", PI=3.14, e=2.7) # Arg1 PI:3.14 e:2.7

При этом из переменной, объявленной с одной звездочкой, будет образован кортеж, а с двумя — словарь. Чтобы объявить параметр, доступный только по ключу, его необходимо объявить после параметра со звездочкой.

def foo(normal, *any, required_name):
    pass

foo(1, required_name=12)

Можно комбинировать все эти типы параметров. Для возвращения значения используется return.

def sum(a, b):
    return a + b

Функция модет возвращать кортеж для дальнейшей распаковки. Указать тип аргумента можно через двоеточие, а возвращаемый тип с помощью стрелочки после объявления функции.

def sum(left: float, right: float) -> float:
    return left + right

Если начать функцию со строки, то она поместиться в свойство __doc__ и будет доступна при вызове help.

def sum(left: float, right: float) -> float:
    """
    Args:
       left: Float
       right: Float
    Returns: sum of arguments
    """

    return left + right

sum(1, 2)
help(sum)
print(sum.__doc__)
/usr/bin/python /test.py
Help on function sum in module __main__:
sum(left:float, right:float) -> float
    Args:
       left: Float
       right: Float
    Returns: sum of arguments


    Args:
       left: Float
        right: Float
    Returns: sum of arguments

Функции тоже являются объектом, поэтому их можно передать.

def sum(a, b):
    return a + b

def funcWith(f, a, b):
    return f(a, b)

print(funcWith(sum, 20 ,30)) # 50

Для того, чтобы распаковать кортеж или список в аргументы, используется звездочка.

print(funcWith(sum, *[20, 30])) # 50

Для того, чтобы распаковать словарь как имя аргумента и изначение используются двойные звездочки.

print(funcWith(sum, **{"a": 20, "b": 30})) # 50

Анонимные функции

Анонимные функции называются лямбда-функциями. Объявляются как lambda param1..paramN: returnvalue

print((lambda: 10 + 10)()) # 20
print((lambda a, b, *c: a - b + sum(c))(1, 2)) # -1

Как и в обычных функциях, параметры могут быть необязательными. Подобно обычным функциям могут буть многострочными.

Функции-генераторы

Функция-генератор возвращает новое вычисляемое значение для каждой итерации. Они поддерживают метод next.

Значение, которое возвращается для новой итерации стоит после ключевого слова yield.

def gen(a):
    for i in range(1, a):
        yield i

for i in gen(10):
    print(i)

Из одной функции генератора можно вернуть результат другой функции-генератора с помощью yield from.

def gen(a):
    for i in range(1, a):
        yield i

def gen2(a):
    for i in range(1, a):
        yield from gen(i)

for i in gen2(10):
    print(i)

Тогда сначала выполнится первая итерация верхней функции, а так для результата каждый из вложенной.

Декораторы функций

Python имеет встроенную поддрежку декорирования функций. Для этого необходимо объявить функцию, которая будет выступать декоратором (она принимает и возвращает декорируемую в качестве аргумента), а затем имя этой функции использовать в качестве аннотации к декорируемой.

def log(f):
    print(str(f) + " was called")
    return f

@log
def sum(a, b):
    return a + b

sum(2, 2) # <function sum at 0x10715d158> was called

Может быть более одной функции-декоратора. Вызов идет снизу вверх по объявленным декораторам.

Чтобы перехватить аргументы, функция декоратор должна возвращать третью функцию, которая ожидает аргументы.

def checktype(func):
    """
    Check types in annotation, if annotion is None, then skipped
    :param func: function
    :return: function
    """

    def inner(*args, **kwargs):
        if not kwargs:
            "Nothing to check. Use named arguments"

        for name, argtype in func.__annotations__.items():
            if name in kwargs:
                checkarg(kwargs[name],argtype)

        return func(*args, **kwargs)

    def checkarg(arg, argtype):
        assert type(arg) == argtype

    return inner

@checktype
def sqlen(l: str, r: str):
    if len(l) > len(r):
        return -1
    elif len(r) > len(l):
        return 1
    return 0

sqlen(l="String 1", r="String2")
# sqlen(l="String 1", r=10) # AssertionError

Вложенные функции

Функции можно вкладывать одну в другую. Внутренняя функция имеет доступ ко всем переменным внешней, но при этом не может их изменять.

def outer():
    x = 1

    def inner():
        print("x=" + str(x))

    inner()

outer() # x=1

Чтобы изменять функцию, нужно указать её как nonlocal.

def outer():
    x = 1

    def inner():
        nonlocal x
        print("x=" + str(x))
        x = 3

    inner()
    print("x=" + str(x))

outer() # x=1 # x=3

Аннотации функций

Функции могут содержать аннотации. С помощью них можно указать данные какого типа принимает функция, предназначение параметров и тип возвращаемого значения.

Аннотации к аргументу ставятся через двоеточие после имени аргумента (если есть значение по-умолчанию, то оно ставится после аннотации).

Аннотации к аргументу вызываются перед вызовом функции и сохраняются в свойство __annotation__ (словарь) по ключу, который является именем функции.

def sum(a: [int, str, "An integer"], b: 1 + 2):
    return a + b

print(sum.__annotations__) # {'a': [<class 'int'>, <class 'str'>, 'An integer'], 'b': 3}

Аннотация к возвращаемому значению ставится через ->, вызываeтся перед вызовом функции и хранится по ключу return.

def sum(a: [int, str, "An integer"], b: 1 + 2) -> 2 + 4:
    print(sum.__annotations__)
    return a + b

print(sum(1,2)) # {'return': 6, 'b': 3, 'a': [<class 'int'>, <class 'str'>, 'An integer']}

Модули

Модулем называется файл с функциями, который можно импортировать с помощью команды import. Это могут быть файлы с расширением .py, написанные на C модули или же один из встроенных модулей Python.

import sys
for path in sys.path:
    print(path)

Импорт модулей — дорогостоящая операция, чтобы быстро импортировать модули, то необходимо перевести их в байт-код. Такие файлы имеют расширение .pyc.

Можно импортировать только определенные переменные, а также сразу задать им псевдонимы с помощью команды from-import-as.

from sys import argv as args
from datetime import timedelta, time

print(args[0])

Каждый модуль имеет имя в переменной __name__.

__name__ = "MyModule"

По-умолчанию модуль называется __name__.

Чтобы определить собственный модуль необходимо создать файл с расширением .py.

Модуль должен лежать в том же каталоге, где он импортируется, либо в одном из каталого sys.path.

import Modulo

Modulo.echo(Modulo.__version)
> ls -1
Modulo.py
__pycache__
script.py

Чтобы импортировать все публичные методы и свойства модуля используется звездочка.

from Modulo import *

echo(10)
# echo(__version__)

Функция dir возвращает список всех идентификаторов для аргумента.

import Modulo
echo(dir(Modulo))
# ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '__version__', 'echo']

Без аргументов возьмется текущий модуль.

print(dir())
    # ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']

a = 1
print(dir())
# ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'a']

Пакетом называется каталог с модулями и специальным файлом __init__.py, который сообщает Python, что каталог является пакетом.

Доступ к модулям пакета осуществляются с помощью точек package1.package2.module.

from Step1.Module.yes import *

Чтобы импортировать модуль, который расположен в том же каталоге, необходимо имя модуля начать с точки.

from .Timer import *

Чтобы обратиться к родительсткому пакету используется две точки.

Файл __init__.py должен быть либо пустым, либо иметь код, который будет выполнятся при первом импорте из пакета.

Он может содержать. - Переменную __all__, которая является списком имен модулей, которые можно загрузить с помощью from package import *. - Можно использовать импорты, которые будут доступны как from package import *.

Чтобы повторно загрузить модуль необходимо воспользоваться функцией reload из модуля imp.

Структуры данных

Последовательности

К последовательностям относятся str, list, tuple, range, bytes и bytearray.

Python поддерживает позиционное присваивание.

one, two, three = 1, 2, 3

С его помощью можно поменять значения местами.

На самом деле правая часть позиционного присваивания неявно приводится к кортежу. По обе стороны могут находится любые последовательности. Чтобы передать в переменную несколько значений сразу используется звездочка, чтобы проигнорировать значение — нижнее подчеркивание.

a, _, *lst = 1, 2, 3, 4
print(a, lst) # 1, [3, 4]

Все указанные последовательности и строки обладают дополнительными свойствами сабскрипта. Отрицательный индекс берет значения с конца.

list = ["One", "Two", "Three"]
print(list[-1]) # Three

Брать срезы слева-направо, справа-налево с помощью двоеточия. Указать можно от начала или до конца.

При этом правое значение является не включительным.

listing = ["One", "Two", "Three", "Four"]
print(listing[:1]) # ['One']
print(listing[1:]) # ['Two', 'Three', 'Four']
print(listing[1:3]) # ['Two', 'Three']
print(listing[-1:]) # ['Four']

Можно указать шаг через еще одно двоеточие.

print(listing[::2]) # ['One', 'Three']
print(listing[1::2]) # ['Two', 'Four']

При полной вырезке создается копия, а не ссылка. При присваивании же создается ссылка.

# l = [1, 2, 3]
# l2 = l <=> l2 === l
# l3 = l[:] <=> l2 !== l

При итерировании последовательностей используется метод __next__ или функция next. Для всех последовательностей возвращается значение. А для словаря — значение ключа, так как словарь является отображением, а не последовательностью. Функция enumerate возвращает итератор, который на каждый вызов next возвращает кортеж ключ/значение.

for k, v in enumerate(range(1, 10)):
    print("{}: {}".format(k, v))

Для объединения последовательностей одного типа используется оператор +.

Функция map принимает функцию и последовательность, потом применяет функцию к каждому элементу.

Функция zip на каждой итерации возвращает кортеж элементов переданных последовательностей, которые находятся на одинаковом смещении.

Функция filter принимает функцию и последовательность, потом фильтрует последовательность с учетом переданной функции. Функция reduce принимает функцию и последовательность и/или начальное значение, потом сводит последовательность к единому значению с помощью переданной функции.

Существуют методы append, extend, insert, pop, remove, clear, index, count, reverse, reversed, shuffle, sort, join. Функции min, max, any.

Список

Список — содержит упорядоченный набор элементов. Задается с помощью квадратных скобок.

toBuy = ["Cheese", "Vine", "Bread", "Tomato", "Olive oil", "Salad"]

for product in toBuy:
    print(product)

Метод append добавляет элемент в конец списка.

toBuy.append("Gum")

Метод insert добавляет элемент на указанную позицию.

list = [1, 2, 3, 4, 5]
list.insert(2, 7)
print(list) # [1, 2, 7, 3, 4, 5]

Метод sort сортирует список.

toBuy.sort()
print(toBuy) # ['Bread', 'Cheese', 'Gum', 'Olive oil', 'Salad', 'Tomato', 'Vine']

Получить элемент можно с помощью сабскрипта из квадратных скобок.

print(toBuy[4]) # Salad

Чтобы создать пустой список используются пустые скобки или фукнция list.

print(list() == []) # True

Создать список можно также из генератора списков.

listOfInt = (int(elem) for elem in ["1", "2", "3", "4", "5"])

for unit in listOfInt:
    print(unit)

Кортеж

Кортежи похожи на списки, но при этом они неизменяемы. Отличие так же в том, что объявляется в круглых скобках.

toBuy = ("Cheese", "Vine", "Bread", "Tomato", "Olive oil", "Salad")
print(toBuy) # ('Cheese', 'Vine', 'Bread', 'Tomato', 'Olive oil', 'Salad')
print(toBuy[4]) # Olive oil

print(().count(toBuy)) # 0

Python распознает кортежи, даже если они не залючены в скобки.

tuple1 = 1, "Эби", True
print(tuple1)

Кортеж можно распаковать в несколько переменных.

age, name, is_a_girl = tuple1
print(name) # Эби

Чтобы получить кортеж с одним элементом нужно поставить после него запятую, иначе Python распознает просто скобки.

print(("Salad",)) # ('Salad',)

Range

Для цикла используется тип range. Но он создает все элементы сразу, так что для тонких мест следует использовать xrange, который создает поток.

for i in range(0, 1000000):
    pass

Диапазон имеет методы index, который возвращает индекс указанного элемента или возбуждает исключение ValueError, а также count, который возвращает количество элементов с переданным значением.

rng = range(2, 20, 4)

try:
    print(rng.index(1))
except ValueError:
    print("Единицы нет")

print(rng.count(1)) # 0

Множество

Чтобы использовать математические операции над множествами используется класс set.

Значения в множестве неупорядочены, но они не могут повторяться.

Для таких множеств определены операции & | и ^ -.

listing1 = [1, 2, 4, 6, 7]
listing2 = [3, 6, 9, 12]
print(set(listing1) & set(listing2)) # {6}
print(set(listing1) | set(listing2)) # {1, 2, 3, 4, 6, 7, 9, 12}
print(set(listing1) ^ set(listing2)) # {1, 2, 3, 4, 7, 9, 12}

Проверить вхождение ключа можно с помощью оператора in.

print(2 in listing1) # True
print(3 in listing1) # False

Для добавления одного элемента используется метод add, а для добавления списка метод update.

Можно применять функции сравнения == равенство, <= левое подмножество правого, < > >=.

Метод isdisjoint проверяет, что пересечение множеств пусто.

Неизменяемое множество — frozenset.

Словарь

Словарь — ассоциативный массив, указывается в фигурных скобках, ключ и значение через двоеточие.

dictionary = \
    {
        "Ключ 1": "Значение 1",
        "Ключ 2": "Значение 2"
    }

print(dictionary) # {'Ключ 1': 'Значение 1', 'Ключ 2': 'Значение 2'}
print(dictionary['Ключ 1']) # Значение 1

Для обхода в цикле с использованием ключей, необходимо указать ключи и значение через запятую с вызовом метода .items().

for key, value in dictionary.items():
    print("{}: {}".format(key, value))

Чтобы создать пустой словарь используются пустые скобки или фукнция dict.

print({} == dict()) # True

Наличие элемента проверяется с помощью оператора in.

print("Vasya" in {}) # False

Для получения списка ключей используется преобразование в список.

dst = {
    "Key1": "Value1",
    "Key2": "Value2",
}

print(list(dst)) # ['Key1', 'Key2']

Функия dict создает словарь из кортежа двух элементов. Статический метод dict.fromkeys создаст словарь с ключами и значениями None.

Метод copy копирует словарь, а не копирует ссылку при присвоении.

Метод get поддерживает значение по-умолчанию.

Метод keys возвращает все ключи.

Метод values возвращает все значения.

Метод items возвращает все ключи и значения в виде массива кортежей.

Метод popitem удаляет и возвращает произвольный кортеж из ключа и значения.

Генераторы списков

Для создания списков, заполненных по более сложным формулам можно использовать генераторы — выражения, позволяющие заполнить список по формуле.

Создать список с одинаковыми элементами можно умножив последовательность с одним элементом на желаемую длину.

print([1] * 3) # [1, 1, 1]

Генератор списков имеет вид [выражение for переменная in последовательность].

Здесь обходится последовательность, к каждой переменной применяется значение и записывается в результирующую последовательность.

print([i ** 2 for i in range(1, 4)]) # [1, 4, 9]

После последовательности можно добавить ограничитель if, который позволит добавить элемент только в случае выполнения условия.

print([ i ** 2 for i in range(1, 4) if i != 3]) # [ 1, 4]

Если разместить генератор списков внутри круглых скобок, то вернется итератор.

gen = (i ** 2 for i in range(1, 4) if i != 3)

for elem in gen:
    print(elem)

В фигурных скобках будет создано множество.

print({i for i in [1, 2, 2, 3]}) # {1, 2, 3}

В фигурных скобках, когда выражение через двоеточие будет создан словарь.

print({ ord(str(i * 2)): i for i in [1, 2, 2, 3]}) # {50: 1, 52: 2, 54: 3}

ООП

Основы

Класс создается с помощью ключевого слова class.

class Person:
    pass

Класс тоже может иметь описание.

class Person:
    """Person template"""
    pass

print(Person.__doc__) # Person template

Методы класса обязаны иметь в качестве первого аргумента слово self. При этом передавать его не нужно, это автоматически сделает Python.

class Person:
    def say(self, message):
        print(message)

Person().say("Hi") # Hi

Создается новый экземпляр через вызов имени класса.

Self является указателем на экземпляр внутри класса.

Подобно функциям, классы можно задекорировать с помощью функций декораторов.

def echo_class_name(C):
    print("Initialize class " + str(C))

    return C

@echo_class_name
class A:
    pass

A() # Initialize class <class '__main__.A'>

Конструктор и деструктор

За инициализацию отвечает метод __init__. В нем мы можем присваивать значения необъявленным свойствам, таким образом объявляя их.

class Person:
    def __init__(self, name):
       self.name = name

mike = Person("Mike")
print(mike.name) # Mike

Деструктором является метод __del__.

class Person:
    population = 0

    def __init__(self, name):
        self.name = name
        Person.population += 1

    def __del__(self):
          Person.population -= 1

Person("Mike")
jane = Person("Jane")
print(Person.population) # 2
del jane
print(Person.population) # 1

Методы класса и объекта

Статический метод можно создать с помощью декоратора @staticmethod или вызова одноименной функции в теле класса.

class Person:
    """Person template"""
    population = 0
    def __init__(self, name):
       self.name = name
       Person.population += 1
    def __del__(self):
        Person.population -= 1

    def make_more():
        Person.population += 1

    make_more = staticmethod(make_more)

    @staticmethod
    def more_more():
          Person.population += 2

Person.make_more()
print(Person.population) # 1
Person.more_more()
print(Person.population) # 3

Существует две области видимости для методов и свойств. Публичные — по-умолчанию и приватные — начинаются с двойного знака подчеркивания.

class Person:
    """Person template"""
    def __init__(self, name, phone_number):
        self.name = name
        self.__phone = phone_number

    def get_phone(self):
        return self.__append7()

    def __append7(self):
        return "7" + self.__phone

mike = Person("Mike", "9114445566")
# print(mike.__phone) AttributeError: 'Person' object has no attribute '__phone'
# print(mike.__append7()) AttributeError: 'Person' object has no attribute '__append7'

Наследование

Для наследования указывается родительский класс в скобках после имени текущего класса.

class Human:
    def __init__(self, age):
        self.age = age

class Person(Human):
    def __init__(self, name):
        self.name = name
        Human.__init__(self, 0)

mike = Person("Mike")
print(mike.age)

Поддерживается множественное наследование.

class Human:
    def __init__(self, age):
        self.age = age

class Man:
    def __init__(self):
        self.voice = "Min"

class Person(Human, Man):
    def __init__(self, name):
           self.name = name
           Human.__init__(self, 0)
           Man.__init__(self)

Поиск методов начинается с базового класса, переходя к родительским в порядке их объявления.

class Human:
    def voice(self):
        print("Human")

class Man:
    def voice(self):
        print("Man")

class Person(Human, Man):
    pass

mike = Person()
mike.voice() # Human

Обратиться к родительскому классу можно с помощью метода super, по имени родительского класса.

class ParentCls:
    def run(self):
        print("Parent")

class AnotherParentCls:
    def run(self):
        print("AnotherParent")

class Cls(ParentCls, AnotherParentCls):
    def run(self):
        super().run()
        AnotherParentCls.run(self)

cls = Cls()
cls.run()
# Parent
# AnotherParent

Базовые классы хранятся в статическом свойстве __bases__.

class Cls(ParentCls, AnotherParentCls):
    def run(self):
        print(Cls.__bases__) # (<class '__main__.ParentCls'>, <class '__main__.AnotherParentCls'>)

Цепочка наследования хранятся в статическом свойстве __mro__. На основании множественного наследования используется механизм примесей mixin. Используется как трейты.

Специальные методы

  • __call__ — вызов объекта как вызов функции.
  • __getattribute__ — аналог одноименной функции. Перехватывает обращение к атрибутам.
  • __setattr__ — аналог одноименной функции. Перехватывает обращение к атрибутам.
  • __delattr__ — аналог одноименной функции. Перехватывает обращение к атрибутам.
  • __len__ — вызывается при вызове функции len на объекте или вместо bool, если она не определена.
  • __bool__ — вызывается при вызове функции bool.
  • __int__ — вызывается при вызове функции int.
  • __float__ — вызывается при вызове функции float.
  • __complex__ — вызывается при вызове функции complex.
  • __round__ — вызывается при вызове функции round.
  • __index__ — вызывается при вызове функций bin, hex, oct.
  • __repr__ и __str__ — вызывается при вызове функций repr и str.
  • __hash__ — используется, если класс участвует в качестве ключа словаря.
  • __add__ — вызывается при сложении.
  • __radd__ — вызывается при сложении, когда экземпляр справа.
  • __iadd__ — вызывается при присваивании +=.
  • __sub__, __rsub__, __isub__ — вызывается при операциях вычитания.
  • __mul__, __rmul__, __imul__ — вызывается при операциях умножения.
  • __truediv__, __rtruediv__, __itruediv__ — вызывается при операциях деления.
  • __floordiv__, __rfloordiv__, __ifloordiv__ — вызывается при операциях деления с округлением.
  • __mod__, __rmod__, __imod__ — вызывается при операции нахождения остатка от деления.
  • __pow__, __rpow__, __ipow__ — вызывается при операции возведения в степень.
  • __neg__ — унарный минус.
  • __pos__ — унарный плюс.
  • __abs__ — вызывается при вызове функции abs.
  • __invert__ — двоичная инверсия ~.
  • __and__, __rand__, __iand__ — двоичное И &.
  • __or__, __ror__, __ior__ — двоичное ИЛИ &.
  • __xor__, __rxor__, __ixor__ — двоичное исключающее ИЛИ ^.
  • __lshift__, __rlshift__, __ilshift__ — сдвиг влево «.
  • __rshift__, __rrshift__, __irshift__ — сдвиг вправо ».
  • __eq__ — сравнение на равенство ==.
  • __ne__ — сравнение на неравенство !=.
  • __lt__ — сравнение на меньше <.
  • __gt__ — сравнение на больше >.
  • __le__ — сравнение на меньше или равно <=.
  • __ge__ — сравнение на больше или равно >=.
  • __contains__ — проверка на вхождение in.

Абстрактные методы

Единственный способ сделать метод абстрактным — это бросать в нем исключение.

Можно задекорировать метод и использовать аннотацию.

Это уже сделано в модуле abc с помощью функции-декоратора abstractmethod.

Доступ к свойствам

В конструкторе объявляются свойства экземпляра. А в классе переменные принадлежат всему классу (статические свойства).

class Person:
    population = 0

    def __init__(self, name):
        self.name = name
        Person.population += 1

print(Person.population) # 0
Person("Mike")
Person("Jane")
print(Person.population) # 2

Для доступа к атрибутам (свойствам) могут использоваться функции. getattr - получить атрибут объекта или значение по-умолчанию. setattr - установить значение для атрибута объекта, возможно несуществующего. delattr - удалить значение для атрибута объекта. hasattr - проверить атрибут объекта на существование.

class Cls:
    def __init__(self):
        self.prop = 1

obj = Cls()
print(getattr(obj, 'prop')) # 1
print(getattr(obj, 'prop2', 0)) # 0
setattr(obj, 'prop2', 1)
print(getattr(obj, 'prop2')) # 1
delattr(obj, 'prop')
print(getattr(obj, 'prop', 0)) # 0
print(hasattr(obj, 'prop')) # False

Можно объявить сеттер, геттер и удалитель одной функцией property.

class Cls:
    def __init__(self):
        self.__secret_var = 0

    def get_secret_var(self):
        print("Getter")
        return self.__secret_var

    def set_secret_var(self, v):
        print("Setter")
        self.__secret_var = v

    def del_secret_var(self):
        print("Delete")
        del self.__secret_var

    var = property(get_secret_var, set_secret_var, del_secret_var, "Documentation")

cls = Cls()
cls.var = 10 # Setter
cls.var # Getter
del cls.var # Delete

Или заменить это все функциями-декораторами var_name.getter, var_name.setter и var_name.deleter.

class Cls:
    def __init__(self):
        self.__secret_var = 0

    @property
    def var(self):
        print("Getter")
        return self.__secret_var

    @var.setter
    def var(self, v):
        print("Setter")
        self.__secret_var = v

    @var.deleter
    def var(self):
        print("Delete")
        del self.__secret_var

cls = Cls()
cls.var = 10 # Setter
cls.var # Getter
del cls.var # Delete

Данные свойства можно объявить абстрактными.

Исключения

Обработка исключений производится с помощью оператора try-except-else. Можно обработать любую ошибку, кроме синтаксической.

try:
    pass
except EOFError:
    print("EOF???")
else:
    print("Исключения не произошло")

Блок else выполняется если ошибки не происходит.

Можно обработать несколько типов исключений сразу, перечислив их в скобках.

try:
    pass
except (ValueError, NameError):
    pass

Можно определить исключение в переменную с помощью оператора as.

try:
    pass
except (ValueError, NameError) as e:
    print(e)

Чтобы создать собственный тип исключения, нужно отнаследоваться от класса Exception.

class MyException(Exception):
    pass

Чтобы бросить исключение используется оператор raise.

try:
    raise MyException
except MyException:
    print("MyException gotcha”)

Блок finally выполняется всегда.

try:
    raise MyException
except MyException:
    print("MyException gotcha")
finally:
    print("Finally block")

Получить информацию об исключении можно с помощью функции exc_info модуля sys.

Для удобного чтения полученного кортежа можно воспользоваться модулем traceback.

print(traceback.print_exception(sys.exc_info()))

Если в блоке except не указать тип исключения, то блок перехватывает все исключения.

Менеджеры контекста

Python поддерживает протокол менеджеров контекста. Протокол гарантирует выполнение завершающих действий.

Для работы с протоколом следует использовать инструкцию with-as. Формат:

with <Выражение> as <Переменная>, <Выражение> as <Переменная>:
        {block}

В начале вычисляется выражение, которое должно возвращать объект с методами __enter__ и __exit__.

  • __enter__ вызывается после создания объекта, возвращает значение, которое присваивается в переменную.
  • Потом вызывается блок внутри with.
  • При возникновении исключения, вызывается __exit__ с теми же аргументами, что возвращает функция exc_info модуля sys. Если исключение обработано, то возвращает True, иначе False и исключение передается вышестоящему обработчику.
  • __exit__ вызывается в любом случае, только в случае успеха все аргументы равны None.
class Cls:
    def __init__(self, value):
        self.value = value

    def __enter__(self):
        return self.value

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Exception")
        self.value = None
        return True

    def run(self):
        raise BaseException

def createCls(value):
    return Cls(value)

with createCls(10) as value:
    createCls(value).run() # Exception

Инструкция assert бросает AssertionError, если выражение справа не равно True.

try:
    assert False
except AssertionError:
    print("Error")

Итераторы, контейнеры и перечисления

Итераторы

Это классы, которые могут выступать как последовательности. Для того, чтобы определить итератор, необходимо определить в классе два метода.

  • __iter__ — говорит о том, что класс является итератором, должен вовращать сам экземпляр класса и выполнять все необходимые предустановки.
  • __next__ — вызывается при каждой итерации, должен возвращать очередное значение из последовательности, пока не возникнет исключение StopIteration.
class Iter:
    def __init__(self, max: int):
        self.__current = 0
        self.max = max

    def __iter__(self):
        return self

    def __next__(self):
        if (self.__current >= self.max):
            raise StopIteration
        self.__current += 1
        return self.__current

for cur in Iter(10):
    print(cur) # print from 1 to 10

Контейнеры

Классы, которые могут выступать как последовательности или отображения (словари).

  • __getitem__ — получение элемента по индексу или ключу (для отображений).
  • __setitem__ — присваивание элемента по индексу или ключу (для отображений).
  • __delitem__ — удаление элемента по индексу или ключу (для отображений).
  • __contains__ — вызывается при проверке на существование значения или ключа (для отображений) с помощью in и not in.
class Container:
    def __init__(self, content):
        self.content = content

    def __getitem__(self, index):
        return self.content[index]

    def __setitem__(self, key, value):
        self.content.extend(value)

    def __contains__(self, item):
        return self.content.__contains__(item)

cont = Container(["A", "B", "C"])
print(cont[1]) # B
cont[4] = "D"
print(cont[3]) # D
print("E" in cont) # False
print("E" not in cont) # True

Перечисление

Чтобы создать перечисление (enumeration) с целыми величинами необходимо наследовать класс от IntEnum из модуля enum.

Чтобы создать перечисление (enumeration) со скалярными величинами необходимо наследовать класс от Enum из модуля enum.

Перечисления обязаны хранить атрибуты, названные по разному, но значения могут быть неуникальными.

Чтобы утвердить, что значения уникальны используется декоратор класса @unique.

class PaymentType(enum.IntEnum):
    VISA = 1
    MASTER = 2
    MAESTRO = 3
    DINNERS = 4
    AMERICAN_EXPRESS = 5

Для того, чтобы создать экземпляр необходимо либо передать идентификатор в конструктор, либо использовать одно из значений.

print(PaymentType(1))
print(PaymentType.VISA)

Это делается благодаря базовому классу EnumMeta, в котором объявлена логика.

Кроме того, можно создать экземпляр с помощью синтаксиса словарей.

print(PaymentType['VISA'])

Из типа перечисления можно создать список его значение, обернув в list.

print(list(PaymentType)) #[<PaymentType.VISA: 1>, <PaymentType.MASTER: 2>, <PaymentType.MAESTRO: 3>, <PaymentType.DINNERS: 4>, <PaymentType.AMERICAN_EXPRESS: 5>]

IntEnum можно использовать как число.

Получить имя можно с помощью свойства name. Оно совпадает с именем переменной.

print(PaymentType.VISA.name) # VISA

Получить значение с помощью value.

print(PaymentType.VISA.value) # 1

Некоторые модули

Модуль Math

  • pi — возвращает число Пи.
  • e - значение числа Эйлера.
  • Есть функции sin, cos, tan, asin, acos, atan. degress — преобразует радианы в градусы. radians — преобразует градусы в радианы.
  • exp - экспонента (e ** x).
  • log — логарифм числа по основанию.
  • log10 — логарифм числа по основанию 10.
  • log2 — логарифм числа по основанию 2.
  • sqrt — квадратный корень.
  • ceil — округление до большего.
  • floor — округление до меньшего.
  • fmod — остатотк от деления.
  • fabs — модуль.
  • factorial — факториал числа.
  • fsum - точная сумма переданных чисел.

Модуль random

  • random — случайное число от 0 до 1.
  • seed — настройка генератора случайных чисел. Если первый параметр одинаковый, то при random число будет тоже.
  • uniform — число в диапазоне от и до.
  • randint — целое число в диапазоне от и до.
  • randrange — случайное число из последовательности. Аргументы как у range.
  • choice — случайное число из переданной последовательности. shuffle - перемешивает последовательность.
  • sample — возвращает список из указанного количества элементов переданной последовательности.

Модуль locale

Модуль используется для настройки локализации. Функция setlocale устанавливает локализацию для категории.

import locale
locale.setlocale(locale.LC_ALL, "ru_RU")

В качестве категории выступают константы. - locale.LC_ALL — все режимы. - locale.LC_COLLATE — сравнение строк. - locale.LC_CTYPE — перевод символов в нижний/верхний регистр. - locale.LC_MONETARY — отображение денежных единиц. - locale.LC_NUMERIC — форматирование чисел. - locale.LC_TIME — форматирование вывода даты и времени

Функция getlocale получает текущую локализацию для режима.

print(locale.getlocale()) # ('ru_RU', 'UTF-8')

Настройки локали можно получить с помощью функции localeconv.

Модуль hashlib

Модуль используется для хеширования строк. Есть функции md5, sha1, sha224, sha256, sha384 и sha512. Все они принимают последовательность байт.

print(hashlib.md5(b"password"))

Чтобы получить зашифрованную последовательность байт используются методы digest и hexdigest.

print(hashlib.md5(b"password").digest())

Передать последовательность можно с помощью метода update.

hash = hashlib.sha256()
hash.update(b"password")
print(hash.hexdigest())

Для создания устойчивого к взлому пароля используется функция pbkdf2_hmac.

Модуль itertools

Модуль содержит функции для работы с последовательностями.

  • count — создает бесконечную, монотонно-изменяющуюся последовательность.
for elem in itertools.count(1, 2):
    if elem > 1000:
        break print(elem)
  • cycle - бесконечно по кругу перебирает последовательность.
  • repeat — возвращает объект заданое количество раз.
for elem in itertools.repeat(1, 10):
    print(elem)
  • combinations — возвращает итератор с различными комбинациями элементов коллекции (как кортежи).
for comb in itertools.combinations("abcd", 3):
    print(comb)
  • combinations_with_replacement — возвращает итератор с различными комбинациями элементов коллекции (как кортежи), но здесь элемент может быть в кортеже с собой.
for comb in itertools.combinations_with_replacement("abcd", 3):
    print(comb)
  • permutations — аналог combinations.
  • product — кортеж из комбинации элементов одной или несколькоих последовательностей.
  • filterfalse — как функция filter, но ожидает значения false.
  • dropwhile — возвращает элементы, начиная с элемента, для которого функция вернет false.
  • takewhile — возвращает элементы, включая до элемента, для которого функция вернет false.
  • compress — фильтрует последовательность в соответствии с булевым значением из второй последовательности.
  • islice — возвращает итератор, для которого можно задать границы и шаг.
  • startmap — аналог map, но каждый элемент должен быть последовательностью.
  • zip_longest — аналог zip, но обходит все элементы, добавляя значение по-умолчанию.
  • accumulate — аналог reduce.
  • chain — принимает несколько последовательностей, при итерации поочередно возвращает их элементы.
  • chain.from_iterable — возвращает итератор последовательности, все элементы которой тоже являются последовательностью.

Модули для работы с датой и временем

Модуль time

  • time — timestamp с 1.01.1970г.
  • gmtime — возвращает struct_time объект переданного timestamp или текущего времени, если параметр не передан.
  • localtime — возвращает struct_time в локальном времени.
  • strftime — принимает формат и struct_time и возвращает строковое представление.
  • strptime — разбирает строку в указанном формате и возвращает объект struct_time.
  • asctime — возвращает сроку в формате ascii, принимает struct_time.
  • ctime — возвращает сроку в формате ascii, принимает timestamp.
  • sleep — используется для задержки скрипта (использует секунды).
  • mktime — принимает struct_time, а возвращает timestamp.
print(time.time()) # 1472475009.691453
print(time.gmtime()) # time.struct_time(tm_year=2016, tm_mon=8, tm_mday=29, tm_hour=12, tm_min=30, tm_sec=10, tm_wday=0, tm_yday=242, tm_isdst=0)
print(time.localtime()) # time.struct_time(tm_year=2016, tm_mon=8, tm_mday=29, tm_hour=12, tm_min=30, tm_sec=10, tm_wday=0, tm_yday=242, tm_isdst=0)
print(time.mktime(time.localtime())) # 1472475009.0

Объект struct_time имеет свойства.

  • tm_year — год
  • tm_mon — месяц
  • tm_mday — день месяца
  • tm_hour — час
  • tm_min — минуты
  • tm_sec — секунды
  • tm_wday — день недели (число)
  • tm_yday — день года
  • tm_isdst — флаг коррекции летнего времени

Модуль datetime

Модуль позволяет оперировать датой и временем. timedelta — класс, дата в виде количества дней, секунд и микросекунд. Экземпляр можно складывать с date и datetime.

print(timedelta(0, 10)) # 0:00:10
tenSeconds = timedelta(0, 10)
print(tenSeconds.days) # 0
print(tenSeconds.seconds) # 10
print(tenSeconds.microseconds) # 0

Над классом можно проводить арифметические операции + - / // : * и получать абсолютное значение с помощью abs.

Можно использовать операторы сравнения.

tenSeconds = timedelta(0, 10)
minTenSeconds = timedelta(0, -10)
print(tenSeconds - minTenSeconds) # 20 sec

date — класс, представление даты. Конструктор принимает год, месяц и день. Статический метод today возвращает текущую дату.

print(date.today()) # 2016-08-29

Статический метод fromtimestamp возвращает дату для timestamp.

print(date.fromtimestamp(sum(i for i in range(1, 50000)))) # 2009-08-11

Статический метод fromordinal возвращает дату, соответствующую количеству дней с первого года.

print(date.fromordinal(736150)) # 2016-07-05
print(date.today() + timedelta(1)) # Yesterday

Есть методы replace, strftime, isotime, ctime, timetuple, toordinal, weekday, isoweekday, isocalendar.

time — класс, представление времени. Коструктор принимает час, минута, секунда, микросекунда, tzinfo.

datetime — класс, представление даты и времени.

print(time(12, 23, 2, 189, timezone(timedelta(0, 3600)))) # 12:23:02.000189+01:00

Есть методы now, utcnow, fromtimestamp, utcfromtimestamp, fromordinal, combine, strptime, date, time, timetz, timestamp, replace, timetuple, utctimetuple, toordinal, weekday, isoweekday, isoformat, ctime, strftime.

tzinfo — абстрактный класс, отвечает за временную зону.

Модуль calendar

Модуль формирует календарь в определенном виде.

Calendar — базовый класс, который принимает в качестве аргумента номер первого дня недели.

(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7)

TextCalendar — выводит календать в виде текста.

LocaleTextCalendar — выводит календать в виде текста с учетом локали.

Имеют методы:

  • formatmonth — возвращает указанный месяц.
import calendar
cal = calendar.TextCalendar(calendar.MONDAY) print(cal.formatmonth(2016, 9))
# September 2016
# Mo Tu We Th Fr Sa Su # 1234 # 5 6 7 8 9 10 11 # 12 13 14 15 16 17 18 # 19 20 21 22 23 24 25 # 26 27 28 29 30
  • prmonth — выводит указанный месяц.
  • formatyear — возвращает указанный год.
  • pryear — выводит указанный год.
  • HTMLCalendar — выводит календать в виде HTML.
  • LocaleHTMLCalendar — выводит календать в виде HTML с учетом локали.

Дополнительно имеют метод formatyearpage.

Модуль timeit

Модуль используется для измерения времени выполнения программы или кода.

Измерения проводятся с помощью класса Timer.

В конструктор он принимает код, который будет исполнятся в качестве строки, код, который будт выполнен перед запуском таймера и необязательную функцию-таймер.

Получить время выполнения можно с помощью метода timeit, который принимает количество повторений.

from timeit import *

timer = Timer("""
[i for i in range(1, 9999999)]
""")

print(timer.timeit(5)) # 3.3326380960061215

Метод repeat запускает метод timeit указанное количество раз и возвращает результат.

Работа с файловой системой

Работа с файлами

  • open — открывает файл.
    • Первый аргумент принимает путь к файлу. Поддерживаются относительные и абсолютные пути. Слэши обрабатываются в соответствие с os.path.sep.
    • Второй параметр необязателен — mode. Он задает режим открытия.
      • r — только чтение (по-умолчанию). После открытия указатель в начале файла. Если файл не существует, возбуждается FileNotFoundError.
      • r+ — чтение и запись. Указатель в начале файла. FileNotFoundError.
      • w — только запись. Указатель в начале файла. Если файла нет, то он создается, иначе перезаписывается.
      • w+ — чтение и запись. Указатель в начале файла. Если файла нет, то он создается, иначе перезаписывается.
      • a — только запись. Указатель в конце файла. Если файла нет, то он создается.
      • a+ — чтение и запись. Указатель в конце файла. Если файла нет, то он создается.
      • x — создание файла для записи. Если есть, то FileExistsError.
      • x+ — создание файла для записи и чтения. Если есть, то FileExistsError.
      • b — файл будет открыт в бинарном режиме. Методы будут принимать и возвращать объекты типа bytes.
      • t — файл будет открыт в бинарном режиме. Методы будут принимать и возвращать объекты типа str. По-умолчанию.
    • При записи данных, информация записывается в буфер. Из буфера в файл данные будут записаны только после вызова метода flush или после закрытия файла. Третьим аргументом buffering можно указать размер буфера. Если будет 0, то данные в файл будут записаны сразу (только для бинарного режима).
      • Если будет 1, то данные в файл будут записаны построчно (только для тесктового режима).
    • Четвертым аргументом encoding можно указать кодировку.
    • Пятым аргументом error можно указать уровень обработки ошибок.
      • strict — при ошибке возбуждается исключение (по-умолчанию).
      • replace — неизвестный символ заменяется символом вопроса или символом с кодом \ufffd.
      • ignore — неизвестный символ будет проигнорирован.
      • xmlcharrefreplace — неизвестный символ заменяется последовательностью &#xxxx;.
      • backslashreplace — неизвестный символ заменяется последовательностью \uxxxx;.
    • Шестым аргументом newline задается режим обработки конца строк.
      • None — выполняется стандартная обрабока (для Windows при чтении \r\n преобразуется в \n, при записи наоборот).
      • “” — пустая строка. Обработка не осуществляется.
      • “<symbol>” — указанный символ считается концом строки.

После открытия файла функция open возвращает объект-дескриптор файла.

  • Метод close — закрывает файл.
  • Метод write — записывает переданную последовательность (str или bytes) в файл.
  • Метод writelines — записывает переданную последовательность (str или bytes) в файл.
  • Метод writable — проверка возможности записи.
  • Метод read — чтение данных. Можно передать количество считываемых данных.
  • Метод readline — считывает из файла одну строку при каждом вызове.
  • Метод readlines — считывает из файла все строки в список.
  • Метод __next__ — считывает из файла одну строку при каждом вызове.
  • Метод flush — принудительно записывает данные в файл.
  • Метод fileno — возвращает целочисленный дескриптор файла. 0 — stdin, 1 — stdout, 2 — stderr.
  • Метод truncate — обрезает файл до указанного количества символов или байт (для бинарного режима).
  • Метод tell — возвращает позицию указателя относительно начала файла.
  • Метод seek — устанавливает позицию, имеющую смещение (первый аргумент) относительно позиции (второй). Из модуля io доступны позиции:
    • SEEK_SET — начало файла
    • SEEK_CUR — текущая позиция
    • SEEK_END — конец файла.
  • Метод seekable — проверка на возможность перемещения указателя.

Помимо методов есть некоторые атрибуты.

  • name — имя файла
  • mode — режим открытия
  • closed — True, есть файл закрыт
  • encoding — кодировка
  • buffer — доступ к буферу. Можно, например, записать в буфер
sources_dir = 'sources'

file = open(sources_dir + "/test", "w+"); file.write("Hello")
file.close()

Модуль os

Модуль содержит низкоуровневые операции для работы с файлами.

Функциональность зависит от операционной системы.

Получить название можно из атрибута name.

import os
print(os.name)

Функция open открывает файл:

  • Путь к файлу.
    • Режим открытия, можно комбинировать несколько через бинарное ИЛИ.
      • os.O_RDONLY — чтение.
      • os.O_WRONLY — запись.
      • os.O_RDWR — чтение и запись.
      • os.O_APPEND — добавление в конец.
      • os.O_CREAT — создать файл, если он не существует.
      • os.O_EXCL — говорит, что изначально файл не должен существовать.
      • os.O_TEMPORARY — файл будет удален после закрытия.
      • os.O_SHORT_LIVED — что и os.O_TEMPORARY, но будет храниться в оперативной памяти.
      • os.O_TRUNC — очистить содержимое.
      • os.O_BINARY — бинарный режим.
      • os.O_TEXT — текстовый режим.
    • mode — восьмиричное число от 0o000 до 0o777.

Функция read читает из файла указанное число байт.

Функция write пишет из файл последовательность байт.

Функция close закрывает файл.

Функция lseek устанавливает указатель в позицию, возвращает новую позицию.

Функция dup возвращает дубликат файлового дескриптора.

Функция fdopen возвращает файл по дескриптору.

Класс StringIO позволяет работать со строкой как с файловым объектом. Все операции хранятся в оперативной памяти.

Методы подобны методам файла, имеется метод getvalue, который возвращает значение.

Для аналогичной работы с байтами используется класс BytesIO.

Функция getcwd возвращает текущий каталог (каталог, где находится файл).

print(os.getcwd()) # /Users/pavel/personal/python/Steps

Функция chdir — переходит в каталог.

os.chdir('/tmp')
print(os.getcwd()) # /private/tmp

Функция mkdir — создает каталог с правами доступа, указанными во втором аргументе с помощью восьмиричного значения.

Функция rmdir — удаляет пустой каталог.

Функция listdir — возвращает список файлов в каталоге.

Чтобы использовать специальные символы *, ? и [] используется функция glob из модуля glob.

Функция walk — возвращает итератор файлов в каталоге (может рекурсивно).

Чтобы удалить непустую папку используется функция rmtree из модуля shutil.

Функция normcase — преобразует переданный путь в тот вид, в котором используется в системе.

Для определения прав используется функция access, на принимает путь и режим. Возвращает True, если проверка успешна, иначе False. - os.F_OK — проверка наличия. - os.R_OK — проверка на права чтения. - os.W_OK — проверка на права записи. - os.X_OK — проверка на исполняемость.

Права можно изменить с помощью функции chmod. Она принимает путь и восьмиричные права.

Модуль shutil имеет методы для манипулирования файлами.

Функция copyfile — копирует файл.

Функция copy — копирует файл вместе с правами доступа. Функция copy2 — копирует файл вместе с метаданными. Функция move — перемещает файл.

Функция rename — переименовывает файл.

Функции remove и unlink — удаляет файл.

Модуль os.path также имеет методы для манипулирования файлами.

Функция exists — проверка на существование.

Функция getsize — размер в байт.

Функция getatime — время последнего доступа, возвращает timestamp в секундах.

Функция getctime — время создания, возвращает timestamp в секундах.

Функция getmtime — время последнего изменения, возвращает timestamp в секундах.

Функция utime — обновить время последнего доступа и изменения, возвращает timestamp в секундах.

Функция abspath — вернет абсолютный путь.

Функция isabs — проверка, что путь — абсолютный.

Функция basename — вернет имя файла без пути до него.

Функция dirname — вернет путь до файла.

Функция split — вернет кортеж из пути и имени файла.

Функция splitdrive — вернет кортеж из пути до файла с именем и диска, на котором он лежит.

Функция splittext — вернет кортеж из имени файла и его расширения.

Функция join — объединяет в путь.

Функция isdir — проверяет, что строка ведет на каталог.

Функция isfile — проверяет, что строка ведет на файл.

Функция islink — проверяет, что строка ведет на ссылку.

Ввод и вывод

Функция print напрямую поддерживает перенаправление вывода с помощью аргумента f. Чтобы перенаправить ввод и вывод используются атрибуты модуля sys stdout, stdin, stderr.

import sys

logfile = './sources/log'
file = open(logfile, "a+");
sys.stderr = file
raise AssertionError

Чтобы проверить, ссылается ли на стандартный ввод на терминал, применяется метод stdin.isatty.

Сохранение объектов

Сохранить объекты в файл могут модули pickle и shelve.

pickle.dump — сохраняет объект (предустановленные в Python) в файл, открытый в бинарном режиме.

file = open('./sources/dump', "w+b")
pickle.dump([1, 2, 3], file)

pickle.load — загружает объект (предустановленные в Python) из файла, открытого в бинарном режиме. pickle.dumps — преобразует объект строку. pickle.loads — преобразует строку, созданную с помощью pickle.dumps в объект.

class Cls:
    def __init__(self):
        self.name = "Вася"

file = open('./sources/dump', "w+b")
pickle.dump(pickle.dumps(Cls()), file)
file.flush()
print(pickle.loads(pickle.load(open('./sources/dump', "r+b"))))

Тоже самое делает объект типа Pickler методами dump, load, dumps, loads.

shelve.open — открывает файл для хранения объектов. Возвращается отображение с объектами DbfilenameShelf. Можно указать режим открытия.

  • r - чтение.
  • w - чтение и запись.
  • c - если файл не существует, то будет создан (по- умолчанию).
  • n - если файл существует, то будет перезаписан.

shelve.DbfilenameShelf.close — закрывает файл. shelve.DbfilenameShelf.keys — получить ключи. shelve.DbfilenameShelf.values — получить значения. shelve.DbfilenameShelf.items — возвращает итератор с кортежем из ключа и значения. shelve.DbfilenameShelf.get — получить значение по ключу или по-умолчанию. shelve.DbfilenameShelf.setdefault — получить значение по ключу или установить. shelve.DbfilenameShelf.pop — удаляет элемент и возвращает его. shelve.DbfilenameShelf.popitem — удаляет произвольный элемент и возвращает кортеж из ключа и значения. shelve.DbfilenameShelf.clear — удаляет все элементы. shelve.DbfilenameShelf.update — обновляет файл.

import shelve
db = shelve.open("./sources/shelve")
db["first"] = ["one", "two", "three"]
db["second"] = {
    "Key1": "Value1"
}
db.update()
for key, value in db.items():
    print(str(key) + ": " + str(value))
    # second: {'Key1': 'Value1'}
    # first: ['one', 'two', 'three']

Работа с SQLite

DB-API

Работать с базой данных SQLite можно с помощью модуля sqlite3. Чтобы писать модули для взаимодействия с БД необходимо придерживаться DB-API.

Модуль sqlite имеет полезныем атрибуты apilevel (версия DB- API), sqlite_version или sqlite_version_info (версия модуля).

Последовательность работы с базой данных согласно DB-API 2.0:

  • Подлючение производится с помощью функции connect. Она должна возвращать объект соединения.
  • Создается объект-курсор.
  • Выполняются запросы, обрабатываются результаты.
    • Перед первым запросом запускается транзакция.
    • Завершается транзакция.
  • Закрывается объект-курсор.
  • Закрывается соединение.

С помощью функции set_trace_callback можно выполнить трассировку. Она принимает ссылку на функцию, которая принимать строку с SQL командой.

connection.set_trace_callback(lambda req: print(req))

Создание и открытие БД

Для создания и открытия служит функция connect, первым аргументом будет путь до базы данных.

import sqlite3

sources_dir = "./sources/"
connection = sqlite3.connect(sources_dir + 'python.db')

Можно указать значение memory:, тогда база будет создана в оперативной памяти.

Чтобы передать параметры при открытии используется синтаксис, как в GET запросе.

  • С помощью аргумента mode можно указать режим доступа.
    • ro — только чтение
    • rw — чтение и запись
    • rwc — чтение, запись и создание БД.
    • memory — аналог :memory:.
  • С помощью аргумента immutable отключаются все механизм транзакций, остается исключительно чтение.

Если база не существует, то она будет создана. Базу всегда нужно закрывать командой close.

connection.close()

Выполнение запросов

Согласно DB-API необходимо создать объект курсор, а все запросы пускать через него.

Создать объект курсор можно с помощью метода cursor объекта-соединения.

cursor = connection.cursor()

Чтобы выполнить несколько запросов, применяется метод executescript объекта-курсора.

По окончанию автоматически делает commit.

cursor.executescript("""
    create table if not exists product (
       id integer primary key autoincrement,
       name varchar(128) not null,
       price real default 0
    );

    insert into product(name, price)
        values ("Raspberry", 306.0), ("Watermelon", 11.2); """)

Чтобы выполнить один запрос, но при этом использовать биндинг применяется метод execute объекта-курсора.

Автоматически commit не делает.

Первым параметром передается запрос.

Все значения, которые нужно забиндить указываются как ?, если второй аргумент будет кортежем.

Указываются каr :<key>, если это будет словарь.

import sqlite3

sources_dir = "./sources/"
connection = sqlite3.connect(sources_dir + 'python.db')
cursor = connection.cursor()
cursor.execute("""
    insert into product(name, price) values (?, ?); """, ("Apple", 5.89))

cursor.execute("""
    insert into product(name, price) values (:name, :price); """, {"name": "Orange", "price": 7.66})

connection.commit()
cursor.close()
connection.close()

Чтобы завершить транзакцию нужно вызвать commit у объекта соединения.

Чтобы забиндить множественные параметры используется метод executemany объекта-курсора.

Автоматически commit не делает.

connection = sqlite3.connect(sources_dir + 'python.db')
cursor = connection.cursor()
cursor.executemany("insert into product (name, price) values (?, ?);", [
        ("Lemon", 5.67),
        ("Grapefruit", 4.44)
    ])
connection.commit()
cursor.close()
connection.close()

Объект соединения также имеет методы executescript, execute и executemany, но эти методы не входят в DB-API.

Объект-курсор имеет атрибуты lastrowid (индекс вставленной последней записи), rowcount (количество добавленных или удаленных методов), description (содержит кортеж кортежей с именем поля).

Обработка результата запроса

Метод fetchone при каждом вызове возвращает одну запись из результат запроса в виде кортежа и передвигает указатель на следующую запись.

cursor.execute("select * from product;")
print(cursor.fetchone()) # (35, 'Raspberry', 306.0)

Сам курсор является итератором, так что результаты можно обойти с помощью цикла.

for product in cursor:
    print(product)

Метод fetchmany возвращает переданное количество записей (по-умолчанию равно cursor.arraysize).

print(cursor.fetchmany(3)) # [(35, 'Raspberry', 306.0), (36, 'Watermelon', 11.2), (37, 'Apple', 5.89)]

Метод fetchall возвращает список всех полученных записей.

Объект-курсор имеет свойство row_factory. Этому свойству можно задать функцию обработчик, которая принимает объект-курсор первым аргументом и запись вторым.

import sqlite3

class Connection:
    def __init__(self, dbname):
        self.__connection = sqlite3.connect(dbname)
        self.cursor = self.__connection.cursor()
        self.cursor.row_factory = lambda cursor, line: Product(line[0], line[1], line[2])

    def execute(self, sql, params=()):
        self.cursor.execute(sql, params)
        self.__connection.commit()
        return self.cursor.fetchall()

class Product:
    def __init__(self, id, name, price):
        self.id = id
        self.name = name
        self.price = price

    def calculate(self, count):
        return self.price * int(count)

product = orm.product.Connection(sources_dir + 'python.db')

for product in product.execute("select * from product;"):
    print(product.calculate(10))

Атрибуту row_factory также можно присвоить ссылку на объект типа Row.

Объект типа Row поддерживает итерации, доступ по индексу и метод keys, который возвращает список с названиями полей.

sources_dir = "./sources/"
connection = sqlite3.connect(sources_dir + 'python.db')
cursor = connection.cursor()
cursor.row_factory = sqlite3.Row
cursor.execute("select * from product")
rows = cursor.fetchall()
print(len(rows)) # 20 (elements)

for row in rows:
    print(row[0]) # first db field
    print(row['naMe']) # 'name' db field (ignore case)
    print(row.keys()) # ['id', 'name', 'price'] field names

cursor.close()
connection.close()

Управление транзакциями

Управлять транзакциями можно с помощью параметра isolation_level функции connect. DEFERRED, IMMEDIATE, EXCLUSIVE — запустит транзакцию с соответствующим урованем.

None — транзакция запущена не будет.

Откатить изменения транзакции можно с помощью метода rollback объекта-соединения.

Свойство класса-соединения in_transaction передает информацию о том, осуществляется ли сейчас транзакция.

Пользовательские функции

С помощью метода create_collation объекта-соединения можно создать пользовательскую функцию сортировки.

Функция должна принимать две строки, возвращать -1, если первая больше, 0 при равенстве и 1, если больше правая.

Метод create_collation принимает первым аргументом название в SQL, вторым ссылку на функцию.

import sqlite3 sources_dir = "./sources/"

connection = sqlite3.connect(sources_dir + 'python.db')
cursor = connection.cursor()

def checktype(func):
    """
    Check types in annotation, if annotion is None, then skipped
        :param func: function :return: function
    """

    def inner(*args, **kwargs):
        if not kwargs:
        "Nothing to check. Use named arguments"

        for name, argtype in func.__annotations__.items():
            if name in kwargs:
                checkarg(kwargs[name],argtype)
                return func(*args, **kwargs)

        def checkarg(arg, argtype):
            assert type(arg) == argtype

        return inner

@checktype
def sqlen(l: str, r: str):
    if len(l) > len(r):
        return -1
    elif len(r) > len(l):
        return 1
    return 0

connection.create_collation("sqlen", sqlen)
cursor.execute("select * from product order by name collate sqlen")
rows = cursor.fetchall()
for row in rows:
    print(row)

"""
(36, 'Watermelon', 11.2)
(40, 'Grapefruit', 4.44)
(42, 'Grapefruit', 4.44)
(44, 'Grapefruit', 4.44)
(46, 'Grapefruit', 4.44)

(48, 'Grapefruit', 4.44)
(50, 'Grapefruit', 4.44)
(52, 'Grapefruit', 4.44)
(54, 'Grapefruit', 4.44)
(35, 'Raspberry', 306.0)
(55, 'Помидор', 14.55)
(38, 'Orange', 7.66)
(37, 'Apple', 5.89)
(39, 'Lemon', 5.67)
(41, 'Lemon', 5.67)
(43, 'Lemon', 5.67)
(45, 'Lemon', 5.67)
(47, 'Lemon', 5.67)
(49, 'Lemon', 5.67)
(51, 'Lemon', 5.67)
(53, 'Lemon', 5.67)
"""

cursor.close()
connection.close()

С помощью метода create_function объекта-соединения можно создать пользовательскую функцию.

Она принимает название функции, количество параметров и ссылку на функцию.

connection = sqlite3.connect(sources_dir + 'python.db')
cursor = connection.cursor()

def ten(a, b):
    if a > b:
        return 10
    return -10

connection.create_function('tens', 2, ten)

cursor.execute("SELECT tens(1, 2);")

print(cursor.fetchone()) # -10
cursor.close()
connection.close()

С помощью метода create_aggregate объекта-соединения можно создать пользовательскую агрегатную функцию.

Она принимает имя функции, количество параметров и сслыку на класс.

Класс должен реализовывать два метода step и finalize.

  • step — вызывается для каждой обрабатываемой записи, ему передаются параметры, колическтво которых задано.
  • finalize — возвращает результат выполнения
class SQLSum:
    def __init__(self):
        self.result = None

    def step(self, arg):
        if self.result is None:
            self.result = arg
            return

        self.result += arg

    def finalize(self):
        return self.result

connection.create_aggregate('mysum', 1, SQLSum)
cursor.execute("select mysum(name) from product;")

Преобразование типов

Каждому типу SQLite соответствует тип Python.

  • NULL - None
  • INTEGER — int
  • REAL — float
  • TEXT — str
  • BLOB — bytes

    Если необходимо сохранить в таблице данные, которые не поддеживаются SQLite, следует преобразовать тип самостоятельно.

Для этого с помощью функции register_adapter необходимо зарегистрировать пользовательскую функцию, которая будет вызываться при попытке вставке объекта в SQL.

Эта функция принимает в качестве аргументов тип данных и ссылку на функцию.

class Product:
    def __init__(self, name):
        self.name = name

sqlite3.register_adapter(Product, lambda p: p.name)
cursor.execute("insert into product (name, price) VALUES (?, ?);", (Product("Тыква"), 12.33))

Чтобы восстановить объект из записи, используется функция register_converter.

Первым аргументом является тип, используемый в SQLite, а вторым функция преобразования.

По умолчанию тип данных определяется при создании таблицы в параметре тип.

cursor.execute("""
    create table if not exists new_product(
        id integer primary key autoincrement,
        product product not null
    );
""")

Определение типа данных задается при создании подключения с помощью аргумента detect_types.

PARSE_COLNAMES — смотри на имена полей, если указано как <real_field> as ‘<alias> [<required_type>]'.

connection = sqlite3.connect(sources_dir + 'python.db', detect_types=sqlite3.PARSE_COLNAMES)

cursor.execute("select name as 'c [product]' from product;")

PARSE_DECLTYPES — по-умолчанию, с помощью имени типа при создании таблицы.

Для даты и времени из модуля datetime уже предусмотрены преобразователи данных.

cursor.execute("""
    create table product(
        id integer primary key autoincrement,
        name varying character (32) not null,
        created_at datetime not null
    );
""")
cursor.execute("insert into product(name, created_at) values (?, ?)", ("Watermelon", datetime.datetime.now()))
print(product) # (1, 'Watermelon', '2016-09-02 18:58:33.569139')

Разработка с серверными БД

Основные отличия

  • Используются специальные модули, которые реализуют DB-API.
  • При подключении указываются специальные параметры.

Взаимодействие с интернетом

URL

Манипулировать URL адресом можно с помощью модуля urllib.parse.

  • URL — ://:/;?#.
  • FTP — ://:@

Разобрать URL можно с помощью функции urlparse.

print(urllib.parse.urlparse("http://ya.ru?a=1&b=4")) # ParseResult(scheme='http', netloc='ya.ru', path='', params='', query='a=1&b=4', fragment='')

Вторым указывается протокол, который дут использован, есть в URL его нет.

Метод geturl объекта ParseResult возвращает строку с исходным URL.

print(urllib.parse.urlparse("http://ya.ru?a=1&b=4").geturl()) # http://ya.ru?a=1&b=4

Собрать URL из кортежа можно с помощью функции urlunoparse.

Вместо urlparse можно воспользоваться функцией urlsplit. Помимо всего прочего, она не выделяет параметры.

print(urllib.parse.urlsplit("http://ya.ru?a=1&b=4")) # SplitResult(scheme='http', netloc='ya.ru', path='', query='a=1&b=4', fragment='')

Чтобы декодировать строку запроса нужно воспользоваться функцией parse_qs. Она принимает строку запроса, параметр keep_blank_values указать, что пустые значения тоже возвращать.

url = "param2=&param1=%D0%9F%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%801"

print(parse_qs(url)) # {'param1': ['Параметр1']}
print(parse_qs(url, keep_blank_values=1)) # {'param1': ['Параметр1'], 'param2': ['']}

Функция parse_qsl делает тоже самое, но возвращает не словарь, список кортежей пар.

print(parse_qsl(url, keep_blank_values=1)) # [('param2', ''), ('param1', 'Параметр1')]

Функция urlencode делает обратную операцию.

print(urlencode({"param1": "Параметр1", "param2": ""})) # param1=%D0%9F%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%801&param 2=

Если поставить параметр doseq в True, то для одного параметра можно будет добавить несколько значений.

print(
    urlencode(
        [("param1", ["Знач1", "Знач1"])],
        doseq=1
    )
) # param1=%D0%97%D0%BD%D0%B0%D1%871&param1=%D0%97%D0%BD%D0%B0%D1% 871

Функция quote кодирует строку. Функция quote_pluse кодирует строку, но ставит + для пробела.

print(quote("Строка 1")) # %D0%A1%D1%82%D1%80%D0%BE%D0%BA%D0%B0%201
print(quote_plus("Строка 1")) # %D0%A1%D1%82%D1%80%D0%BE%D0%BA%D0%B0+1

Функция quote_from_bytes кодирует последовательность байт. Функция unquote, unquote_plus, unquote_to_bytes декодирует строку.

Преобразовать относительную ссылку в абсолютную можно с помощью функции urljoin.

Она преобразует ссылку относительно текущего контекста подобно файловой системе, если бы хост был бы корневым каталогом.

url = "http://yandex.ru/news/bad.html"

print(urljoin(url, "good.html")) # http://yandex.ru/news/good.html
print(urljoin(url, "/good.html")) # http://yandex.ru/good.html
print(urljoin(url, "../search/good.html")) # http://yandex.ru/search/good.html
print(urljoin(url, "very/bad.html")) # http://yandex.ru/news/very/bad.html

HTML

Чтобы экранировать специальные символы HTML используется функция escape из модуля xml.sax.saxutils. Дополнительно ей можно передать словарь, по которому будут производится замены.

print(escape("<&>")) # &lt;&amp;&gt;

Обратная ей функция — unescape.

Обмен данными

Модуль http.client позволяет взаимодействовать по HTTP(s) методами GET, HEAD и POST.

За создание соединения ответственен класс HTTPConnection. Его конструктор принимает хост, порт и таймаут.

connection = HTTPConnection("http://suggest-maps.yandex.ru/")

Закрыть соединение можно с помощью метода close.

Метод request отправляет запрос. Он принимает метод, путь, тело запроса и заголовки,

connection.request(
    'GET',
    '/suggest-geo?' + urlencode(
        {
            'lang': 'ru-RU',
            'search_type': 'all', 'fullpath': 1,
            'v': 5,
            'part': 'Россия, Москва, улица Солженицына',
        }
    )
)

Метод getresponse возвращет результат в виде объекта типа HTTPResponse.

Метод read возвращает тело ответа.

Метод getheader возвращает запрошенный заголовок ответа или значение по-умолчанию.

Метод getheaders возвращает все заголовки ответа. Свойство status статус в виде числа.

Свойство reason статус в виде текста.

Свойство version содержит версию протокола HTTP.

connection = HTTPConnection("suggest-maps.yandex.ru", 80)
connection.request(
    'GET',
    '/suggest-geo?' + urlencode(
        {
            'lang': 'ru-RU',
            'search_type': 'all',
            'fullpath': "1",
            'v': "5",
            '_': 2315123,
            'part': 'Россия, Москва, улица Солженицына',
        }
    )
)

response = connection.getresponse()
print(response.read())

Свойство msg содержит объект сообщение.

Модуль urllib.request также предоставляет методы для работы с интернет.

Для выполнения запроса используется функция urlopen. Она принимает Url, данные, таймаут. В качестве URL может выступать объект Request. Если данные переданы, то это будет POST, иначе GET. Функция возвращает объект типа HTTPRequest.

from urllib.request import *
result = urlopen(
    Request(
        "http://suggest-maps.yandex.ru/suggest-geo?" + urlencode(
            {
                'lang': 'ru-RU',
                'search_type': 'all',
                'fullpath': "1",
                'v': "5",
                '_': 2315123,
                'part': 'Калинин',
            }
        )
    )
)

print(result) # <http.client.HTTPResponse object at 0x1031569e8>

HTTPResponse имеет метод read, который возвращает ответ.

print(result.read().decode("utf-8"))

Метод readline считывает одну строку на каждый вызов.

Метод readlines возвращает список.

HTTPResponse является итератором.

Метод info возвращает список заголовков.

Свойство code содержит код ответа.

Свойство msg содержит текстовый код ответа.