🚀 Как логировать без боли в Python
Как настроить логирование в Python один раз — и больше к этому не возвращаться.
Обычно начинающие разработчики либо используют
Что мы получаем:
* Удобный формат времени и уровня лога
* Защиту от дублирования логов (если модуль импортируется несколько раз)
* Готовность к масштабированию (можно легко добавить файл-логгер)
Если вы устали от
Пользуетесь ли вы встроенным
📲 Мы в MAX
👉@BookPython
Как настроить логирование в Python один раз — и больше к этому не возвращаться.
Обычно начинающие разработчики либо используют
print(), либо подключают logging, но каждый раз пишут кучу однотипного кода. Я так тоже делал. Но потом вывел себе простую универсальную схему, которую теперь кидаю в каждый новый проект:
import logging
def setup_logger(name: str) -> logging.Logger:
logger = logging.getLogger(name)
if not logger.hasHandlers():
logger.setLevel(logging.INFO)
handler = logging.StreamHandler()
formatter = logging.Formatter(
'%(asctime)s - %(levelname)s - %(name)s - %(message)s'
)
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
logger = setup_logger(__name__)
logger.info("Скрипт стартовал")
Что мы получаем:
* Удобный формат времени и уровня лога
* Защиту от дублирования логов (если модуль импортируется несколько раз)
* Готовность к масштабированию (можно легко добавить файл-логгер)
Если вы устали от
print(), просто сохраните себе этот сниппет — он сэкономит вам время и нервы.Пользуетесь ли вы встроенным
logging, или предпочитаете что-то вроде loguru?👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Существует два понятия с похожими названиями, которые легко перепутать: переопределение (overriding) и перегрузка (overloading).
Переопределение происходит, когда дочерний класс определяет метод, который уже был реализован в родительском классе, фактически заменяя его. В некоторых языках необходимо явно указывать, что метод переопределяется (например, в C# используется модификатор
Перегрузка, напротив, — это наличие нескольких функций с одним и тем же именем, но разными сигнатурами. Это поддерживается в таких языках, как Java и C++, и часто используется как способ предоставления значений по умолчанию:
Python не поддерживает поиск функций по сигнатурам, только по именам. Вы можете написать код, который явно анализирует типы и количество аргументов, но это обычно выглядит громоздко и не очень красиво:
Если вам нужны подсказки типов для такой реализации, модуль
📲 Мы в MAX
👉@BookPython
Переопределение происходит, когда дочерний класс определяет метод, который уже был реализован в родительском классе, фактически заменяя его. В некоторых языках необходимо явно указывать, что метод переопределяется (например, в C# используется модификатор
override), в других — это необязательно (в Java можно, но не обязательно использовать аннотацию @Override). В Python нет ни обязательного, ни стандартного способа обозначать такие методы (некоторые программисты применяют пользовательский декоратор @override, который ничего не делает, а служит только для читаемости кода).Перегрузка, напротив, — это наличие нескольких функций с одним и тем же именем, но разными сигнатурами. Это поддерживается в таких языках, как Java и C++, и часто используется как способ предоставления значений по умолчанию:
class Foo {
public static void main(String[] args) {
System.out.println(Hello());
}
public static String Hello() {
return Hello("world");
}
public static String Hello(String name) {
return "Hello, " + name;
}
}
Python не поддерживает поиск функций по сигнатурам, только по именам. Вы можете написать код, который явно анализирует типы и количество аргументов, но это обычно выглядит громоздко и не очень красиво:
def quadrilateral_area(*args):
if len(args) == 4:
quadrilateral = Quadrilateral(*args)
elif len(args) == 1:
quadrilateral = args[0]
else:
raise TypeError()
return quadrilateral.area()
Если вам нужны подсказки типов для такой реализации, модуль
typing предоставляет декоратор @overload, который можно использовать следующим образом:
from typing import overload
@overload
def quadrilateral_area(
q: Quadrilateral
) -> float: ...
@overload
def quadrilateral_area(
p1: Point, p2: Point,
p3: Point, p4: Point
) -> float: ...
👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
В Python оператор квадратных скобок
Необычность оператора
Что же передаётся в
Пример:
Объект
📲 Мы в MAX
👉@BookPython
[] можно переопределить, реализовав магический метод __getitem__. Это позволяет, например, создать объект, который виртуально содержит бесконечное количество повторяющихся элементов:
class Cycle:
def __init__(self, lst):
self._lst = lst
def __getitem__(self, index):
return self._lst[index % len(self._lst)]
print(Cycle(['a', 'b', 'c'])[100]) # 'b'
Необычность оператора
[] в Python в том, что он поддерживает особый синтаксис. Его можно использовать не только так: [2], но и так: [2:10], [2:10:2], [2::2] или даже [:]. Смысл такой записи — [start:stop:step], но в ваших собственных объектах вы можете использовать этот синтаксис как угодно.Что же передаётся в
__getitem__ в таких случаях? Объекты slice созданы специально для этого.Пример:
class Inspector:
def __getitem__(self, index):
print(index)
Inspector()[1]
# 1
Inspector()[1:2]
# slice(1, 2, None)
Inspector()[1:2:3]
# slice(1, 2, 3)
Inspector()[:]
# slice(None, None, None)
Inspector()[:, 0, :]
# (slice(None, None, None), 0, slice(None, None, None))
Объект
slice сам по себе ничего не делает — он просто хранит атрибуты start, stop и step:
s = slice(1, 2, 3)
print(s.start) # 1
print(s.stop) # 2
print(s.step) # 3
👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1