Паттерн "Стратегия" (Strategy) — это поведенческий паттерн проектирования, который определяет семейство алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми. Паттерн "Стратегия" позволяет изменять алгоритмы независимо от клиентов, которые их используют.
Паттерн включает следующие компоненты:
from abc import ABC, abstractmethod
# Интерфейс стратегии
class Strategy(ABC):
@abstractmethod
def sort(self, data):
pass
# Конкретные стратегии
class BubbleSortStrategy(Strategy):
def sort(self, data):
print("Sorting using Bubble Sort")
for i in range(len(data)):
for j in range(0, len(data)-i-1):
if data[j] > data[j+1]:
data[j], data[j+1] = data[j+1], data[j]
class QuickSortStrategy(Strategy):
def sort(self, data):
print("Sorting using Quick Sort")
self.quick_sort(data, 0, len(data) - 1)
def quick_sort(self, data, low, high):
if low < high:
pi = self.partition(data, low, high)
self.quick_sort(data, low, pi - 1)
self.quick_sort(data, pi + 1, high)
def partition(self, data, low, high):
pivot = data[high]
i = low - 1
for j in range(low, high):
if data[j] <= pivot:
i = i + 1
data[i], data[j] = data[j], data[i]
data[i + 1], data[high] = data[high], data[i + 1]
return i + 1
# Контекст
class SortingContext:
def __init__(self, strategy: Strategy):
self._strategy = strategy
def set_strategy(self, strategy: Strategy):
self._strategy = strategy
def sort(self, data):
self._strategy.sort(data)
# Клиентский код
data = [5, 2, 9, 1, 5, 6]
context = SortingContext(BubbleSortStrategy())
context.sort(data)
print(data) # [1, 2, 5, 5, 6, 9]
context.set_strategy(QuickSortStrategy())
data = [3, 7, 8, 5, 2, 1, 9, 5, 4]
context.sort(data)
print(data) # [1, 2, 3, 4, 5, 5, 7, 8, 9]
Недостатки:
Паттерн "Стратегия" является мощным инструментом для управления алгоритмами и их выбора в зависимости от конкретной ситуации, улучшая гибкость и расширяемость кода.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1👍1🤔1👾1
Anonymous Quiz
6%
GIL отсутствует в последних версиях CPython
12%
GIL позволяет нескольким потокам Python выполняться параллельно на нескольких ядрах процессора
13%
GIL нужен для управления памятью и предотвращения утечек памяти
69%
GIL блокирует выполнение всех потоков Python, кроме одного, в любой момент времени
Паттерн "Шаблонный метод" (Template Method) — это поведенческий паттерн проектирования, который определяет скелет алгоритма в методе, оставляя некоторые шаги подклассам. Подклассы могут переопределять эти шаги, не изменяя структуру алгоритма.
Паттерн включает следующие компоненты:
from abc import ABC, abstractmethod
# Абстрактный класс с шаблонным методом
class Beverage(ABC):
def prepare_recipe(self):
self.boil_water()
self.brew()
self.pour_in_cup()
self.add_condiments()
def boil_water(self):
print("Boiling water")
def pour_in_cup(self):
print("Pouring into cup")
@abstractmethod
def brew(self):
pass
@abstractmethod
def add_condiments(self):
pass
# Конкретный подкласс для кофе
class Coffee(Beverage):
def brew(self):
print("Dripping Coffee through filter")
def add_condiments(self):
print("Adding Sugar and Milk")
# Конкретный подкласс для чая
class Tea(Beverage):
def brew(self):
print("Steeping the tea")
def add_condiments(self):
print("Adding Lemon")
# Клиентский код
def prepare_beverage(beverage: Beverage):
beverage.prepare_recipe()
coffee = Coffee()
tea = Tea()
print("Making coffee:")
prepare_beverage(coffee)
print("\nMaking tea:")
prepare_beverage(tea)
Паттерн "Шаблонный метод" является мощным инструментом для организации кода и управления алгоритмами, предоставляя возможность изменять отдельные шаги алгоритма без изменения его основной структуры.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1👀1💊1
Паттерн "Посетитель" (Visitor) — это поведенческий паттерн проектирования, который позволяет добавлять в программу новые операции, не изменяя классы объектов, над которыми эти операции могут выполняться. Посетитель позволяет определить операцию для объектов других классов, не изменяя эти классы.
Паттерн включает следующие компоненты:
from abc import ABC, abstractmethod
# Интерфейс элемента
class Element(ABC):
@abstractmethod
def accept(self, visitor):
pass
# Конкретные элементы
class TextElement(Element):
def accept(self, visitor):
visitor.visit_text_element(self)
def get_text(self):
return "This is a text element."
class ImageElement(Element):
def accept(self, visitor):
visitor.visit_image_element(self)
def get_image(self):
return "This is an image element."
# Интерфейс посетителя
class Visitor(ABC):
@abstractmethod
def visit_text_element(self, element):
pass
@abstractmethod
def visit_image_element(self, element):
pass
# Конкретный посетитель
class PrintVisitor(Visitor):
def visit_text_element(self, element):
print(f"Printing: {element.get_text()}")
def visit_image_element(self, element):
print(f"Printing: {element.get_image()}")
class SaveVisitor(Visitor):
def visit_text_element(self, element):
print(f"Saving: {element.get_text()}")
def visit_image_element(self, element):
print(f"Saving: {element.get_image()}")
# Клиентский код
elements = [TextElement(), ImageElement()]
print_visitor = PrintVisitor()
save_visitor = SaveVisitor()
for element in elements:
element.accept(print_visitor)
for element in elements:
element.accept(save_visitor)
Паттерн "Посетитель" является мощным инструментом для организации и расширения операций над объектами, упрощая добавление новых операций и улучшая структуру кода.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1👀1💊1
Anonymous Quiz
24%
asyncio позволяет выполнять задачи параллельно на нескольких ядрах процессора
50%
asyncio позволяет эффективно управлять большим количеством I/O операций
15%
asyncio обеспечивает защиту от состояния гонки
11%
asyncio упрощает синхронный ввод-вывод
👍5
LRU (Least Recently Used) cache — это алгоритм кэширования, который удаляет наименее недавно использованные элементы для освобождения места для новых. В этом алгоритме кэш запоминает, когда каждый элемент был использован в последний раз, и при необходимости удаления элемента удаляет тот, который использовался наиболее давно.
Обычно реализуется с использованием двух ключевых структур данных:
Модуль
functools
предоставляет встроенную реализацию LRU cache через декоратор lru_cache
. Вот пример использования этого декоратора:from functools import lru_cache
@lru_cache(maxsize=3)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
# Использование
print(fibonacci(10)) # 55
print(fibonacci.cache_info()) # CacheInfo(hits=8, misses=11, maxsize=3, currsize=3)
# Вывод значений из кэша
print(fibonacci(8)) # 21
print(fibonacci.cache_info()) # CacheInfo(hits=9, misses=11, maxsize=3, currsize=3)
lru_cache
в Python, упрощают внедрение.LRU cache является эффективным и простым способом улучшения производительности и управления памятью в системах с ограниченными ресурсами.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Anonymous Quiz
29%
Методы класса в Python не могут быть вызваны без создания экземпляра класса
54%
В Python можно изменять атрибуты экземпляра класса в методах класса
15%
Атрибуты класса могут быть изменены только из методов класса
2%
Классы в Python не поддерживают наследование
👍1
Существует множество готовых реализаций систем очередей сообщений (Message Queue, MQ), каждая из которых предназначена для различных потребностей и сценариев использования. Вот некоторые из самых популярных и широко используемых реализаций MQ:
Это высокопроизводительная система очередей сообщений, построенная на протоколе AMQP (Advanced Message Queuing Protocol). Поддерживает различные паттерны маршрутизации, такие как очереди, маршрутизация по ключам и топологии обмена.
import pika
# Установка соединения с RabbitMQ
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
# Создание очереди
channel.queue_declare(queue='hello')
# Отправка сообщения
channel.basic_publish(exchange='',
routing_key='hello',
body='Hello World!')
print(" [x] Sent 'Hello World!'")
# Закрытие соединения
connection.close()
Это распределённая потоковая платформа, ориентированная на высокую пропускную способность и низкую задержку. Используется для построения систем обработки потоков данных в реальном времени.
from kafka import KafkaProducer
# Создание продюсера
producer = KafkaProducer(bootstrap_servers='localhost:9092')
# Отправка сообщения
producer.send('test-topic', b'Hello, Kafka!')
producer.flush()
# Закрытие продюсера
producer.close()
Существует множество готовых реализаций MQ, каждая из которых предназначена для различных сценариев использования и требований. Выбор подходящей реализации зависит от конкретных потребностей вашего проекта, таких как производительность, масштабируемость, простота использования и интеграции с другими системами.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍4🔥2👀1
Anonymous Quiz
15%
Использование multiprocessing.Queue
57%
Использование asyncio.gather
26%
Использование threading.Lock
2%
Использование os.fork
👍6👾1
RPC (Remote Procedure Call) — это протокол, который позволяет программам вызывать функции или процедуры, выполняющиеся на удалённом компьютере так, как если бы они выполнялись локально. RPC абстрагирует детали сетевого взаимодействия, предоставляя простой и знакомый способ выполнения распределённых вычислений.
import grpc
from concurrent import futures
import time
import calculator_pb2
import calculator_pb2_grpc
class CalculatorServicer(calculator_pb2_grpc.CalculatorServicer):
def Add(self, request, context):
response = calculator_pb2.AddReply()
response.result = request.a + request.b
return response
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
calculator_pb2_grpc.add_CalculatorServicer_to_server(CalculatorServicer(), server)
server.add_insecure_port('[::]:50051')
server.start()
try:
while True:
time.sleep(86400)
except KeyboardInterrupt:
server.stop(0)
if __name__ == '__main__':
serve()
Клиентская часть:
import grpc
import calculator_pb2
import calculator_pb2_grpc
def run():
with grpc.insecure_channel('localhost:50051') as channel:
stub = calculator_pb2_grpc.CalculatorStub(channel)
response = stub.Add(calculator_pb2.AddRequest(a=1, b=2))
print(f"1 + 2 = {response.result}")
if name == '__main__':
run()
syntax = "proto3";
service Calculator {
rpc Add (AddRequest) returns (AddReply) {}
}
message AddRequest {
int32 a = 1;
int32 b = 2;
}
message AddReply {
int32 result = 1;
}
RPC является мощным инструментом для построения распределённых систем, предоставляя простой и интуитивно понятный способ вызова удалённых процедур и улучшая взаимодействие между различными компонентами системы.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
gRPC (Google Remote Procedure Call) — это современный высокопроизводительный фреймворк для реализации удалённых вызовов процедур (RPC). Он был разработан Google и использует протокол HTTP/2 для передачи данных, а также Protocol Buffers (protobuf) для сериализации и десериализации сообщений. gRPC поддерживает множество языков программирования и предназначен для создания распределённых систем и микросервисной архитектуры.
syntax = "proto3";
service Calculator {
rpc Add (AddRequest) returns (AddReply) {}
}
message AddRequest {
int32 a = 1;
int32 b = 2;
}
message AddReply {
int32 result = 1;
}
Для этого используется утилита
protoc
:protoc --python_out=. --grpc_python_out=. calculator.proto
Реализация сервера:
import grpc
from concurrent import futures
import time
import calculator_pb2
import calculator_pb2_grpc
class CalculatorServicer(calculator_pb2_grpc.CalculatorServicer):
def Add(self, request, context):
response = calculator_pb2.AddReply()
response.result = request.a + request.b
return response
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
calculator_pb2_grpc.add_CalculatorServicer_to_server(CalculatorServicer(), server)
server.add_insecure_port('[::]:50051')
server.start()
try:
while True:
time.sleep(86400)
except KeyboardInterrupt:
server.stop(0)
if __name__ == '__main__':
serve()
Реализация клиента:
import grpc
import calculator_pb2
import calculator_pb2_grpc
def run():
with grpc.insecure_channel('localhost:50051') as channel:
stub = calculator_pb2_grpc.CalculatorStub(channel)
response = stub.Add(calculator_pb2.AddRequest(a=1, b=2))
print(f"1 + 2 = {response.result}")
if name == '__main__':
run()
gRPC является мощным и гибким инструментом для построения современных распределённых систем, обеспечивая высокую производительность и масштабируемость, а также поддерживая множество языков программирования.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥2
ОПП (Объектно-ориентированное программирование) — это парадигма, основанная на концепции объектов. Объекты могут содержать данные в виде полей (или атрибутов) и код в виде процедур (или методов). Предоставляет структуру для организации программного кода таким образом, чтобы его было легче понимать, разрабатывать и поддерживать.
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError("Subclass must implement abstract method")
class Dog(Animal):
def speak(self):
return f"{self.name} says Woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says Meow!"
# Использование
animals = [Dog("Buddy"), Cat("Whiskers")]
for animal in animals:
print(animal.speak())
speak
.speak
.animals
содержит объекты различных классов, и полиморфизм позволяет вызывать метод speak
для каждого из них, не зная их конкретного класса.ООП — мощная парадигма программирования, предоставляющая инструменты для организации кода, повышения его повторного использования, модульности и расширяемости. Используя его, можно создавать более структурированные, гибкие и поддерживаемые программные решения.
Please open Telegram to view this post
VIEW IN TELEGRAM
💊6👍5❤2
Anonymous Quiz
14%
Менеджеры контекста используются для управления памятью
9%
Менеджеры контекста заменяют исключения на предупреждения
72%
Менеджеры контекста должны реализовывать методы enter и exit
6%
Менеджеры контекста не могут использоваться с асинхронным кодом
👍2🤔1🎉1
Типы данных делят на 2 группы: изменяемые и не изменяемые.
Упорядоченные коллекции, которые могут содержать элементы разных типов. Пример: [1, "apple", 3.14]. Списки часто используются для хранения и последовательного доступа к элементам.
e = [1, 2, 3, 4, 5]
Коллекции пар ключ-значение. Пример: {"name": "Alice", "age": 25}. Словари удобны для представления объектов с атрибутами. Ключом в словаре может быть значение с не изменяемым типом данных (int, float, str, tuple, bool, frozenset и т.д.)
g = {"name": "Alice", "age": 25}
Неупорядоченные коллекции уникальных элементов. Пример: {1, 2, 3}. Используются для удаления дубликатов и выполнения операций над множествами, таких как объединение, пересечение.
h = {1, 2, 3, 4, 5}
Это изменяемая последовательность целых чисел в диапазоне от 0 до 255. Они используются для работы с двоичными данными, например, при чтении файлов или сетевого взаимодействия. bytearray полезен, когда вам нужно изменять данные на уровне байтов.
ba = bytearray([50, 100, 150, 200])
Как положительные, так и отрицательные. Например, 1, 100, -20.
a = 5
Числа с плавающей точкой (то есть с дробной частью). Примеры: 3.14, -0.001
b = 2.5
Этот тип данных используется для представления комплексных чисел, которые включают в себя действительную и мнимую части. В Python комплексные числа могут быть созданы с помощью литерала j для мнимой части. Например, комплексное число 3 + 4j. Комплексные числа используются в научных и инженерных расчетах, где необходимо работать с числами, имеющими мнимую составляющую.
z = 3 + 4j
В старых версиях Python (2.x и ранее) существовал отдельный тип данных long для представления очень больших целых чисел. Однако в Python 3 и выше этот тип был упразднен, и теперь все целые числа (int) могут быть любой длины. Таким образом, в современном Python отдельного типа данных long не существует — все большие целые числа автоматически становятся int.
a = 12345678901234567890L # Python 2.x
a = 12345678901234567890 # Python 3
Текст, заключенный в одинарные, двойные или тройные кавычки. Например: "hello", 'world'.
c = "Hello, Python!"
Имеют всего два значения:
True
и False
. Они часто используются в условиях и логических выражениях.d = True
Похожи на списки, но являются неизменяемыми. Пример: (1, "apple", 3.14). Используются, когда данные не должны изменяться после их создания. Если кортеж содержит изменяемые данные, то он становится изменяемым
f = (1, 2, 3)
Это неизменяемая последовательность чисел, обычно используемая в циклах for. range полезен для итерации через серии числовых значений.
for i in range(0, 10):
print(i)
Этот тип данных имеет только одно возможное значение:
None
. Оно используется для обозначения отсутствия значения. Часто используется в логических операциях например if a is None:
a = None
Это неизменяемый аналог set. Так как frozenset неизменяем, он может использоваться в качестве ключа в словарях.
fs = frozenset([1, 2, 3])
Похожи на bytearray, но являются неизменяемыми. Они также представляют собой последовательности целых чисел от 0 до 255 и используются для работы с двоичными данными.
b = bytes([50, 100, 150, 200])
Please open Telegram to view this post
VIEW IN TELEGRAM
👍19🔥2❤1
Anonymous Quiz
21%
thread.sleep()
44%
thread.wait()
16%
thread.hold()
19%
thread.join()
Контекстный менеджер в Python - это специальный тип объекта, который предназначен для управления контекстом в блоке кода. Основная цель контекстного менеджера - обеспечить корректное управление ресурсами, такими как файлы, сетевые соединения или блокировки в многопоточных программах. Это помогает предотвратить ошибки, такие как утечки ресурсов, и делает код более читаемым и безопасным.Чтобы понять, как работает контекстный менеджер, рассмотрим два ключевых метода, которые он должен реализовывать:
enter
вызывается в начале блока кода, управляемого контекстным менеджером (обычно после ключевого слова with
), и обычно используется для выделения ресурсов.exit
вызывается после окончания блока кода и обычно занимается очисткой ресурсов.class FileHandler:
def init(self, filename, mode):
self.filename = filename
self.mode = mode
self.file = None
def enter(self):
self.file = open(self.filename, self.mode)
return self.file
def exit(self, exc_type, exc_val, exc_tb):
if self.file:
self.file.close()
# Использование контекстного менеджера
with FileHandler('example.txt', 'w') as f:
f.write('Привет, мир!')
# После выхода из блока with файл автоматически закрывается
В этом примере
FileHandler
- это контекстный менеджер для работы с файлами. Когда начинается блок with
, вызывается метод enter
, который открывает файл. После завершения работы в блоке with
автоматически вызывается метод exit
, который закрывает файл. Это предотвращает ошибки, связанные с забытым закрытием файла, и делает код более надежным и читаемым.Контекстные менеджеры широко используются в Python для управления ресурсами, их можно встретить в стандартной библиотеке (например,
open
для файлов), а также во многих сторонних библиотеках.Контекстный менеджер в Python - это способ управления ресурсами в блоке кода, обеспечивающий автоматическое выделение и освобождение ресурсов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤1
Anonymous Quiz
17%
dict.update()
49%
queue.Queue.put()
15%
set.add()
18%
list.append()
👍8
Декоратор в Python — это специальная функция, которая позволяет изменять или расширять поведение других функций или методов. Он оборачивает другую функцию (или класс) и позволяет выполнить какой-то код до или после основной функции, не изменяя её.
Декораторы могут изменять поведение функции, не изменяя её кода.
Они позволяют использовать общий код в нескольких функциях, уменьшая дублирование.
В Python декораторы могут быть применены к функции с использованием символа @, что делает код более читабельным и элегантным.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Anonymous Quiz
42%
Протоколы позволяют проверять соответствие объектов во время выполнения
11%
Протоколы не могут использоваться с абстрактными методами
9%
Протоколы ограничивают наследование классов
38%
Протоколы требуют явного указания реализации методов
Различие между
init()
и new()
заключается в их роли при создании экземпляров классов.init()
не возвращает ничего и используется для установки значений атрибутов объекта.__init__()
. Это статический метод, который должен возвращать новый созданный объект, и он используется в особых случаях, например, при создании экземпляров синглтонов или при наследовании от неизменяемых типов данных, как tuple.Допустим, у нас есть класс
Person
, представляющий информацию о человеке. Мы используем init()
для инициализации атрибутов каждого объекта этого класса.class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# Создание экземпляра класса Person
person1 = Person("Алексей", 30)
print(f"Имя: {person1.name}, Возраст: {person1.age}")
В этом примере
init()
используется для установки имени и возраста для каждого объекта Person. Это самый распространенный способ инициализации атрибутов в объектно-ориентированном программировании.new()
используется реже, но его можно применять в специфических сценариях, например, для создания синглтонов (одиночек).class Singleton:
_instance = None
def new(cls):
if cls._instance is None:
print("Создание экземпляра")
cls._instance = super(Singleton, cls).new(cls)
return cls._instance
# Создание экземпляров Singleton
singleton1 = Singleton()
singleton2 = Singleton()
print(singleton1 is singleton2) # Вернет True, так как оба объекта являются одним и тем же экземпляром
Здесь
new()
гарантирует, что класс Singleton
создает только один экземпляр. При попытке создать новый объект этого класса, new()
возвращает уже существующий экземпляр, если он есть, предотвращая создание новых экземпляров.Please open Telegram to view this post
VIEW IN TELEGRAM
🤔9👍5❤3🔥2