Что знаешь про агрегацию ?
Спросят с вероятностью 3%
Агрегация в ООП — это концепция, при которой один класс включает в себя другой класс в качестве части, но обе части могут существовать независимо друг от друга. Агрегация описывает "имеет-a" отношения между объектами, где один объект является контейнером или коллекцией для другого объекта, но не несет ответственности за его существование.
Рассмотрим простой пример с классами
В этом примере:
✅Класс
✅Класс
Оба объекта могут существовать независимо. Объект
Различие между агрегацией и композицией
✅Агрегация: Части могут существовать независимо. Если объект-контейнер удален, включенные объекты могут продолжать существовать.
✅Композиция: Части не могут существовать независимо. Если объект-контейнер удален, все включенные объекты также будут удалены.
Пример агрегации:
Пример композиции:
Преимущества
1️⃣Гибкость: Компоненты могут быть легко заменены или изменены без влияния на другие части системы.
2️⃣Повторное использование: Один и тот же объект может быть использован в нескольких агрегатах.
3️⃣Чистая архитектура: Способствует созданию более модульного и поддерживаемого кода.
Агрегация в ООП — это отношение, при котором один объект включает в себя другой, но оба объекта могут существовать независимо. Это полезно для создания гибкой и модульной архитектуры, где компоненты могут быть легко заменены или повторно использованы.
👉 Можно посмотреть Примеры как отвечают люди на этот вопрос, или перейти К списку 1096 вопроса на Python разработчика. Ставь 👍 если нравится контент
🔐 База собесов | 🔐 База тестовых
Спросят с вероятностью 3%
Агрегация в ООП — это концепция, при которой один класс включает в себя другой класс в качестве части, но обе части могут существовать независимо друг от друга. Агрегация описывает "имеет-a" отношения между объектами, где один объект является контейнером или коллекцией для другого объекта, но не несет ответственности за его существование.
Рассмотрим простой пример с классами
Person
и Address
:class Address:
def __init__(self, street, city):
self.street = street
self.city = city
def display(self):
return f"{self.street}, {self.city}"
class Person:
def __init__(self, name, address):
self.name = name
self.address = address # Агрегация
def display(self):
return f"{self.name} lives at {self.address.display()}"
# Создание объектов Address и Person
address = Address("123 Main St", "New York")
person = Person("John Doe", address)
print(person.display()) # Выведет: John Doe lives at 123 Main St, New York
В этом примере:
✅Класс
Address
определяет атрибуты улицы и города и метод для отображения адреса.✅Класс
Person
включает объект Address
в качестве атрибута.Оба объекта могут существовать независимо. Объект
Address
может существовать без объекта Person
, и наоборот.Различие между агрегацией и композицией
✅Агрегация: Части могут существовать независимо. Если объект-контейнер удален, включенные объекты могут продолжать существовать.
✅Композиция: Части не могут существовать независимо. Если объект-контейнер удален, все включенные объекты также будут удалены.
Пример агрегации:
class Engine:
def __init__(self, horsepower):
self.horsepower = horsepower
class Car:
def __init__(self, model, engine):
self.model = model
self.engine = engine # Агрегация
engine = Engine(150)
car = Car("Toyota", engine)
# Удаление объекта car не удаляет объект engine
del car
print(engine.horsepower) # Выведет: 150
Пример композиции:
class Engine:
def __init__(self, horsepower):
self.horsepower = horsepower
class Car:
def __init__(self, model, horsepower):
self.model = model
self.engine = Engine(horsepower) # Композиция
car = Car("Toyota", 150)
# Удаление объекта car также удаляет объект engine
del car
# Теперь доступ к engine невозможен
Преимущества
1️⃣Гибкость: Компоненты могут быть легко заменены или изменены без влияния на другие части системы.
2️⃣Повторное использование: Один и тот же объект может быть использован в нескольких агрегатах.
3️⃣Чистая архитектура: Способствует созданию более модульного и поддерживаемого кода.
Агрегация в ООП — это отношение, при котором один объект включает в себя другой, но оба объекта могут существовать независимо. Это полезно для создания гибкой и модульной архитектуры, где компоненты могут быть легко заменены или повторно использованы.
👉 Можно посмотреть Примеры как отвечают люди на этот вопрос, или перейти К списку 1096 вопроса на Python разработчика. Ставь 👍 если нравится контент
🔐 База собесов | 🔐 База тестовых
Что такое dependency injection ?
Спросят с вероятностью 3%
Внедрение зависимостей (Dependency Injection, DI) — это паттерн проектирования в ООП, который используется для уменьшения жесткой связи между компонентами системы и повышения их модульности и тестируемости. Зависимости (объекты, от которых зависит класс) передаются классу извне, а не создаются внутри класса.
Зачем он нужен?
1️⃣Ослабление связей: Уменьшает жесткую связь между классами, делая их более независимыми друг от друга.
2️⃣Повышение тестируемости: Позволяет легко заменять реальные зависимости на поддельные (mock) объекты во время тестирования.
3️⃣Гибкость и расширяемость: Облегчает изменение и замену зависимостей без необходимости изменять код класса.
Как он работает?
DI может быть реализован несколькими способами:
1️⃣Внедрение через конструктор (Constructor Injection):
Зависимости передаются через параметры конструктора.
2️⃣Внедрение через сеттер (Setter Injection):
Зависимости передаются через методы установки (сеттеры).
3️⃣Внедрение через интерфейс (Interface Injection):
В этом подходе используется интерфейс для предоставления зависимостей. Это менее распространенный метод в Python, так как язык не имеет явной поддержки интерфейсов как, например, Java.
Преимущества
1️⃣Уменьшение жесткой связи: Классы меньше зависят друг от друга, что упрощает их изменение и замену.
2️⃣Повышение модульности: Каждый компонент может быть разработан и протестирован отдельно.
3️⃣Легкость тестирования: Зависимости могут быть легко заменены на заглушки или mock-объекты во время тестирования, что делает тестирование проще и надежнее.
4️⃣Улучшенная читаемость и поддерживаемость: Четко видно, какие зависимости нужны классу, что делает код более понятным.
Недостатки
1️⃣Сложность настройки: Может потребоваться больше начальных настроек для передачи всех зависимостей.
2️⃣Понимание паттерна: Требуется понимание концепции DI для правильного использования, что может быть сложным для начинающих разработчиков.
Рассмотрим пример с веб-приложением, где у нас есть контроллер, который зависит от сервиса для обработки бизнес-логики:
Dependency Injection — это паттерн проектирования, который позволяет передавать зависимости классу извне, а не создавать их внутри класса. Это улучшает модульность, тестируемость и гибкость кода, уменьшая жесткую связь между компонентами системы.
👉 Можно посмотреть Примеры как отвечают люди на этот вопрос, или перейти К списку 1096 вопроса на Python разработчика. Ставь 👍 если нравится контент
🔐 База собесов | 🔐 База тестовых
Спросят с вероятностью 3%
Внедрение зависимостей (Dependency Injection, DI) — это паттерн проектирования в ООП, который используется для уменьшения жесткой связи между компонентами системы и повышения их модульности и тестируемости. Зависимости (объекты, от которых зависит класс) передаются классу извне, а не создаются внутри класса.
Зачем он нужен?
1️⃣Ослабление связей: Уменьшает жесткую связь между классами, делая их более независимыми друг от друга.
2️⃣Повышение тестируемости: Позволяет легко заменять реальные зависимости на поддельные (mock) объекты во время тестирования.
3️⃣Гибкость и расширяемость: Облегчает изменение и замену зависимостей без необходимости изменять код класса.
Как он работает?
DI может быть реализован несколькими способами:
1️⃣Внедрение через конструктор (Constructor Injection):
Зависимости передаются через параметры конструктора.
class Service:
def do_something(self):
return "Service is doing something."
class Client:
def __init__(self, service):
self.service = service
def perform_action(self):
return self.service.do_something()
# Внедрение зависимости через конструктор
service = Service()
client = Client(service)
print(client.perform_action()) # Выведет: Service is doing something.
2️⃣Внедрение через сеттер (Setter Injection):
Зависимости передаются через методы установки (сеттеры).
class Client:
def set_service(self, service):
self.service = service
def perform_action(self):
return self.service.do_something()
# Внедрение зависимости через сеттер
service = Service()
client = Client()
client.set_service(service)
print(client.perform_action()) # Выведет: Service is doing something.
3️⃣Внедрение через интерфейс (Interface Injection):
В этом подходе используется интерфейс для предоставления зависимостей. Это менее распространенный метод в Python, так как язык не имеет явной поддержки интерфейсов как, например, Java.
Преимущества
1️⃣Уменьшение жесткой связи: Классы меньше зависят друг от друга, что упрощает их изменение и замену.
2️⃣Повышение модульности: Каждый компонент может быть разработан и протестирован отдельно.
3️⃣Легкость тестирования: Зависимости могут быть легко заменены на заглушки или mock-объекты во время тестирования, что делает тестирование проще и надежнее.
4️⃣Улучшенная читаемость и поддерживаемость: Четко видно, какие зависимости нужны классу, что делает код более понятным.
Недостатки
1️⃣Сложность настройки: Может потребоваться больше начальных настроек для передачи всех зависимостей.
2️⃣Понимание паттерна: Требуется понимание концепции DI для правильного использования, что может быть сложным для начинающих разработчиков.
Рассмотрим пример с веб-приложением, где у нас есть контроллер, который зависит от сервиса для обработки бизнес-логики:
class OrderService:
def process_order(self, order_id):
return f"Processing order {order_id}"
class OrderController:
def __init__(self, order_service):
self.order_service = order_service
def handle_request(self, order_id):
return self.order_service.process_order(order_id)
# Внедрение зависимости через конструктор
order_service = OrderService()
order_controller = OrderController(order_service)
print(order_controller.handle_request(123)) # Выведет: Processing order 123
Dependency Injection — это паттерн проектирования, который позволяет передавать зависимости классу извне, а не создавать их внутри класса. Это улучшает модульность, тестируемость и гибкость кода, уменьшая жесткую связь между компонентами системы.
👉 Можно посмотреть Примеры как отвечают люди на этот вопрос, или перейти К списку 1096 вопроса на Python разработчика. Ставь 👍 если нравится контент
🔐 База собесов | 🔐 База тестовых
Тестирование ПО включает в себя множество различных типов тестов, каждый из которых предназначен для проверки различных аспектов приложения. Основные виды тестов, используемые в разработке:
unittest
, pytest
.pytest
, nose2
, unittest
.Ориентируется на результат выполнения функциональных задач.
pytest
, unittest
, Selenium для веб-приложений.pytest
.Примеры использования инструментов:
Юнит-тестирование с
pytest
# math_operations.py
def add(a, b):
return a + b
# test_math_operations.py
import pytest
from math_operations import add
def test_add():
assert add(1, 2) == 3
assert add(-1, 1) == 0
assert add(-1, -1) == -2
if __name__ == '__main__':
pytest.main()
Интеграционное тестирование с
pytest
# database_operations.py
def connect_to_db():
return "Connected to DB"
def get_data_from_db():
return {"data": "Sample data"}
# test_integration.py
import pytest
from database_operations import connect_to_db, get_data_from_db
def test_db_integration():
assert connect_to_db() == "Connected to DB"
data = get_data_from_db()
assert "data" in data
assert data["data"] == "Sample data"
ifittest, py== '__main__':
pytest.main()
Функциональное тестирование с Selenium
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
def test_google_search():
driver = webdriver.Chrome()
driver.get("https://www.google.com")
search_box = driver.find_element(By.NAME, "q")
search_box.send_keys("pytest")
search_box.send_keys(Keys.RETURN)
assert "pytest" in driver.title
driver.quit()
ifты: unitte== '__main__':
test_google_search()
Каждый вид тестирования играет важную роль в процессе обеспечения качества программного обеспечения. Выбор подходящего типа тестирования зависит от конкретных задач и этапа разработки, на котором находится проект. Использование различных инструментов и методов тестирования помогает выявлять ошибки, улучшать производительность и обеспечивать соответствие приложения требованиям пользователей.
Please open Telegram to view this post
VIEW IN TELEGRAM
mock
— это термин, который относится к созданию фиктивных объектов или имитаций для тестирования. Обычно означает использование библиотеки unittest.mock
, которая входит в стандартную библиотеку и предоставляет мощные инструменты для создания и управления mock-объектами.Позволяют изолировать тестируемый код от внешних зависимостей, таких как базы данных, сетевые соединения, файловые системы и другие ресурсы. Это делает тесты более надежными и позволяет тестировать только тот код, который непосредственно интересует разработчика.
Основные возможности:
Основные компоненты:
mock
— этдекоратор и контекстный менеджер: Используются для замены объектов на mock-объекты в определенном пространстве имен.MagicMock
класс: Расширяет Mock
и включает магические методы (например, getitem, setitem и т.д.).Примеры использования:
Пример создания mock-объекта
from unittest.mock import Mock
# Создание mock-объекта
mock_obj = Mock()
# Настройка возвращаемого значения для метода
mock_obj.some_method.return_value = 42
# Вызов метода
result = mock_obj.some_method()
print(result) # Вывод: 42
# Проверка вызова метода
mock_obj.some_method.assert_called_once()
Пример использования patch
from unittest.mock import patch
# Предположим, у нас есть функция, которая делает HTTP-запрос
def fetch_data():
import requests
response = requests.get("https://api.example.com/data")
return response.json()
# Тестируем функцию с использованием patch
@patch('requests.get')
def test_fetch_data(mock_get):
# Настройка mock-объекта
mock_response = Mock()
mock_response.json.return_value = {"key": "value"}
mock_get.return_value = mock_response
# Вызов тестируемой функции
result = fetch_data()
assert result == {"key": "value"}
# Проверка вызова mock-объекта
mock_get.assert_called_once_with("https://api.example.com/data")
# Запуск теста
test_fetch_data()
Пример использования MagicMock
from unittest.mock import MagicMock
# Создание MagicMock-объекта
mock_obj = MagicMock()
# Настройка возвращаемого значения для магического методаен.
3. `Magicmock_obj.__getitem__.return_value = "value"
# Вызов магического метода
result = mock_obj["key"]
print(result) # Вывод: value
# Проверка вызова магического метода
mock_obj.__getitem__.assert_called_once_with("key")
Преимущества:
Mock-объекты являются мощным инструментом для создания изолированных и надежных тестов в Python. Библиотека
unittest.mock
предоставляет все необходимые средства для создания и управления mock-объектами, позволяя эффективно тестировать код, избегая зависимости от внешних ресурсов и улучшая качество тестирования.Please open Telegram to view this post
VIEW IN TELEGRAM
pytest
— это популярный и мощный фреймворк для тестирования, который позволяет писать компактные и легко читаемые тесты. Он широко используется благодаря своей простоте, гибкости и поддержке различных расширений. Поддерживает как модульное, так и функциональное тестирование, предоставляя множество удобных инструментов для тестирования кода.Основные особенности
unittest
и другими фреймворками, что упрощает миграцию.Установка
pytest
Можно установить с помощью pip:
pip install pytest
Тестирование функции
Предположим, у нас есть простая функция для сложения двух чисел:
# math_operations.py
def add(a, b):
return a + b
Теперь напишем тест для этой функции с его использованием:
# test_math_operations.py
from math_operations import add
def test_add():
assert add(1, 2) == 3
assert add(-1, 1) == 0
assert add(-1, -1) == -2
Запуск тестов
Для него можно использовать команду
pytest
:pytest test_math_operations.py
pytest
автоматически найдет и выполнит все тесты, а затем выведет результаты на экран.Фикстуры (fixtures)
Позволяют задавать инициализацию, необходимую для тестов. Они могут использоваться для подготовки данных, создания объектов и других операций, которые нужны перед выполнением тестов.
# test_math_operations.py
import pytest
from math_operations import add
@pytest.fixture
def input_data():
return 1, 2
def test_add(input_data):
a, b = input_data
assert add(a, b) == 3
Параметризация тестов
Позволяет запускать один и тот же тест с разными наборами данных.
# test_math_operations.py
import pytest
from math_operations import add
@pytest.mark.parametrize("a, b, expected", [
(1, 2, 3),
(-1, 1, 0),
(-1, -1, -2),
])
def test_add(a, b, expected):
assert add(a, b) == expected
Плагины:
Поддерживает множество плагинов, которые расширяют его функциональность. Некоторые из популярных плагинов:
unittest.mock
для создания и управления mock-объектами.Пример использования плагина
pytest-cov
Для его установки:
pip install pytest-cov
Запуск тестов с генерацией отчета о покрытии:
pytest --cov=my_module test_my_module.py
pytest
— это мощный и гибкий фреймворк для тестирования, который упрощает написание и выполнение тестов. Благодаря простому синтаксису, поддержке фикстур, параметризации и плагинов, Позволяет эффективно автоматизировать процесс тестирования и обеспечивать высокое качество кода.Please open Telegram to view this post
VIEW IN TELEGRAM
Юнит-тестирование (unit testing) — это метод тестирования ПО, при котором отдельные модули или компоненты (юниты) программы проверяются на корректность их работы. Предназначены для проверки небольших, изолированных частей кода, таких как функции или методы классов, чтобы убедиться, что они работают правильно.
Особенности:
Преимущества:
Пример использования
unittest
Он является встроенным и предоставляет богатые возможности для написания и выполнения юнит-тестов.
Пример кода для юнит-тестирования:
Предположим, у нас есть модуль
math_operations.py
с функцией add
:# math_operations.py
def add(a, b):
return a + b
Теперь тест для этой функции:
# test_math_operations.py
import unittest
from math_operations import add
class TestMathOperations(unittest.TestCase):
def test_add(self):
self.assertEqual(add(1, 2), 3)
self.assertEqual(add(-1, 1), 0)
self.assertEqual(add(-1, -1), -2)
if __name__ == '__main__':
unittest.main()
Запуск тестов
Для него можно выполнить скрипт
test_math_operations.py
:python test_math_operations.py
Или использовать команду
unittest
из командной строки:python -m unittest test_math_operations.py
Использование
pytest
для юнит-тестированияПредлагает более лаконичный и мощный подход к юнит-тестированию.
# test_math_operations.py
from math_operations import add
def test_add():
assert add(1, 2) == 3
assert add(-1, 1) == 0
assert add(-1, -1) == -2
Запуск тестов с
pytest
Убедитесь, что он установлен. Вы можете установить его с помощью pip:
pip install pytest
Запуск тестов:
pytest test_math_operations.py
Юнит-тестирование — это важный метод тестирования, который помогает обеспечивать качество и надежность кода, проверяя отдельные модули или компоненты программы. Использование таких инструментов, как
unittest
и pytest
, позволяет автоматизировать процесс тестирования, выявлять ошибки на ранних стадиях разработки и уверенно вносить изменения в код.Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какой метод используется для чтения всего содержимого файла в Python?
Anonymous Quiz
61%
read()
6%
readline()
13%
readall()
20%
readlines()
Существует множество модулей и библиотек для тестирования, которые помогают автоматизировать процесс тестирования, обнаруживать ошибки и обеспечивать качество кода. Некоторые из наиболее популярных модулей и библиотек для тестирования:
Встроенные модули
import unittest
class TestMathOperations(unittest.TestCase):
def test_add(self):
self.assertEqual(1 + 1, 2)
if __name__ == '__main__':
unittest.main()
def add(a, b):
"""
Возвращает сумму a и b.
>>> add(1, 2)
3
>>> add(-1, 1)
0
"""
return a + b
if name == '__main__':
import doctest
doctest.testmod()
Внешние библиотеки
def add(a, b):
return a + b
def test_add():
assert add(1, 2) == 3
assert add(-1, 1) == 0
if name == '__main__':
import pytest
pytest.main()
nose
.unittest
и расширяет его возможности.import unittest
class TestMathOperations(unittest.TestCase):
def test_add(self):
self.assertEqual(1 + 1, 2)
if name == '__main__':
import nose2
nose2.main()
from hypothesis import given
from hypothesis.strategies import integers
def add(a, b):
return a + b
@given(integers(), integers())
def test_add(x, y):
assert add(x, y) == x + y
if name == '__main__':
import pytest
pytest.main()
4️⃣ mock (unittest.mock)
➕ Библиотека для создания фиктивных объектов и имитации поведения зависимостей.
➕ Включена в стандартную библиотеку Python начиная с версии 3.3 как unittest.mock.
import unittest
from unittest.mock import patch
def fetch_data():
# Представим, что эта функция делает запрос к внешнему API
return "Real data"
class TestFetchData(unittest.TestCase):
@patch('main.fetch_data', return_value="Mock data")
def test_fetch_data(self, mock_fetch):
result = fetch_data()
self.assertEqual(result, "Mock data")
if:
== 'main':
unittest.main()
[tox]
envlist = py36, py37, py38
[testenv]
deps = pytest
commands = pytest
coverage run -m pytest
coverage report
coverage html # Создает отчет в формате HTML
Выбор инструмента для тестирования зависит от ваших потребностей и предпочтений. Стандартные модули, такие как
unittest
и doctest
, предоставляют базовые возможности для тестирования, в то время как внешние библиотеки, такие как pytest
, nose2
и hypothesis
, предлагают более мощные и гибкие инструменты для написания и выполнения тестов. Использование библиотек для измерения покрытия кода, таких как coverage
, помогает убедиться, что ваш код полностью протестирован.Please open Telegram to view this post
VIEW IN TELEGRAM
Monkey patching — это техника программирования, при которой поведение библиотеки или модуля изменяется во время выполнения программы. Этот метод позволяет динамически изменять или расширять код, написанный другими разработчиками, без изменения исходного кода самой библиотеки или модуля.
Основные особенности:
Пример использования Monkey Patching
Оригинальная функция
Допустим, у нас есть модуль
math_operations.py
с функцией add
:# math_operations.py
def add(a, b):
return a + b
Monkey Patching
Изменить функцию
add
, чтобы она вместо сложения выполняла вычитание. Мы можем сделать это с помощью monkey patching:import math_operations
# Оригинальная функция
print(math_operations.add(5, 3)) # Вывод: 8
# Monkey patching
def new_add(a, b):
return a - b
math_operations.add = new_add
# После monkey patching
print(math_operations.add(5, 3)) # Вывод: 2
Пример с использованием стандартной библиотеки
Где изменим поведение метода
str.upper
:# Оригинальный метод
print("hello".upper()) # Вывод: HELLO
# Monkey patching
def new_upper(self):
return self.lower()
str.upper = new_upper
# После monkey patching
print("hello".upper()) # Вывод: hello
Применение Monkey Patching в тестировании
Часто используется в тестировании для имитации поведения зависимостей или для замены реальных объектов на фиктивные (mock) объекты.
import unittest
from unittest.mock import patch
class ExternalService:
def fetch_data(self):
# Представим, что эта функция делает запрос к внешнему API
return "Real data"
def process_data():
service = ExternalService()
return service.fetch_data()
class TestProcessData(unittest.TestCase):
@patch('__main__.ExternalService.fetch_data', return_value="Mock data")
def test_process_data(self, mock_fetch_data):
result = process_data()
self.assertEqual(result, "Mock data")
if __name__ == '__main__':
unittest.main()
В этом примере:
unittest.mock.patch
для замены метода fetch_data
класса ExternalService
на фиктивный метод, возвращающий "Mock data".process_data
возвращает подделанные данные вместо реальных данных.Предостережения при его использовании
Хотя monkey patching может быть полезным, оно также может привести к проблемам, если использовать его неправильно:
Monkey patching — мощная техника, которая позволяет динамически изменять поведение модулей и библиотек во время выполнения программы. Она может быть полезна для исправления ошибок, добавления функциональности или создания фиктивных объектов для тестирования. Однако использовать monkey patching следует осторожно, чтобы избежать проблем с отладкой и неожиданным поведением программы.
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что произойдет, если передать словарь в функцию с **kwargs в Python?
Anonymous Quiz
76%
Словарь будет распакован в именованные аргументы
5%
Произойдет ошибка времени выполнения
9%
Словарь будет преобразован в список
10%
Произойдет ошибка компиляции
Реализация тестов — важная часть процесса разработки программного обеспечения, которая помогает обеспечить корректность и надёжность кода. Для написания тестов обычно используется модуль
unittest
, который является стандартным модулем для тестирования и поставляется вместе. Другие популярные библиотеки для тестирования включают pytest
и nose
.Использование модуля
unittest
Предоставляет инструменты для создания и выполнения тестов. Давайте рассмотрим основные шаги для написания тестов с использованием
unittest
.Основные шаги для написания тестов:
unittest.TestCase
.test_
.assert
) используются для проверки условий, таких как assertEqual
, assertTrue
, assertFalse
, assertRaises
и другие.Примеры использования:
Допустим, у нас есть простая функция для сложения двух чисел:
# Пример функции в файле my_module.py
def add(a, b):
return a + b
Теперь мы напишем тесты для этой функции:
# Пример теста в файле test_my_module.py
import unittest
from my_module import add
class TestAddFunction(unittest.TestCase):
def test_add_integers(self):
self.assertEqual(add(1, 2), 3)
self.assertEqual(add(-1, 1), 0)
self.assertEqual(add(-1, -1), -2)
def test_add_floats(self):
self.assertAlmostEqual(add(1.1, 2.2), 3.3)
def test_add_strings(self):
self.assertEqual(add('a', 'b'), 'ab')
if __name__ == '__main__':
unittest.main()
Запуск тестов
Тесты можно запускать разными способами. Вот несколько способов:
python -m unittest test_my_module.py
Просто запустите файл
test_my_module.py
как обычный Python-скрипт.python test_my_module.py
Использование
pytest
Это мощная библиотека для тестирования, которая упрощает написание и выполнение тестов. Она поддерживает функциональные и модульные тесты и имеет лаконичный синтаксис.
# Пример функции в файле my_module.py
def add(a, b):
return a + b
Запуск тестов с
pytest
Убедитесь, что
pytest
установлен. Вы можете установить его с помощью pip:pip install pytest
Запуск тестов:
pytest test_my_module.py
Преимущества:
Написание тестов — важная часть разработки программного обеспечения, которая помогает обнаруживать ошибки и обеспечивать качество кода. Для тестирования можно использовать стандартный модуль
unittest
или более мощную библиотеку pytest
. Основные шаги включают создание тестовых классов, написание тестовых методов, использование утверждений и запуск тестов. Выбор инструмента зависит от ваших предпочтений и требований проекта, но оба подхода обеспечивают эффективное тестирование вашего кода.Please open Telegram to view this post
VIEW IN TELEGRAM
Если не использовать конструкцию
with
, гарантировать закрытие файла можно несколькими способами, в частности, используя конструкцию try-finally
или модуль contextlib
.Использование
try-finally
Позволяет обеспечить закрытие файла даже в случае возникновения исключения. В блоке
finally
можно указать код, который должен выполниться независимо от того, было ли исключение в блоке try
или нет.file = open('example.txt', 'r')
try:
content = file.read()
print(content)
finally:
file.close()
В этом примере:
try
.try
или нет, файл будет закрыт в блоке finally
.Использование модуля
contextlib
Предоставляет утилиты для работы с контекстными менеджерами. Одной из таких утилит является функция
contextlib.closing
, которая может быть использована для автоматического закрытия объекта, поддерживающего метод close
.from contextlib import closing
file = open('example.txt', 'r')
with closing(file) as f:
content = f.read()
print(content)
В этом примере:
closing
.with
завершается, closing
автоматически закрывает файл.Создание пользовательского контекстного менеджера
Также можно создать свой собственный контекстный менеджер с помощью класса, который реализует методы
__enter__
и exit.class FileManager:
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
def __enter__(self):
self.file = open(self.filename, self.mode)
return self.file
def __exit__(self, exc_type, exc_value, traceback):
self.file.close()
# Использование
with FileManager('example.txt', 'r') as file:
content = file.read()
print(content)
В этом примере:
FileManager
реализует методы enter и exit.Гарантировать закрытие файла можно несколькими способами, помимо использования конструкции
with
:try-finally
, чтобы файл всегда закрывался независимо от возникновения исключений.contextlib
и его утилиту closing
для автоматического закрытия файла.Эти методы обеспечивают надёжное управление ресурсами и предотвращают утечки ресурсов, которые могут возникнуть при некорректном закрытии файлов.
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что произойдет, если в Python вызвать функцию, использующую yield, но не пройти по итератору?
Anonymous Quiz
10%
возникнет исключение
16%
вернется None
25%
функция завершится без результата
50%
создастся генератор
Python предоставляет мощные встроенные функции и модули для работы с файлами. Основные операции включают открытие, чтение, запись и закрытие файлов.
Открытие файла
Файл можно открыть с помощью встроенной функции
open()
. Эта функция возвращает объект файла, который затем можно использовать для выполнения различных операций с файлом.Синтаксис функции
open()
:file_object = open(file_name, mode)
file_name
: Имя файла, который вы хотите открыть.mode
: Режим, в котором вы хотите открыть файл. Основные режимы включают:'r'
: чтение (по умолчанию)'w'
: запись (содержимое файла будет удалено)'a'
: добавление (новые данные будут добавлены в конец файла)'b'
: бинарный режим (добавляется к основному режиму, например 'rb'
или 'wb'
)Примеры:
Чтение файла
# Открытие файла в режиме чтения
with open('example.txt', 'r') as file:
content = file.read()
print(content)
Запись в файл
# Открытие файла в режиме записи
with open('example.txt', 'w') as file:
file.write('Hello, world!')
Добавление в файл
# Открытие файла в режиме добавления
with open('example.txt', 'a') as file:
file.write('\nAppended text.')
Чтение из файла
Файловый объект предоставляет несколько методов для чтения данных:
read(size=-1)
: Читает весь файл или size
байт, если указан.readline(size=-1)
: Читает одну строку или size
байт, если указан.readlines()
: Читает все строки файла и возвращает их в виде списка.Примеры:
Чтение всего файла
with open('example.txt', 'r') as file:
content = file.read()
print(content)
Чтение файла построчно
with open('example.txt', 'r') as file:
for line in file:
print(line, end='') # `end=''` чтобы избежать двойного переноса строки
Чтение файла в список строк
with open('example.txt', 'r') as file:
lines = file.readlines()
print(lines)
Запись в файл
Файловый объект также предоставляет методы для записи данных:
write(string)
: Записывает строку в файл.writelines(lines)
: Записывает список строк в файл.Примеры:
Запись строки в файл
with open('example.txt', 'w') as file:
file.write('Hello, world!')
Запись списка строк в файл
lines = ['First line\n', 'Second line\n', 'Third line\n']
with open('example.txt', 'w') as file:
file.writelines(lines)
Использование менеджеров контекста (
with
)Она автоматически закрывает файл после выхода из блока
with
, даже если возникло исключение.with open('example.txt', 'r') as file:
content = file.read()
print(content)
Закрытие файла
Если файл открыт без использования
with
, его нужно закрыть вручную с помощью метода close()
.file = open('example.txt', 'r')
content = file.read()
print(content)
file.close()
Дополнительные операции с файлами
Модуль
os
предоставляет функции для работы с файловой системой, такие как переименование, удаление и создание директорий.Примеры:
Переименование файла
import os
os.rename('example.txt', 'new_example.txt')
Удаление файла
import os
os.remove('new_example.txt')
Создание директории
import os
os.mkdir('new_directory')
Удаление директории
import os
os.rmdir('new_directory')
Python предоставляет богатые возможности для работы с файлами, начиная с простого чтения и записи и заканчивая сложными операциями с файловой системой. Использование менеджеров контекста (
with
) обеспечивает безопасное и эффективное управление файлами.Please open Telegram to view this post
VIEW IN TELEGRAM
Принцип SLAP (Single Level of Abstraction Principle) относится к принципам чистого кода и разработки программного обеспечения. Он заключается в том, что каждый метод или функция должны работать на одном уровне абстракции.
Помогает сделать код более читаемым, поддерживаемым и легким для понимания. Когда код организован таким образом, что каждая функция или метод выполняет задачи только на одном уровне абстракции, разработчики могут легче следить за логикой программы и быстрее находить ошибки.
При разработке ПО, вы должны стремиться к тому, чтобы методы и функции содержали действия только одного типа или уровня абстракции. Это может быть достигнуто через декомпозицию задач на более мелкие подзадачи и создание соответствующих методов для каждой подзадачи.
def process_order(order):
# Проверка наличия товара на складе
for item in order['items']:
if not warehouse_has_item(item):
raise Exception("Товара нет на складе")
# Расчет общей стоимости заказа
total_price = 0
for item in order['items']:
total_price += item['price'] * item['quantity']
# Создание записи в базе данных
save_order_to_db(order, total_price)
# Отправка уведомления клиенту
send_confirmation_email(order['customer_email'])
Эта функция выполняет несколько задач на разных уровнях абстракции: проверка наличия товара, расчет стоимости, работа с базой данных, отправка email. Это нарушает принцип SLAP.
def process_order(order):
check_items_availability(order['items'])
total_price = calculate_total_price(order['items'])
save_order(order, total_price)
notify_customer(order['customer_email'])
def check_items_availability(items):
for item in items:
if not warehouse_has_item(item):
raise Exception("Товара нет на складе")
def calculate_total_price(items):
total_price = 0
for item in items:
total_price += item['price'] * item['quantity']
return total_price
def save_order(order, total_price):
save_order_to_db(order, total_price)
def notify_customer(email):
send_confirmation_email(email)
Принцип SLAP означает, что каждая функция должна выполнять задачи только на одном уровне абстракции. Это делает код более чистым и легким для понимания.
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что произойдет, если в Python изменить ключ в dict во время итерации по нему?
Anonymous Quiz
17%
ничего не произойдет
17%
возникнет ошибка компиляции
23%
возникнет исключение RuntimeError
43%
значение ключа изменится
Кодовые метрики когезии (cohesion) и связи (coupling) играют ключевую роль в проектировании программного обеспечения. Давайте разберем их более подробно.
Когезия (Cohesion)
Это мера того, насколько сильно элементы внутри модуля связаны друг с другом. Высокая когезия означает, что элементы модуля работают вместе для выполнения одной задачи.
class Utility:
def calculate_tax(self, amount):
# Код для расчета налога
pass
def send_email(self, email, message):
# Код для отправки email
pass
def generate_report(self, data):
# Код для генерации отчета
pass
Этот класс выполняет несколько несвязанных задач, что снижает когезию.
class TaxCalculator:
def calculate_tax(self, amount):
# Код для расчета налога
pass
class EmailSender:
def send_email(self, email, message):
# Код для отправки email
pass
class ReportGenerator:
def generate_report(self, data):
# Код для генерации отчета
pass
Каждый класс выполняет одну четко определенную задачу, что повышает когезию.
Связь (Coupling)
Это мера зависимости между модулями. Низкая связь означает, что изменения в одном модуле минимально влияют на другие модули.
class OrderProcessor:
def __init__(self):
self.tax_calculator = TaxCalculator()
self.email_sender = EmailSender()
def process_order(self, order):
tax = self.tax_calculator.calculate_tax(order.amount)
self.email_sender.send_email(order.customer_email, "Order processed")
OrderProcessor сильно зависит от TaxCalculator и EmailSender.
class OrderProcessor:
def __init__(self, tax_calculator, email_sender):
self.tax_calculator = tax_calculator
self.email_sender = email_sender
def process_order(self, order):
tax = self.tax_calculator.calculate_tax(order.amount)
self.email_sender.send_email(order.customer_email, "Order processed")
В этом примере зависимости инъектируются через конструктор, что уменьшает связь между модулями и позволяет их легче тестировать и заменять.
Когезия делает модули логичными и понятными, а низкая связь позволяет модулям работать независимо друг от друга.
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какое значение имеет неинициализированная переменная в Python?
Anonymous Quiz
36%
None
17%
undefined
6%
null
40%
невозможно использовать неинициализированные переменные
Порождающий паттерн (creational pattern) — это тип шаблонов проектирования, который предоставляет различные способы создания объектов, помогая отделить логику создания объектов от их основного использования. Порождающие паттерны помогают сделать систему более гибкой и независимой от конкретных классов, которые она использует.
Гарантирует, что у класса есть только один экземпляр, и предоставляет глобальную точку доступа к этому экземпляру.
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance
# Использование
s1 = Singleton()
s2 = Singleton()
print(s1 is s2) # True
Определяет интерфейс для создания объектов, но позволяет подклассам изменять тип создаваемых объектов.
from abc import ABC, abstractmethod
class Product(ABC):
@abstractmethod
def operation(self):
pass
class ConcreteProductA(Product):
def operation(self):
return "Result of ConcreteProductA"
class ConcreteProductB(Product):
def operation(self):
return "Result of ConcreteProductB"
class Creator(ABC):
@abstractmethod
def factory_method(self):
pass
def some_operation(self):
product = self.factory_method()
return f"Creator: The same creator's code has just worked with {product.operation()}"
class ConcreteCreatorA(Creator):
def factory_method(self):
return ConcreteProductA()
class ConcreteCreatorB(Creator):
def factory_method(self):
return ConcreteProductB()
# Использование
creator = ConcreteCreatorA()
print(creator.some_operation())
creator = ConcreteCreatorB()
print(creator.some_operation())
Порождающие паттерны проектирования помогают создавать объекты в системе, абстрагируя логику их создания. Они делают код более гибким и независимым от конкретных классов, упрощая поддержку и расширение системы.
Please open Telegram to view this post
VIEW IN TELEGRAM