Anonymous Quiz
11%
@property запрещает изменение значения атрибута
14%
@property позволяет скрыть метод класса от доступа
65%
@property позволяет определить метод, который будет вызываться при доступе к атрибуту
10%
@property используется только для методов, которые возвращают неизменяемые значения
👍6
В Python существуют два основных типа полиморфизма: перегрузка методов и наследование и переопределение методов. Давайте рассмотрим каждый из них подробнее.
Перегрузка методов подразумевает использование одного и того же метода с различными типами данных. Однако в Python это реализуется несколько иначе, чем в статически типизированных языках, таких как C++ или Java. В Python отсутствует явная поддержка перегрузки методов. Вместо этого мы можем использовать стандартные функции с переменным числом аргументов.
Пример:
class Math:
def add(self, a, b, c=0):
return a + b + c
math = Math()
print(math.add(2, 3)) # 5
print(math.add(2, 3, 4)) # 9
В этом примере метод
add
может принимать два или три аргумента, что является примером неявной перегрузки.Наследование и переопределение методов – это более распространенный и важный аспект полиморфизма в Python. Это когда методы в дочернем классе переопределяют поведение методов в базовом классе.
Пример:
class Animal:
def sound(self):
raise NotImplementedError("Subclass must implement abstract method")
class Dog(Animal):
def sound(self):
return "Woof"
class Cat(Animal):
def sound(self):
return "Meow"
def make_sound(animal):
print(animal.sound())
dog = Dog()
cat = Cat()
make_sound(dog) # Woof
make_sound(cat) # Meow
В этом примере класс
Dog
и класс Cat
переопределяют метод sound
базового класса Animal
. Функция make_sound
вызывает метод sound
независимо от конкретного типа объекта.Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤4🐳1💊1
Anonymous Quiz
24%
sorted() сортирует список на месте
71%
sorted() возвращает новый отсортированный список
3%
sorted() не поддерживает пользовательские функции сравнения
2%
sorted() работает только с числовыми значениями
👍2
В Python можно создать итератор из коллекции, используя встроенную функцию
iter()
. Итераторы – это объекты, которые реализуют метод __iter__()
и метод __next__()
. Давайте рассмотрим, как это работает на примере.Рассмотрим список, который является одной из стандартных коллекций в Python:
my_list = [1, 2, 3, 4, 5]
Чтобы создать итератор из этого списка, используем функцию
iter()
:my_iterator = iter(my_list)
Теперь
my_iterator
– это итератор, который можно использовать для поочередного доступа к элементам списка.Мы можем использовать функцию
next()
для получения следующего элемента итератора:print(next(my_iterator)) # Выводит: 1
print(next(my_iterator)) # Выводит: 2
print(next(my_iterator)) # Выводит: 3
Когда элементы коллекции заканчиваются,
next()
вызовет исключение StopIteration
.Обычно итераторы используются в сочетании с циклами
for
, что упрощает работу с ними:for item in my_iterator:
print(item)
Если попытаться использовать итератор повторно после его исчерпания, он больше не будет выдавать элементы:
my_iterator = iter(my_list)
for item in my_iterator:
print(item)
# Повторное использование того же итератора:
for item in my_iterator:
print(item) # Ничего не выведет, так как итератор уже исчерпан
Можно создать собственный итератор, определив класс с методами
__iter__()
и __next__()
.Пример:
class MyIterator:
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index < len(self.data):
result = self.data[self.index]
self.index += 1
return result
else:
raise StopIteration
my_iterable = MyIterator([10, 20, 30])
for item in my_iterable:
print(item)
В этом примере мы создали собственный итератор, который перебирает элементы списка
[10, 20, 30]
.iter()
.__iter__()
и __next__()
для поочередного доступа к элементам.for
для удобства перебора элементов коллекции.Please open Telegram to view this post
VIEW IN TELEGRAM
👍25
Anonymous Quiz
8%
Выражения-генераторы могут быть использованы только в функциях
14%
Выражения-генераторы возвращают список
11%
Выражения-генераторы не поддерживают фильтрацию данных
67%
Выражения-генераторы создают итератор
Для того чтобы создать класс, который поддерживает протокол итератора в Python, нужно определить два метода:
__iter__()
и __next__()
. Давайте рассмотрим пошагово, как это сделать.Начнем с создания класса, который будет содержать коллекцию данных. В данном примере это будет список.
class MyIterable:
def __init__(self, data):
self.data = data
self.index = 0
Метод
__iter__()
должен возвращать сам итератор. В данном случае наш класс сам будет являться итератором, поэтому метод __iter__()
будет возвращать self
.class MyIterable:
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self
Метод
__next__()
должен возвращать следующий элемент последовательности. Если элементы закончились, метод должен вызывать исключение StopIteration
.class MyIterable:
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index < len(self.data):
result = self.data[self.index]
self.index += 1
return result
else:
raise StopIteration
class MyIterable:
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index < len(self.data):
result = self.data[self.index]
self.index += 1
return result
else:
raise StopIteration
# Создаем объект нашего класса
my_iterable = MyIterable([10, 20, 30, 40, 50])
# Используем его в цикле for
for item in my_iterable:
print(item)
self.data
хранит данные, а self.index
отслеживает текущую позицию в последовательности.__iter__()
возвращает сам объект, так как наш класс будет сам итератором.__next__()
возвращает следующий элемент в последовательности и увеличивает индекс. Если элементов больше нет, вызывается исключение StopIteration
.__iter__()
и __next__()
в вашем классе.__iter__()
должен возвращать объект итератора (обычно self
).__next__()
должен возвращать следующий элемент или вызывать StopIteration
, если элементов больше нет.Please open Telegram to view this post
VIEW IN TELEGRAM
👍13
Anonymous Quiz
4%
isinstance() не поддерживает проверку наследования
5%
isinstance() всегда возвращает True для встроенных типов данных
30%
isinstance() проверяет, имеет ли объект указанный тип данных
61%
isinstance() проверяет, является ли объект экземпляром указанного класса или его подклассов
Статические методы (static methods) в Python используются для создания методов, которые связаны с классом, но не требуют доступа к экземпляру этого класса или к самим данным класса. Это методы, которые выполняют функции, связанные с классом, но не изменяют и не используют состояние экземпляра (атрибуты объекта) или состояние самого класса (атрибуты класса). Они могут быть вызваны на уровне класса, а не на уровне экземпляра класса.
Для создания статического метода в Python используется декоратор
@staticmethod
. Давайте рассмотрим пример:class MyClass:
@staticmethod
def static_method(arg1, arg2):
return arg1 + arg2
Вы можете вызывать статический метод как через сам класс, так и через его экземпляр:
result = MyClass.static_method(5, 10)
print(result) # Вывод: 15
my_instance = MyClass()
result = my_instance.static_method(3, 7)
print(result) # Вывод: 10
self
, что позволяет им изменять состояние конкретного экземпляра класса.class MyClass:
def instance_method(self, value):
self.value = value
cls
, что позволяет им изменять состояние самого класса.class MyClass:
class_variable = 0
@classmethod
def class_method(cls, value):
cls.class_variable = value
self
или cls
в качестве первого аргумента и не могут изменять состояние экземпляра или класса.class MyClass:
@staticmethod
def static_method(arg1, arg2):
return arg1 + arg2
@staticmethod
.Please open Telegram to view this post
VIEW IN TELEGRAM
👍12
Anonymous Quiz
2%
str() вызывается при сравнении объектов
1%
str() вызывается при удалении объекта
4%
str() вызывается при создании нового экземпляра класса
93%
str() вызывается при преобразовании объекта в строку с помощью str()
💊24❤2👀2
Методы класса (class methods) в Python используются для методов, которые работают с самим классом, а не с его экземплярами. Они позволяют изменять состояние класса или выполнять операции, которые относятся ко всему классу в целом, а не к отдельным его экземплярам.
Для создания метода класса в Python используется декоратор
@classmethod
. Такие методы принимают первым аргументом не self
(как в методах экземпляра), а cls
, что указывает на сам класс.Пример:
class MyClass:
class_variable = 0
@classmethod
def class_method(cls, value):
cls.class_variable = value
Метод класса можно вызывать как на уровне класса, так и через экземпляры класса:
# Вызов метода класса через сам класс
MyClass.class_method(10)
print(MyClass.class_variable) # Вывод: 10
# Вызов метода класса через экземпляр класса
instance = MyClass()
instance.class_method(20)
print(MyClass.class_variable) # Вывод: 20
Фабричный метод — это метод класса, который возвращает новый экземпляр класса. Рассмотрим пример, где метод класса используется для создания объекта с предустановленными значениями.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def from_birth_year(cls, name, birth_year):
age = 2024 - birth_year
return cls(name, age)
# Создание экземпляра через основной конструктор
person1 = Person("Alice", 30)
print(person1.name, person1.age) # Вывод: Alice 30
# Создание экземпляра через фабричный метод
person2 = Person.from_birth_year("Bob", 1990)
print(person2.name, person2.age) # Вывод: Bob 34
self
).class MyClass:
def instance_method(self, value):
self.value = value
@staticmethod
).class MyClass:
@staticmethod
def static_method(arg1, arg2):
return arg1 + arg2
@classmethod
).class MyClass:
class_variable = 0
@classmethod
def class_method(cls, value):
cls.class_variable = value
@classmethod
и принимают cls
в качестве первого аргумента.Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Anonymous Quiz
3%
zip() работает только с числовыми последовательностями
54%
zip() объединяет несколько последовательностей в одну, возвращая итератор
3%
zip() изменяет исходные последовательности
41%
zip() объединяет несколько последовательностей в одну, возвращая список
Обычные методы и методы класса в Python различаются в основном тем, к чему они привязаны и как используются. Давайте рассмотрим их отличия более подробно.
Привязка к экземпляру:
self
, который указывает на текущий экземпляр класса.Использование атрибутов: Могут изменять состояние экземпляра, то есть работать с его атрибутами.
Определение:
class MyClass:
def instance_method(self, value):
self.value = value
Вызов:
instance = MyClass()
instance.instance_method(10)
Пример:
class Dog:
def __init__(self, name):
self.name = name
def bark(self):
print(f"{self.name} говорит: Гав-гав!")
dog = Dog("Бобик")
dog.bark() # Вывод: Бобик говорит: Гав-гав!
Привязка к классу:
cls
, который указывает на сам класс.Использование атрибутов: Могут изменять состояние класса, то есть работать с атрибутами класса.
Определение:
class MyClass:
class_variable = 0
@classmethod
def class_method(cls, value):
cls.class_variable = value
Вызов: Могут вызываться как через сам класс, так и через его экземпляры.
MyClass.class_method(10)
instance = MyClass()
instance.class_method(20)
Пример:
class Dog:
total_dogs = 0
def __init__(self, name):
self.name = name
Dog.total_dogs += 1
@classmethod
def get_total_dogs(cls):
return cls.total_dogs
dog1 = Dog("Бобик")
dog2 = Dog("Шарик")
print(Dog.get_total_dogs()) # Вывод: 2
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20❤1
Anonymous Quiz
86%
init() вызывается при создании нового экземпляра класса, инициализируя его атрибуты
2%
init() вызывается при удалении экземпляра класса
3%
init() нельзя переопределять в пользовательских классах
9%
init() вызывается при каждом вызове метода класса
👍12
Внедрение зависимостей (Dependency Injection, DI) — это дизайн-паттерн, используемый в объектно-ориентированном программировании для управления зависимостями между объектами. Внедрение зависимостей позволяет сделать код более гибким, тестируемым и поддерживаемым, отделяя создание объектов от их использования.
Car
использует объект Engine
, то Engine
является зависимостью для Car
.Рассмотрим пример, где класс
Car
зависит от класса Engine
.class Engine:
def start(self):
print("Engine started")
class Car:
def __init__(self, engine):
self.engine = engine
def start(self):
self.engine.start()
print("Car started")
# Создание объекта Engine
engine = Engine()
# Внедрение зависимости Engine в объект Car через конструктор
car = Car(engine)
car.start()
Внедрения через методы (сеттеры)
class Engine:
def start(self):
print("Engine started")
class Car:
def __init__(self):
self.engine = None
def set_engine(self, engine):
self.engine = engine
def start(self):
if self.engine is not None:
self.engine.start()
print("Car started")
else:
print("No engine to start")
# Создание объекта Engine
engine = Engine()
# Создание объекта Car
car = Car()
# Внедрение зависимости Engine в объект Car через метод
car.set_engine(engine)
car.start()
Внедрения через свойства
class Engine:
def start(self):
print("Engine started")
class Car:
def __init__(self):
self._engine = None
@property
def engine(self):
return self._engine
@engine.setter
def engine(self, engine):
self._engine = engine
def start(self):
if self._engine is not None:
self._engine.start()
print("Car started")
else:
print("No engine to start")
# Создание объекта Engine
engine = Engine()
# Создание объекта Car
car = Car()
# Внедрение зависимости Engine в объект Car через свойство
car.engine = engine
car.start()
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤2
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