Anonymous Quiz
15%
Декораторы не могут быть вложены друг в друга
65%
Декораторы могут изменить аргументы и возвращаемое значение функции
11%
Декораторы применяются только к методам класса
9%
Декораторы не поддерживают передачу аргументов
👍9
Когда в Python используется наследование, и у родительских классов есть методы с одинаковым названием, происходит так называемое разрешение имен. Поведение зависит от способа вызова метода и от того, как определены классы.
Если у вас есть множественное наследование, то порядок разрешения методов (MRO, Method Resolution Order) определяет, какой метод будет вызван. Python использует алгоритм C3-линеаризации для вычисления MRO.
class A:
def say_hello(self):
print("Hello from A")
class B:
def say_hello(self):
print("Hello from B")
class C(A, B):
pass
c = C()
c.say_hello()
В примере выше класс
C
наследует от классов A
и B
. Метод say_hello
есть в обоих родительских классах. Порядок разрешения методов в классе C
будет таким: C -> A -> B
. Чтобы увидеть MRO, можно использовать метод __mro__
или функцию mro()
:print(C.__mro__)
# (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
print(C.mro())
# [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
Таким образом, при вызове
c.say_hello()
будет вызван метод say_hello
класса A
, так как он идет первым в MRO.Если вы переопределите метод в дочернем классе, то будет вызван метод, определенный в самом дочернем классе:
class A:
def say_hello(self):
print("Hello from A")
class B:
def say_hello(self):
print("Hello from B")
class C(A, B):
def say_hello(self):
print("Hello from C")
c = C()
c.say_hello()
# Вывод: Hello from C
Иногда необходимо явно вызвать метод одного из родительских классов. Для этого используется функция
super()
, которая возвращает объект, через который можно вызывать методы родительского класса.class A:
def say_hello(self):
print("Hello from A")
class B:
def say_hello(self):
print("Hello from B")
class C(A, B):
def say_hello(self):
super().say_hello()
print("Hello from C")
c = C()
c.say_hello()
# Вывод:
# Hello from A
# Hello from C
Можно вызвать его напрямую через имя класса:
class A:
def say_hello(self):
print("Hello from A")
class B:
def say_hello(self):
print("Hello from B")
class C(A, B):
def say_hello(self):
A.say_hello(self)
B.say_hello(self)
print("Hello from C")
c = C()
c.say_hello()
# Вывод:
# Hello from A
# Hello from B
# Hello from C
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍25🔥1
Anonymous Quiz
58%
GIL предотвращает выполнение нескольких потоков одновременно
20%
GIL предотвращает выполнение нескольких процессов одновременно
10%
GIL улучшает производительность многопоточных программ
12%
GIL необходим для работы асинхронного кода
👍6
Когезия (cohesion) и связность (coupling) — это два важных концепта в программировании, которые влияют на качество и структуру кода.
Когезия относится к степени, в которой элементы внутри модуля (например, класса или функции) связаны друг с другом и работают вместе для выполнения одной задачи. Высокая когезия означает, что элементы модуля сильно связаны и направлены на выполнение одной функции, что делает модуль более понятным и легким для сопровождения.
Класс, выполняющий одну задачу:
class FileHandler:
def read_file(self, filename):
with open(filename, 'r') as file:
return file.read()
def write_file(self, filename, data):
with open(filename, 'w') as file:
file.write(data)
Функция, выполняющая одну конкретную задачу:
def calculate_sum(numbers):
return sum(numbers)
Преимущества высокой когезии:
Связность относится к степени зависимости одного модуля от другого. Высокая связность означает, что модули сильно зависят друг от друга, что делает систему более жесткой и сложной для сопровождения. Низкая связность, напротив, означает, что модули имеют минимальные зависимости друг от друга, что делает систему более гибкой и легко модифицируемой.
Использование интерфейсов или абстракций:
class Database:
def connect(self):
pass
class MySQLDatabase(Database):
def connect(self):
print("Connecting to MySQL database")
class PostgreSQLDatabase(Database):
def connect(self):
print("Connecting to PostgreSQL database")
def initialize_db(db: Database):
db.connect()
db = MySQLDatabase()
initialize_db(db)
Внедрение зависимостей:
class Service:
def __init__(self, repository):
self.repository = repository
def perform_action(self):
self.repository.save("Some data")
class Repository:
def save(self, data):
print(f"Saving {data}")
repository = Repository()
service = Service(repository)
service.perform_action()
Преимущества низкой связности:
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15😁1
Anonymous Quiz
19%
del() вызывается при доступе к элементу объекта по индексу
3%
del() вызывается при создании нового экземпляра класса
4%
del() вызывается при изменении атрибута объекта
74%
del() вызывается перед удалением объекта сборщиком мусора
Порождающие паттерны (creational patterns) — это шаблоны проектирования в объектно-ориентированном программировании, которые предназначены для управления процессом создания объектов.
Одиночка (Singleton): Паттерн Одиночка гарантирует, что у класса будет только один экземпляр, и предоставляет глобальную точку доступа к нему.
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
singleton1 = Singleton()
singleton2 = Singleton()
print(singleton1 is singleton2) # True
Фабричный метод (Factory Method): Фабричный метод определяет интерфейс для создания объекта, но позволяет подклассам изменять тип создаваемых объектов.
class Animal:
def speak(self):
raise NotImplementedError("Subclass must implement abstract method")
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow!"
class AnimalFactory:
@staticmethod
def get_animal(animal_type):
if animal_type == "dog":
return Dog()
elif animal_type == "cat":
return Cat()
else:
return None
dog = AnimalFactory.get_animal("dog")
cat = AnimalFactory.get_animal("cat")
print(dog.speak()) # Woof!
print(cat.speak()) # Meow!
Абстрактная фабрика (Abstract Factory): Абстрактная фабрика предоставляет интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов.
class Dog:
def speak(self):
return "Woof!"
class Cat:
def speak(self):
return "Meow!"
class PetFactory:
def create_dog(self):
return Dog()
def create_cat(self):
return Cat()
factory = PetFactory()
dog = factory.create_dog()
cat = factory.create_cat()
print(dog.speak()) # Woof!
print(cat.speak()) # Meow!
Строитель (Builder): Паттерн Строитель используется для создания сложных объектов пошагово. Он позволяет создавать разные представления объекта, используя один и тот же код.
class House:
def __init__(self):
self.walls = None
self.roof = None
self.windows = None
def __str__(self):
return f"House with {self.walls} walls, {self.roof} roof, and {self.windows} windows."
class HouseBuilder:
def __init__(self):
self.house = House()
def build_walls(self, walls):
self.house.walls = walls
return self
def build_roof(self, roof):
self.house.roof = roof
return self
def build_windows(self, windows):
self.house.windows = windows
return self
def build(self):
return self.house
builder = HouseBuilder()
house = builder.build_walls("brick").build_roof("tile").build_windows("double-glazed").build()
print(house)
# House with brick walls, tile roof, and double-glazed windows.
Прототип (Prototype): Паттерн Прототип создает новые объекты путем копирования существующих экземпляров (прототипов).
import copy
class Prototype:
def __init__(self, value):
self.value = value
def clone(self):
return copy.deepcopy(self)
original = Prototype(10)
clone = original.clone()
print(original.value) # 10
print(clone.value) # 10
clone.value = 20
print(original.value) # 10
print(clone.value) # 20
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍26❤2
Anonymous Quiz
12%
Аннотации типов обязательно должны быть указаны для всех аргументов функции
71%
Аннотации типов используются только для документации и статической проверки типов
12%
Аннотации типов автоматически выполняют приведение типов
5%
Аннотации типов изменяют поведение функции во время выполнения
Абстрактная фабрика (Abstract Factory) — это порождающий паттерн проектирования, который предоставляет интерфейс для создания семейств взаимосвязанных или взаимозависимых объектов без указания их конкретных классов. Этот паттерн позволяет создавать комплекты объектов, которые должны работать вместе, обеспечивая при этом их взаимозаменяемость.
Создание абстрактных продуктов: Рассмотрим пример, в котором абстрактная фабрика создает различные виды кнопок и чекбоксов для двух разных операционных систем: Windows и MacOS.
from abc import ABC, abstractmethod
class Button(ABC):
@abstractmethod
def click(self):
pass
class Checkbox(ABC):
@abstractmethod
def check(self):
pass
Создание конкретных продуктов
class WindowsButton(Button):
def click(self):
print("Windows button clicked")
class MacOSButton(Button):
def click(self):
print("MacOS button clicked")
class WindowsCheckbox(Checkbox):
def check(self):
print("Windows checkbox checked")
class MacOSCheckbox(Checkbox):
def check(self):
print("MacOS checkbox checked")
Создание абстрактной фабрики
class GUIFactory(ABC):
@abstractmethod
def create_button(self) -> Button:
pass
@abstractmethod
def create_checkbox(self) -> Checkbox:
pass
Создание конкретных фабрик
class WindowsFactory(GUIFactory):
def create_button(self) -> Button:
return WindowsButton()
def create_checkbox(self) -> Checkbox:
return WindowsCheckbox()
class MacOSFactory(GUIFactory):
def create_button(self) -> Button:
return MacOSButton()
def create_checkbox(self) -> Checkbox:
return MacOSCheckbox()
Использование абстрактной фабрики
def client_code(factory: GUIFactory):
button = factory.create_button()
checkbox = factory.create_checkbox()
button.click()
checkbox.check()
# Клиентский код может работать с любыми фабриками и продуктами
windows_factory = WindowsFactory()
macos_factory = MacOSFactory()
print("Client: Testing client code with Windows factory:")
client_code(windows_factory)
print("\nClient: Testing client code with MacOS factory:")
client_code(macos_factory)
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Anonymous Quiz
8%
enter() вызывается при создании нового экземпляра класса
11%
enter() вызывается при выходе из блока with
72%
enter() вызывается при входе в блок with и должен возвращать объект для использования в блоке
10%
enter() используется для изменения атрибутов объекта
👍2
Паттерн "Строитель" — это порождающий паттерн проектирования, который позволяет создавать сложные объекты пошагово и отделяет процесс конструирования объекта от его представления, что дает возможность использовать один и тот же процесс для создания различных представлений.
Создание продукта
class House:
def __init__(self):
self.walls = None
self.roof = None
self.windows = None
def __str__(self):
return f"House with {self.walls} walls, {self.roof} roof, and {self.windows} windows."
Определение интерфейса строителя
from abc import ABC, abstractmethod
class HouseBuilder(ABC):
@abstractmethod
def build_walls(self):
pass
@abstractmethod
def build_roof(self):
pass
@abstractmethod
def build_windows(self):
pass
@abstractmethod
def get_house(self):
pass
Создание конкретных строителей
class ConcreteHouseBuilder(HouseBuilder):
def __init__(self):
self.house = House()
def build_walls(self):
self.house.walls = "brick"
return self
def build_roof(self):
self.house.roof = "tile"
return self
def build_windows(self):
self.house.windows = "double-glazed"
return self
def get_house(self):
return self.house
Создание директора (опционально)
class Director:
def __init__(self, builder):
self.builder = builder
def construct_house(self):
self.builder.build_walls().build_roof().build_windows()
return self.builder.get_house()
Использование паттерна "Строитель"
# Использование без директора
builder = ConcreteHouseBuilder()
house = builder.build_walls().build_roof().build_windows().get_house()
print(house) # House with brick walls, tile roof, and double-glazed windows.
# Использование с директором
director = Director(builder)
house = director.construct_house()
print(house) # House with brick walls, tile roof, and double-glazed windows.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤3
Anonymous Quiz
82%
enumerate() возвращает пары индекс-значение для каждого элемента последовательности
4%
enumerate() изменяет исходную последовательность
9%
enumerate() возвращает только индексы элементов последовательности
5%
enumerate() работает только с числовыми значениями
🎉5❤1
Это порождающий паттерн проектирования, который определяет интерфейс для создания объекта, но позволяет подклассам изменять тип создаваемого объекта. Это позволяет классу делегировать создание объектов подклассам, таким образом убирая жесткую привязку к конкретным классам и делая систему более гибкой и расширяемой.
Определение интерфейса продукта
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def speak(self):
pass
Создание конкретных продуктов
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow!"
Определение создателя
class AnimalFactory(ABC):
@abstractmethod
def create_animal(self) -> Animal:
pass
def some_operation(self) -> str:
animal = self.create_animal()
return f"The animal says: {animal.speak()}"
Создание конкретных создателей
class DogFactory(AnimalFactory):
def create_animal(self) -> Animal:
return Dog()
class CatFactory(AnimalFactory):
def create_animal(self) -> Animal:
return Cat()
Использование фабричного метода
def client_code(factory: AnimalFactory):
print(factory.some_operation())
dog_factory = DogFactory()
cat_factory = CatFactory()
print("Client: Testing client code with DogFactory:")
client_code(dog_factory) # Вывод: The animal says: Woof!
print("\nClient: Testing client code with CatFactory:")
client_code(cat_factory) # Вывод: The animal says: Meow!
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍2
Anonymous Quiz
55%
hash() должен возвращать уникальное значение для каждого объекта
33%
hash() вызывается при добавлении объекта в хэш-таблицу
2%
hash() вызывается при изменении атрибутов объекта
11%
hash() используется для проверки равенства объектов
🤯7❤2🔥1
Это порождающий паттерн проектирования, который позволяет создавать новые объекты, копируя уже существующие экземпляры. Этот паттерн полезен, когда процесс создания объекта является дорогим (в смысле затрат ресурсов) и трудоемким, а копирование существующего объекта оказывается проще и быстрее.
clone()
, позволяющий клонировать объект.clone()
на прототипах.Определение интерфейса прототипа
from abc import ABC, abstractmethod
import copy
class Shape(ABC):
def __init__(self, id):
self.id = id
@abstractmethod
def clone(self):
pass
Создание конкретных прототипов
class Rectangle(Shape):
def __init__(self, id, width, height):
super().__init__(id)
self.width = width
self.height = height
def clone(self):
return copy.deepcopy(self)
def __str__(self):
return f"Rectangle(id={self.id}, width={self.width}, height={self.height})"
class Circle(Shape):
def __init__(self, id, radius):
super().__init__(id)
self.radius = radius
def clone(self):
return copy.deepcopy(self)
def __str__(self):
return f"Circle(id={self.id}, radius={self.radius})"
Использование прототипа
def main():
rect1 = Rectangle(1, 10, 20)
circle1 = Circle(2, 15)
rect2 = rect1.clone()
circle2 = circle1.clone()
print(rect1) # Rectangle(id=1, width=10, height=20)
print(rect2) # Rectangle(id=1, width=10, height=20)
print(circle1) # Circle(id=2, radius=15)
print(circle2) # Circle(id=2, radius=15)
if __name__ == "__main__":
main()
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Anonymous Quiz
11%
functools.partial() изменяет исходную функцию
15%
functools.partial() удаляет некоторые аргументы из функции
68%
functools.partial() создаёт новую функцию с предопределёнными значениями некоторых аргументов
7%
functools.partial() позволяет функции работать асинхронно
Это паттерны проектирования, которые упрощают создание отношений между объектами, обеспечивая гибкую структуру и способствуя повторному использованию кода. Эти паттерны помогают организовать классы и объекты в большие структуры, сохраняя при этом гибкость и эффективность.
Паттерн Адаптер позволяет объектам с несовместимыми интерфейсами работать вместе. Он оборачивает один из объектов, преобразуя его интерфейс в совместимый.
class EuropeanSocket:
def voltage(self):
return 230
class USASocket:
def voltage(self):
return 120
class Adapter:
def __init__(self, socket):
self.socket = socket
def voltage(self):
return self.socket.voltage()
# Использование
european_socket = EuropeanSocket()
adapter = Adapter(european_socket)
print(adapter.voltage()) # 230
Паттерн Мост разделяет абстракцию и реализацию, позволяя изменять их независимо друг от друга.
class DrawingAPI:
def draw_circle(self, x, y, radius):
pass
class DrawingAPI1(DrawingAPI):
def draw_circle(self, x, y, radius):
print(f"API1.circle at {x}:{y} radius {radius}")
class DrawingAPI2(DrawingAPI):
def draw_circle(self, x, y, radius):
print(f"API2.circle at {x}:{y} radius {radius}")
class Shape:
def __init__(self, drawing_api):
self.drawing_api = drawing_api
def draw(self):
pass
class CircleShape(Shape):
def __init__(self, x, y, radius, drawing_api):
super().__init__(drawing_api)
self.x = x
self.y = y
self.radius = radius
def draw(self):
self.drawing_api.draw_circle(self.x, self.y, self.radius)
# Использование
circle1 = CircleShape(1, 2, 3, DrawingAPI1())
circle2 = CircleShape(5, 7, 11, DrawingAPI2())
circle1.draw() # API1.circle at 1:2 radius 3
circle2.draw() # API2.circle at 5:7 radius 11
Паттерн Компоновщик позволяет группировать объекты в древовидные структуры для представления иерархий "часть-целое".
class Component:
def operation(self):
pass
class Leaf(Component):
def operation(self):
return "Leaf"
class Composite(Component):
def __init__(self):
self.children = []
def add(self, component):
self.children.append(component)
def operation(self):
results = []
for child in self.children:
results.append(child.operation())
return f"Branch({'+'.join(results)})"
# Использование
leaf1 = Leaf()
leaf2 = Leaf()
composite = Composite()
composite.add(leaf1)
composite.add(leaf2)
print(composite.operation()) # Branch(Leaf+Leaf)
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Anonymous Quiz
88%
iter() должен возвращать итератор для объекта
7%
iter() вызывается при создании нового экземпляра класса
4%
iter() используется для изменения атрибутов объекта
0%
iter() вызывается при удалении объекта
💊13❤1
Паттерн "Адаптер" (Adapter) — это структурный паттерн проектирования, который позволяет объектам с несовместимыми интерфейсами работать вместе. Адаптер оборачивает один из объектов и преобразует его интерфейс в интерфейс, который ожидает клиент. Этот паттерн часто используется для интеграции кода с устаревшими библиотеками или компонентами.
Целевой интерфейс (Target Interface): Интерфейс, который ожидает клиент.
Клиент (Client): Объект, который использует целевой интерфейс для взаимодействия с другими объектами.
Адаптируемый интерфейс (Adaptee): Существующий интерфейс, который необходимо адаптировать.
Адаптер (Adapter): Класс, который оборачивает адаптируемый интерфейс и преобразует его в целевой интерфейс.
Определение целевого интерфейса и адаптируемого интерфейса
class EuropeanSocketInterface:
def voltage(self):
pass
def live(self):
pass
def neutral(self):
pass
def earth(self):
pass
class USASocket:
def voltage(self):
return 120
def live(self):
return 1
def neutral(self):
return -1
Создание адаптера
class Adapter(EuropeanSocketInterface):
def __init__(self, usa_socket):
self.usa_socket = usa_socket
def voltage(self):
return self.usa_socket.voltage()
def live(self):
return self.usa_socket.live()
def neutral(self):
return self.usa_socket.neutral()
def earth(self):
return 0 # В американских розетках может не быть заземления
Использование адаптера
def client_code(socket):
print(f"Voltage: {socket.voltage()}V")
print(f"Live: {socket.live()}")
print(f"Neutral: {socket.neutral()}")
print(f"Earth: {socket.earth()}")
# Использование
usa_socket = USASocket()
adapter = Adapter(usa_socket)
client_code(adapter)
Объектный адаптер: Использует композицию для оборачивания объекта.
Классовый адаптер: Использует множественное наследование для адаптации одного интерфейса к другому.
Пример классового адаптера:
class USASocket:
def voltage(self):
return 120
def live(self):
return 1
def neutral(self):
return -1
class EuropeanSocketInterface:
def voltage(self):
pass
def live(self):
pass
def neutral(self):
pass
def earth(self):
pass
class Adapter(EuropeanSocketInterface, USASocket):
def earth(self):
return 0 # В американских розетках может не быть заземления
# Использование
adapter = Adapter()
client_code(adapter)
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤4
Anonymous Quiz
80%
missing() вызывается при попытке доступа к отсутствующему ключу в словаре
9%
missing() вызывается при создании нового экземпляра класса
6%
missing() используется для удаления ключей из словаря
6%
missing() вызывается при добавлении нового ключа в словарь
❤1