test_derived = Derived(12)
print(test_derived.calculate_sum())
— или можно вместо
Base.__init__(self, single_value, single_value)
писать
super().__init__(single_value, single_value)
— не называя специально родительский класс.
хак: многострочные комментарии пишутся с тремя кавычками в начале и в конце:
""" Multi-line comment
Second line
Third line
Blah-blah-blah """
Полиморфизм
— мы переопределяем поведение (отдельных) методов, унаследованных от родительского класса
например, переопределим метод «вычислить», заменив сложение на вычитание:
class Base:
def __init__(self, value_1, value_2):
self._value_1 = value_1
self._value_2 = value_2
def calculate(self):
return self._value_1 + self._value_2
class Derived(Base):
def calculate(self):
Return self._value_1 - self._value_2
test_derived = Derived(10, 2)
print(test_derived.calculate())
+ теперь мы можем сделать функцию, которая будет пользоваться одним и тем же интерфейсом, а реализация будет уже прописана внутри классов:
class Base:
def __init__(self, value_1, value_2):
self._value_1 = value_1
self._value_2 = value_2
def calculate(self):
return self._value_1 + self._value_2
class Derived(Base):
def calculate(self):
return self._value_1 - self._value_2
def print_calculation(object_to_calculate):
Print(object_to_calculate.calculate())
test_base = Base(10, 2)
test_derived = Derived(10, 2)
Print_calculation(test_base)
Print_calculation(test_derived)
можно переопределять операторы, например, «==» (сравнение) — ему соответствует метод __eq__():
class Class:
...
def __eq__ (self, other):
if other.a > self.a:
return True
else:
return False
instance_1 = Class(1, 2)
instance_2 = Class(1, 5)
if instance_1 == instance_2:
print("Equal")
==============
Марта — хакатон
PIP — установка модулей (скачивает и устанавливает):
pip install X
можно для конкретного проекта сделать тестовое окружение — виртуальный «контейнер», в котором будут именно те библиотеки именно в тех версиях, которые нужны.
virtualenv — более старый пакет
venv — более новый
pipenv — ещё один
venv:
на Linux:
pyvenv FOLDER_NAME
на Windows:
python3 -m venv FOLDER_NAME
— потом надо запустить FOLDER_NAME/Scripts/activate.bat
(потом надо будет запустить deactivate.bat, чтобы отключить и снова начать использовать дефолтный Питон)
в VK чтобы что-то вытянуть даже из публичной группы, нужно сначала зарегистрировать приложение в самом VK, там выдадут секретный ключ и что-то ещё
документация VK: https://vk.com/dev/
бота в Телеграме тоже нужно регистрировать в самом Телеграме — это делается через системного бота BotFather, который через команду /newbot выдаёт секретный токен для нашего бота.
документация Телеграма: core.telegram.org/api
работа с PostgreSQL в Питоне: библиотека psycopg2
ещё небольшой хак: если надо разбить строку в коде на две строки для красоты — если есть скобки, ничего не надо дополнительного, если нет скобок — надо в конце первой строки поставить обратный слэш («\»)
==============
Марта
модули GUI:
PyQt — см. отдельную презентацию…
WXPython (привязка для фреймворка WXWidgets):
— тоже надо ставить через PIP (wx)
— тоже есть графический редактор интерфейса
— можно не задавать абсолютные размеры, а создавать “sizer” (в PyQt то же самое называется “layout”), тогда всё будет перерастягиваться при изменении размеров окна, etc.
tkinter (Tk interface)
— Tk — ещё один фреймворк (изначально для языка Tcl — Тикль, Ти-си-эль, Так-тикль, Тикль-ток)
— не надо ставить через PIP, уже есть в Питоне в качестве базового пакета (в Python 3 называется tkinter)
— ещё есть редактор rapyd — тоже визуальный редактор интерфейса
общее по GUI:
у консольного приложения три потока (ввод, вывод, ошибка).
event loop (mainloop) — бесконечный цикл, который «слушает» входы и заканчивается, только когда вызывается закрытие окна приложения.
==============
Марта
Исключения
(тут есть полуофициальный туториал по исключениям в Питоне)
два способа обработки ошибок
— возврат кода ошибки (если ошибка вложена глубоко, нужно руками поднимать её наверх в основной код, где она будет отлавливаться)
— а есть try-catch (try-except на Питоне), который делает это сам — поднимает ошибку наверх, пока её не поймают
стандартные (встроенные) исключения, которые можно переопределять:
ValueError, IOError (→ OSError), Exception, … (полный список)
raise — поднимает нужное исключение «вручную».
def divide(left_value, right_value):
if right_value == 0:
raise IOError("Divide by zero")
return left_value / right_value
print(divide(4,0))
try:
print(divide(4,0))
except ValueError as exception:
print("Please do not divide by zero")
else:
print("Everything is fine")
— можно переопределить стандартное общее исключение Питона:
except Exception as exception:
print(exception)
или вообще просто
except:
print("Oops")
— есть ещё волшебное слово finally — этот (под)блок вызывается всегда, независимо от того, произошло исключение или нет (а также завершился ли участок кода естественным образом или вообще был прерван).
try:
…
except … as exception:
…
else:
…
finally:
print("Exiting")
— выполняется в любом случае, даже если что-то сломается по ходу обработки исключения — в отличие от просто того же кода, написанного после блока try!
Как обеспечить симметричность некоторых операций (e.g. открыли файл — потом надо закрыть)?
пример — работа с файлами:
file = open ("test.txt", 'w') # 'w' — открытие для записи; если файл есть, очищает его(!), если файла нет, создаёт его
file.write("Hello, World!")
file. close ()
— по идее, можно не закрывать, но:
close() увеличивает шансы, что произойдёт запись на жёсткий диск; мы удалим дескриптор из памяти ОС (иначе они могут кончиться); в следующий раз мы откроем файл уже точно в том же состоянии.
Существует концепция RAII (resource acquisition is initialization) — получение некоторого ресурса неразрывно совмещается с инициализацией объекта, а освобождение — с уничтожением объекта.
Ср. конструкторы и деструкторы в C++.
В Питоне деструкторов (в чистом виде) нет. Все экземпляры объектов лежат в памяти, пока сборщик мусора их не вычистит.
Но безопасная работа с симметричными операциями в Питоне есть, “context management”.
Блок with:
with open("test.txt", 'w'), as opened_file:
opened_file.write("Test line")
— делает обращение с файлом симметричным — т.е. обязательно вызывает close() после завершения всех операций (даже если исключение вылетит во время работы или даже мы аварийно завершим программу по Ctrl+C!)
with open("test.txt", ' a '), as opened_file:
opened_file.write(" \n Test line")
— дописывает строку к уже имеющемуся в файле тексту
with open("test.txt", 'w') as opened_file, open("test2.txt", 'w') as opened_file2:
opened_file.write("Test line")
opened_file2.write("Test line")
Для своего класса
Как сделать то же самое для своего класса — нужно переопределить __exit__():
clas ContextedClass:
def __enter__ (self):
print("Enter switched context")
return(self)
def __exit__ (self, exc_type, exc_value, traceback):
print("Left switched context")
with ContextedClass() as my_class:
raise IOError("Oops")
print("Hello")
print("Some other operations")
пояснения:
__ enter __() — то, что происходит, когда мы создаём экземпляр класса (при этом ещё __init__() выполняется) и работаем с ним через with (и только в этом случае); если мы просто создаём объект, будет выполнен только __init__()
__ exit __() — по сути, почти- деструктор
контекст — набор условий, состояний, окружений.
то же самое — ещё и с конструктором:
clas ContextedClass:
def __init__ (self, stored_value):
self._value = stored_value
def __enter__(self):
print("Enter switched context")
return(self) # если хотим, чтобы ещё работал конструктор, нужно ещё здесь вернуть обязательно экземпляр класса!
def __exit__ (self, exc_type, exc_value, traceback):
print("Left switched context")
with ContextedClass(42) as my_class:
raise IOError("Oops")
print("Hello")
print(my_class._value)
print("Some other operations")
— итого, если мы создаём экземпляр класса просто так, выполняется только __init__(). Если же мы создаём экземпляр класса через with, то выполняется и __init__(), и __enter__(), а после завершения работы ещё и обязательно __ exit __().