Python Core Addition Flashcards

1
Q

В каком году написана первая статья про python

A

Гвидо Ван Россум - 1991-й (релиз)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Что такое python?

A
  • Интерпретируемый
  • Динамическая типизация
  • Автоматическое управление памятью
  • Конец 1980-х
  • Гвидо ван Россум

Python - это язык программирования высокого уровня, интерпретируемый, с динамической типизацией и автоматическим управлением памятью. Он был разработан в конце 1980-х годов Гвидо ван Россумом и имеет широкую популярность среди разработчиков благодаря своей простоте и эффективности. Python широко применяется в различных областях, включая науку о данных, машинное обучение, веб-разработку, игровую индустрию, GIS и многие другие.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Какие типы данных есть в python? На какие классы делятся?

A

Python поддерживает множество различных встроенных типов данных, включая:

  • Числа: int, float, и complex.
  • Строки: str.
  • Списки: list.
  • Кортежи: tuple.
  • Словари: dict.
  • Множества: set.
  • Булевы значения: bool.

Эти типы данных можно разделить на несколько классов:

  • Числовые типы данных: int, float, и complex.
  • Строковые типы данных: str.
  • Коллекции: list, tuple, dict, и set.
  • Булевы типы данных: bool.

Каждый тип предоставляет свои собственные методы и функции для работы с данными, а также поддерживает операции, которые могут выполняться на них, такие как арифметические и логические операции.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Что такое лямбда-функция? Какое у неё назначение?

A

Лямбда-функция (также известна как “анонимная функция”) - это функция, которая определяется в одной строке кода без использования ключевого слова def. Она может быть использована вместо обычной функции, когда требуется быстрое определение небольшой функции.

В Python лямбда-функция определяется с помощью ключевого слова lambda, за которым следует список аргументов через запятую, затем символ :, и наконец, тело функции.

Например, чтобы определить лямбда-функцию, которая удваивает свой аргумент, можно написать:

double = lambda x: x * 2

Лямбда-функции в основном используются в качестве аргументов функций высшего порядка , которые принимают другие функции в качестве аргументов. Также они могут использоваться для создания более читаемого и компактного кода.

Например, можно использовать лямбда-функцию вместо объявления обычной функции для преобразования списка:

numbers = [1, 2, 3, 4, 5]
squares = list(map(lambda x: x**2, numbers))

Этот пример создает список квадратов чисел в списке numbers с помощью функции map(), принимающей лямбда-функцию в качестве аргумента.

Таким образом, лямбда-функция в Python позволяет определять небольшие функции быстро и использовать их в качестве аргументов для других функций.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Что такое PEP 8?

A

PEP 8 (Python Enhancement Proposal 8) - это документ, содержащий рекомендации по написанию кода на языке Python.

Он содержит стилевые соглашения, которые, следуя практике, повышают читабельность кода, делая его более понятным, расширяемым и поддерживаемым. Документ был опубликован в 2001 году и рекомендуется как основной стандарт написания кода Python. PEP 8 охватывает такие темы, как именование переменных, расположение отступов, длина строк, комментарии, импорты и многое другое.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Как получить документацию по атрибутам объекта?

A

В Python вы можете получить документацию по атрибутам объекта с помощью атрибута doc. Например, если у вас есть объект с атрибутом attribute_name, то вы можете получить его документацию следующим образом:

python
print(attribute_name.\_\_doc\_\_)
~~~
Вы также можете использовать встроенную функцию help() для получения подробной информации о любом объекте, включая его атрибуты. Просто передайте объект в функцию help(), чтобы получить всю доступную документацию:
python
help(attribute_name)
~~~
Небольшое уточнение: doc отображает документацию для конкретного атрибута или метода. Если вы хотите получить общую документацию для объекта, вызовите help() без параметров (т.е. help(object_name)).

Например, если у вас есть класс с атрибутом attribute_name, вы можете получить его документацию следующим образом:
```python
class MyClass:
“"”This is the docstring for MyClass.”””
attribute_name = “value”

print(MyClass.attribute_name.__doc__)
~~~
Этот код выведет документацию для атрибута attribute_name, которая будет равна None, так как мы не определили документацию для него в классе. Теперь мы можем использовать функцию help() для получения документации для самого класса:
```python
help(MyClass)
~~~
Это приведет к выводу всей доступной документации для MyClass, включая документацию для его атрибута attribute_name.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Что такое docstring?

A

Docstring в Python - это строка документации, которая описывает, что делает функция, метод, модуль или класс Python.

Данная строка располагается в начале определения объекта и используется для генерации документации автоматически.

В других словах, docstring используется для создания описания API и содержит информацию о том, как использовать функцию или метод, какие аргументы они принимают и какие значения возвращают.

Например:
```python
def add_numbers(a, b):
“””
This function takes in two numbers and returns their sum
“””
return a + b
~~~
В данном примере, docstring - это строка между тройными кавычками, после имени функции. Она описывает, что делает функция и как ее использовать.

Docstring является важным инструментом в Python разработке, так как важно документировать ваш код для себя и для других разработчиков. Документированный код легче поддерживать и понимать, что облегчает разработку и сотрудничество.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

В чём разница между типами list и tuple?

A

Изменяемый и неизменяемый.
Кортеж обрабатывается быстрее за счёт неизменяемости.

В Python, список (list) и кортеж (tuple) являются двумя различными типами данных, которые предоставляют набор элементов в определенном порядке. Основная разница между ними заключается в том, что список может быть изменен (мутабельный тип), а кортеж является неизменяемым (иммутабельным типом).

То есть, после создания кортежа, вы не можете изменять его содержимое, добавлять или удалять элементы. Это делает кортежи более эффективными по памяти и дает гарантию того, что их содержимое не будет изменено случайно в коде. В то время как список может быть изменен, что было бы очень полезно, если вам нужна коллекция элементов, которые вы можете изменять по ходу выполнения кода.

Другая разница между списком и кортежем заключается в скорости доступа к элементам. За счет того, что кортежи являются неизменным типом данных, они обрабатываются быстрее, чем списки.

Например, для создания списка в Python используется квадратная скобка, а для создания кортежа используется круглая скобка. Вот примеры использования списков и кортежей:

python
my_list = [1, 2, 3, 4, 5] # Это список
my_tuple = (1, 2, 3, 4, 5) # Это кортеж
~~~
Cписок может быть изменен, например, можно добавить элемент в список:
python
my_list.append(6)
~~~
Но не можем добавить элемент в кортеж, так как он неизменяем:
```python
my_tuple.append(6) # Эта строка вызовет ошибку
~~~
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Может ли быть индекс списка отрицательным?

A

Да, индекс списка может быть отрицательным. В таком случае, отрицательное значение считается от конца списка, где -1 соответствует последнему элементу, -2 - предпоследнему элементу и так далее.

Например, чтобы получить последний элемент списка my_list в Python, можно использовать следующую команду:

python
last_element = my_list[-1]
~~~
Также можно использовать отрицательные значения для срезов (slicing) списка, например:
python
my_list[-3:] # вернет последние три элемента списка
my_list[:-2] # вернет все элементы списка, кроме последних двух
my_list[::-1] # вернет список в обратном порядке
~~~
Но следует учесть, что если индекс отрицательный и его абсолютное значение больше или равно длине списка, будет возбуждено исключение IndexError.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Что значит конструкция pass?

A

В Python, pass является пустым оператором. Он используется там, где синтаксически требуется оператор, но никаких действий выполнять не нужно. Например, это может быть полезно при написании заглушки функции, которая будет реализована позже, или в цикле, который ничего не должен делать на данной итерации. Пример использования конструкции pass:
```python
def my_function():
pass # заглушка для функции, которая будет реализована позже

for i in range(10):
if i < 3:
pass # ничего не делать на первых трёх итерациях
else:
print(i) # вывести значения на всех остальных итерациях
```
В обоих случаях pass играет роль пустого оператора, который не выполняет никаких действий, но позволяет синтаксически корректно описать код.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Чем отличаются многопоточное и многопроцессорное приложение?

A

Многопоточное и многопроцессорное приложения отличаются друг от друга в том, как они используют ресурсы компьютера. В многопроцессорных приложениях каждый процесс имеет свой собственный набор ресурсов, включая память, открытые файлы, сетевые соединения и другие системные ресурсы. В многопоточных приложениях несколько потоков выполняются в рамках одного процесса, используя общие ресурсы. Это означает, что все потоки имеют доступ к общим данным.

Реализация многопоточности в Python выполняется за счет стандартной библиотеки threading. Многопроцессорность в Python может быть достигнута с помощью библиотек multiprocessing и concurrent.futures.

При правильном использовании оба подхода могут ускорить выполнение программы и улучшить управляемость ею, однако многопоточное приложение может иметь проблемы с блокировками и условиями гонки при доступе к общим ресурсам. В многопроцессорных приложениях каждый процесс защищен от других процессов и обеспечивает более высокую степень изоляции.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Как просмотреть методы объекта?

A

Чтобы посмотреть все методы и атрибуты, связанные с определенным объектом в Python, можно использовать функцию dir(). Она принимает объект в виде аргумента и возвращает список имен всех атрибутов и методов объекта. Например, если нужно увидеть все методы и атрибуты, связанные с объектом my_list, следующее:

```python
my_list = [1, 2, 3]
print(dir(my_list))
~~~
Это выведет список всех методов и атрибутов, которые можно использовать с объектом my_list.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Что такое *args и **kwargs в определении функции?

A
  • *args - собирает последовательность элементов в кортеж
  • **kwargs - собирает последовательность типа dog="Brock", fish=["Larry", "Curly", "Moe"], turtle="Shelldon" в словарь

*args и **kwargs - это специальные параметры в Python, которые позволяют передавать переменное количество аргументов в функцию. Параметр *args используется для передачи переменного количества аргументов без ключевого слова. Он представляет собой кортеж из всех дополнительных аргументов, переданных функции. Параметр **kwargs используется для передачи переменного количества именованных аргументов. Он представляет собой словарь из всех дополнительных именованных аргументов, переданных функции.

Cимвол * и ** могут использоваться в определении функций для указания переменного числа аргументов, которые могут быть переданы в функцию.

Символ * перед именем параметра означает, что все позиционные аргументы, которые не были использованы при определении других параметров, будут собраны в кортеж, который можно будет использовать внутри функции. Такой параметр называется *args. Например:

python
def my_fun(a, b, *args):
    print(a, b, args)

Вызов функции my_fun(1, 2, 3, 4, 5) выведет на экран следующее:
python
1 2 (3, 4, 5)
~~~
Символ `**` перед именем параметра означает, что все именованные аргументы, которые не были использованы при определении других параметров, будут собраны в словарь, который можно будет использовать внутри функции. Такой параметр называется `**kwargs`. Например:
python
def my_fun(a, b, **kwargs):
print(a, b, kwargs)
~~~
Вызов функции my_fun(1, 2, x=3, y=4, z=5) выведет на экран следующее:
```python
1 2 {‘x’: 3, ‘y’: 4, ‘z’: 5}
~~~
Использование *args и **kwargs позволяет создавать более гибкие функции, которые могут принимать любое количество аргументов.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Python полностью поддерживает ООП?

A

Да, Python является полностью объектно-ориентированной языковой средой. Он поддерживает все основные принципы объектно-ориентированного программирования (ООП), такие как наследование, инкапсуляция и полиморфизм.

В Python все объекты в явном виде являются экземплярами классов, и даже типы данных, такие как список или словарь, являются классами со своими методами и атрибутами.

Кроме того, Python поддерживает множественное наследование, который позволяет создавать новые классы, которые наследуют методы и атрибуты от нескольких родительских классов одновременно.

В целом, Python предоставляет множество инструментов для написания кода в объектно-ориентированном стиле, и это один из главных его преимуществ, особенно для написания крупных и сложных приложений.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Что такое globals() и locals()?

A

globals() и locals() - это встроенные функции в Python, которые возвращают словари глобальных и локальных переменных соответственно.

globals() возвращает словарь, содержащий все глобальные переменные, доступные в текущей области видимости, включая встроенные переменные.

locals() возвращает словарь, содержащий все локальные переменные, определенные в текущей области видимости. Это включает аргументы функции и переменные, которым присвоено значение внутри функции.

Например, вот как можно использовать эти функции:
```python
x = 5
y = 10

def my_func(z):
a = 3
print(globals()) # выводит все глобальные переменные
print(locals()) # выводит все локальные переменные

my_func(7)
~~~
В этом примере функция my_func() принимает один аргумент и определяет две локальные переменные (a и z). Когда она вызывается, она выводит на экран словари глобальных и локальных переменных.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Что хранится в атрибуте __dict__?

A

Атрибут __dict__ содержит словарь, который хранит атрибуты объекта в виде пар ключ-значение. Этот словарь заполняется значениями при создании объекта и может быть изменен позже. Например, если у вас есть объект класса Person, и вы создаете его экземпляр person1, то вы можете добавить новый атрибут age и присвоить ему значение 25 следующим образом:
```python
class Person:
def __init__(self, name):
self.name = name
def say_hello(self):
print(“Hello, my name is”, self.name)

person1 = Person(“Alice”)
person1.age = 25
print(person1.__dict__)
~~~
Это выведет словарь, содержащий пару ключ-значение {'name': 'Alice', 'age': 25}.

Вы можете обратиться к любому атрибуту объекта, используя либо обычную запись person1.name, либо запись, использующую словарь python person1.\_\_dict\_\_["name"].

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

Как проверить файл .py на синтаксические ошибки, не запуская его?

A

Утилита py_compile, позволит проверить файл .py на наличие синтаксических ошибок без его запуска.

Вы можете использовать командную строку или терминал для проверки файла .py на наличие синтаксических ошибок, не запуская его, используя флаг -m с модулем py_compile. Вот как это сделать:

Откройте командную строку или терминал.
Перейдите в каталог, содержащий файл .py, который вы хотите проверить.
Выполните следующую команду:
```python
python -m py_compile yourfile.py
~~~
где yourfile.py - это имя файла, который вы хотите проверить.

Эта команда выполнит проверку файла и выведет описание любых синтаксических ошибок, которые были найдены, или пустой вывод, если ошибок нет.

18
Q

Зачем в python используется ключевое слово self?

A

Для обращения к текущему объекту класса.

Оно передается как первый аргумент в методы класса и позволяет работать с атрибутами и методами объекта класса внутри этих методов.

К примеру, рассмотрим класс Person, который имеет атрибут name и метод say_hello:
```python
class Person:
def __init__(self, name):
self.name = name

def say_hello(self):
    print(f"Hello, my name is {self.name}") ~~~ Здесь мы можем обратиться к атрибуту name объекта класса Person с помощью ключевого слова self. Аналогично, мы можем вызвать метод say_hello, который также использует self для доступа к атрибуту name: ```python person = Person("Alice") person.say_hello() # выведет "Hello, my name is Alice" ~~~ Таким образом, self позволяет нам работать с атрибутами и методами объекта класса внутри его методов.
19
Q

Что такое декоратор? Как написать собственный?

A

Функция, которая принимает другую функцию в качестве аргумента и расширяет ее функциональность без изменения ее кода.

Декораторы могут использоваться для добавления логирования, проверки аутентификации, тайминга выполнения и других аспектов.

Вот пример создания декоратора:

def uppercase(func):
    def wrapper():
        original_result = func()
        modified_result = original_result.upper()
        return modified_result
    return wrapper
  1. Получаем func на вход
  2. Присваиваем ее в переменную
  3. Модифицируем
  4. Возвращаем результат
20
Q

Что может быть ключом в словаре?

A

this will result in {1: ‘one again’}

В Python ключом в словаре может быть любой неизменяемый объект, такой как число, строка или кортеж. Например:

my_dict = {1: 'one', 'two': 2, (3, 4): 'three four'}

В этом примере ключами словаря являются число 1, строка ‘two’ и кортеж (3, 4). Однако, если вы попытаетесь использовать изменяемый объект, такой как список, как ключ словаря, вы получите TypeError:

my_dict = {[1, 2]: 'one two'}

Также, если вы попытаетесь добавить два ключа в словарь с одинаковым хеш-кодом, то второй ключ перезапишет первый:

my_dict = {1: 'one', '1': 'one again'}
21
Q

В чём разница между пакетами и модулями?

A

Модуль - файл с кодом
Пакет - папка с модулями и __init__.py который инциализирует переменные, функции и классы и делает их доступными внутри модулей этого пакета

Модуль - это файл, содержащий код Python, который может быть повторно использован в других программах.

Пакет - это директория, содержащая один или несколько модулей (или пакетов внутри пакетов), а также специальный файл __init__.py, который выполняется при импорте пакета. Он может содержать код, который инициализирует переменные, функции и классы, и становится доступным для использования внутри модулей, находящихся внутри этого пакета.

Таким образом, основная разница между модулем и пакетом заключается в том, что модуль - это файл с кодом, который можно использовать повторно, а пакет - это директория, которая может содержать один или несколько модулей. Код, находящийся в файле __init__.py, может инициализировать переменные, функции и классы, что обеспечивает общую функциональность для всех модулей, находящихся внутри пакета.

Например, если у нас есть пакет mypackage, в нем может находится несколько модулей, таких как module1.py, module2.py. В файле __init__.py определяются функции и переменные, которые могут использоваться внутри module1 и module2.

Некоторые примеры импорта:
```python
import mymodule # импортируем модуль
from mypackage import mymodule # импортируем модуль из пакета
from mypackage.mymodule import myfunction # импортируем функцию из модуля в пакете
~~~

22
Q

Как перевести строку, содержащую двоичный код (1 и 0), в число?

A

Для того, чтобы перевести строку, содержащую двоичный код, в целое число в Python, нужно воспользоваться функцией int(), передав ей вторым аргументом основание системы счисления - в данном случае 2. Например:

binary_str = '110101'
decimal_num = int(binary_str, 2)
print(decimal_num)

Вывод:

53
23
Q

Для чего используется функция \_\_init\_\_ ?

A

Функция __init__ является конструктором класса, и она вызывается автоматически при создании нового экземпляра класса.

Эта функция используется для инициализации атрибутов, которые будут принадлежать объектам, создаваемым с помощью класса.

Внутри функции __init__ определяются атрибуты объекта, которые будут доступны через ссылку на экземпляр, на который ссылается переменная self.

Пример:

class Person:
    def \_\_init\_\_(self, name, age):
        self.name = name
        self.age = age

person1 = Person("John", 30)
person2 = Person("Alice", 25)

print(person1.name)  # output: John
print(person2.age)   # output: 25

В этом примере функция __init__ устанавливает два атрибута экземпляра для каждого объекта, создаваемого с помощью класса Person: name и age. Когда мы создаем новый объект, мы передаем эти аргументы в функцию __init__, чтобы инициализировать соответствующие атрибуты.

24
Q

Что такое слайс(slice)?

A

Слайс (slice) - это способ извлечения определенной части последовательности (например, строки, списка, кортежа) с использованием индексации.

Синтаксис для создания слайса:
```python
sequence[start:end:step]
~~~
где start - индекс, с которого начинается извлечение (включительно), end - индекс, на котором заканчивается извлечение (не включая его), и step - шаг для извлечения элементов (по умолчанию равен 1). Обратите внимание, что если не указывать start, то по умолчанию он равен 0, а если не указывать end, то по умолчанию он равен длине последовательности.

Вот пример использования слайса для выбора подряд идущих элементов списка (list):
```python
my_list = [0, 1, 2, 3, 4, 5]
my_slice = my_list[1:4] # выбираем элементы с индексами от 1 до 3 включительно
print(my_slice) # выведет [1, 2, 3]
~~~
В этом примере мы использовали слайс my_list[1:4] для выбора элементов списка с индексами от 1 до 3 включительно.

25
Q

Как проверить, что один кортеж содержит все элементы другого кортежа?

A

Для проверки того, содержит ли один кортеж все элементы другого кортежа в Python, можно воспользоваться встроенной функцией all(), передав ей выражение генератора списков, которое проверяет наличие каждого элемента из второго кортежа в первом кортеже. Например:

first_tuple = (1, 2, 3, 4, 5)
second_tuple = (2, 4, 5)

contains_all = all(elem in first_tuple for elem in second_tuple)

print(contains_all)  # True

Этот код создает два кортежа first_tuple и second_tuple и затем использует генератор списка, чтобы проверить, содержит ли first_tuple все элементы из second_tuple. Результат будет True, если все элементы второго кортежа содержатся в первом кортеже, и False в противном случае.

Если вам нужно проверить, содержит ли кортеж все элементы из другой последовательности, не обязательно кортежа, вы можете использовать преобразование типа set() для сравнения их элементов, как показано ниже:

first_tuple = (1, 2, 3, 4, 5)
some_list = [2, 4, 5]

contains_all = set(some_list).issubset(set(first_tuple))
print(contains_all)  # True

Этот код дает тот же результат, что и предыдущий пример, но здесь мы преобразуем элементы some_list и first_tuple в множество и используем метод issubset() для проверки, содержит ли первое множество все элементы второго множества.

26
Q

Почему пустой список нельзя использовать как аргумент по умолчанию?

A

Значения по умолчанию для аргументов функции вычисляются только один раз, когда функция определяется, а не каждый раз, когда она вызывается. Таким образом, если вы попытаетесь использовать изменяемый тип данных (например, список) как аргумент по умолчанию для функции, то каждый вызов функции, который изменяет это значение, также изменит значение по умолчанию для всех последующих вызовов функции. Это может привести к неожиданным поведениям.

Пустой список - это изменяемый тип данных в Python, поэтому его использование в качестве аргумента по умолчанию не рекомендуется. Вместо этого лучше использовать None в качестве значения по умолчанию и создавать новый пустой список внутри функции, если требуется список. Например:

def my_function(my_list=None):
    if my_list is None:
        my_list = []
    # do something with my_list

Таким образом, вы всегда можете быть уверены, что получаете новый объект списка при каждом вызове функции.

27
Q

Что такое @classmethod, @staticmethod, @property?

A

@classmethod, @staticmethod, and @property - это декораторы методов класса в языке Python.

@classmethod декоратор используется для создания методов, которые будут работать с классом в целом, а не с отдельным экземпляром. В качестве первого параметра этот метод принимает класс, а не экземпляр объекта, и часто используется для создания фабричных методов и методов, которые работают с класс-уровнем методов.

Используется, когда вам нужно получить методы, не относящиеся к какому-либо конкретному экземпляру, но тем не менее, каким-то образом привязанные к классу. Самое интересное в них то, что их можно переопределить дочерними классами.

@staticmethod декоратор работает подобно @classmethod, но он не получает доступ к классу в качестве первого параметра.

Статический метод помогает в достижении инкапсуляции в классе, поскольку он не знает о состоянии текущего экземпляра. Кроме того, статические методы делают код более читабельным и повторно используемым, а также более удобным для импорта по сравнению с обычными функциями, поскольку каждую функцию не нужно отдельно импортировать.

@property декоратор используется для создания свойств объекта, которые можно получить и задать, но выглядят как обычные атрибуты объекта. Это позволяет управлять доступом к атрибутам объекта, установив условиями доступа и возможностью заложить дополнительную логику при чтении, установке или удалении атрибута.

Например, явное использование декораторов может выглядеть так:

class MyClass:
    def \_\_init\_\_(self, value):
        self._value = value

    @classmethod
    def from_string(cls, input_string):
        value = process_input_string(input_string)
        return cls(value)

    @staticmethod
    def process_input_string(input_string):
        # implementation details

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, new_value):
        if new_value < 0:
            raise ValueError("Value must be positive")
        self._value = new_value

Декорированные методы могут быть использованы для достижения различных целей, таких как доступ к класс-уровню, расширение функциональности объекта и управление доступом к атрибутам.

28
Q

Что такое синхронный код?

A

Синхронный код - это код, который выполняется последовательно, один за другим, и блокирует выполнение других задач до его завершения. Это означает, что если у вас есть функция, которая занимает много времени на выполнение, и вы вызываете ее в основной программе, то выполнение программы заблокируется до завершения этой функции.

Примером синхронного кода в Python может служить следующий фрагмент, который содержит цикл while, обрабатывающий список элементов:
```python
items = [1, 2, 3, 4, 5]
for item in items:
print(item)
~~~
Здесь цикл for будет обрабатывать каждый элемент в списке items последовательно, один за другим, и не будет переходить к следующему элементу, пока не завершится обработка текущего элемента.

Выполнение синхронного кода может занять много времени и может вызвать проблемы с производительностью, особенно когда код выполняет блокирующие операции, такие как чтение и запись файлов, обращение к сети, или поиск значений в базе данных. Для решения этой проблемы в Python используют асинхронное программирование с использованием конструкций async/await и библиотеки asyncio. Они позволяют выполнять несколько задач асинхронно, не блокируя выполнение других задач, и добиваться более высокой производительности.

29
Q

Что такое асинхронный код? Приведите пример.

A

Асинхронный код - это подход к написанию кода, который позволяет выполнять несколько задач одновременно в рамках одного процесса. Это достигается за счет использования асинхронных функций и корутин. В отличие от синхронного кода, который выполняет каждую задачу последовательно, асинхронный код может запустить несколько задач “параллельно” и организовать их выполнение с помощью итераций и вызовов коллбеков.

Примером использования асинхронного кода является библиотека asyncio в Python. Например, вот простой пример кода, который использует asyncio для запуска нескольких задач одновременно и ожидания их завершения:
```python
import asyncio

async def hello():
await asyncio.sleep(1)
print(“Hello”)

async def world():
await asyncio.sleep(2)
print(“World”)

async def main():
await asyncio.gather(hello(), world())

if __name__ == ‘__main__’:
asyncio.run(main())
~~~
В этом примере мы определяем 3 асинхронные функции: hello(), world() и main(). Функции hello() и world() печатают соответствующие сообщения и ждут 1 и 2 секунды соответственно. Функция main() запускает эти две функции одновременно с помощью asyncio.gather() и ждет, пока они завершат свою работу. Затем мы запускаем функцию main() с помощью asyncio.run(). В результате мы получим сообщения “Hello” и “World”, каждое через 1 и 2 секунды соответственно, при этом результаты двух задач были получены почти одновременно.

30
Q

Каким будет результат следующего выражения?

python
    >>> -30 % 10
   
A

Результатом выражения “-30 % 10” будет - 0. Это происходит потому, что оператор % возвращает остаток от деления первого числа на второе, и в данном случае -30 можно разбить на целое количество десяток и остаток 0. Поэтому -30 % 10 равно 0.

31
Q

Для чего нужен метод id()?

A

Метод id() используется для получения уникального целочисленного идентификатора (адреса в памяти) объекта. Этот идентификатор может быть использован для сравнения объектов, поскольку два объекта будут иметь одинаковый идентификатор только в том случае, если это один и тот же объект в памяти.

Например, если у вас есть две переменные, которые ссылаются на один и тот же объект, то их идентификаторы будут равны:

python
a = [1, 2, 3]
b = a
print(id(a))  # выведет адрес в памяти объекта a
print(id(b))  # выведет адрес в памяти объекта b
~~~
Однако, если у вас есть две переменные, которые ссылаются на разные объекты, их идентификаторы будут отличаться:
python
a = [1, 2, 3]
b = [1, 2, 3]
print(id(a)) # выведет адрес в памяти объекта a
print(id(b)) # выведет адрес в памяти объекта b (отличный от идентификатора a)
~~~
Использование метода id() может быть полезно при отладке или проверке, какие переменные ссылаются на один и тот же объект. Однако, в общем случае, использование метода id() не рекомендуется, поскольку это может быть неэффективным при работе с большим количеством объектов в памяти.
32
Q

Что такое итератор?

A

Итератор (Iterator) — это объект, который возвращает свои элементы по одному за раз. Он должен иметь метод __next__(), который возвращает следующий элемент и вызывает исключение StopIteration, когда элементы закончились. Итератор также может быть написан с помощью генераторов.

Пример использования итератора в Python:
```python
my_list = [1, 2, 3, 4, 5]

Получаем итератор из списка
my_iterator = iter(my_list)

Выводим элементы итератора
print(next(my_iterator)) # выведет 1
print(next(my_iterator)) # выведет 2
print(next(my_iterator)) # выведет 3
~~~
В этом примере мы создаем список и получаем из него итератор. Затем мы выводим элементы итератора с помощью функции next(), которая вызывает метод __next__() объекта итератора. Каждый вызов функции next() выводит следующий элемент, пока не закончатся элементы списка, после чего будет вызвано исключение StopIteration.

Еще один способ создания итераторов в Python — использование генераторов. Генератор — это функция, которая возвращает итерируемый объект (такой, как список или кортеж). Вместо того, чтобы возвращать все элементы сразу, генератор возвращает элементы по одному по мере необходимости.

Например:
```python
# Определяем генератор
def my_generator():
yield 1
yield 2
yield 3
yield 4
yield 5

Получаем итератор из генератора
my_iterator = my_generator()

Выводим элементы итератора
print(next(my_iterator)) # выведет 1
print(next(my_iterator)) # выведет 2
print(next(my_iterator)) # выведет 3
print(next(my_iterator)) # выведет 4
print(next(my_iterator)) # выведет 5
~~~

33
Q

Что такое генератор? Чем отличается от итератора?

A

Генератор - это функция, которая использует ключевое слово yield для возврата итератора. Генератор может быть использован для создания последовательности значений, которые генерируются в момент обращения к ним, что позволяет эффективно использовать память и ускоряет выполнение программы.

Отличие генератора от итератора заключается в том, что итератор используется для обхода коллекции (например, списка) до тех пор, пока все элементы не будут перебраны, а генератор используется для создания последовательности значений. Итераторы также могут быть созданы как классы, которые реализуют методы __iter__() и __next__(), в то время как генераторы создаются при помощи функций и используют ключевое слово yield.

Пример использования генератора, который генерирует последовательность чисел от 0 до n включительно:
```python
def my_generator(n):
for i in range(n + 1):
yield i

my_gen = my_generator(5)

for i in my_gen:
print(i)
~~~
Этот код создаст объект генератора my_gen, который можно использовать для последовательного получения каждого из значений, произведенных генератором при помощи ключевого слова yield.

34
Q

Для чего используется ключевое слово yield?

A

Ключевое слово “yield” используется для создания генераторов. Генератор - это функция, которая может возвращать последовательность значений используя инструкции yield вместо return. При каждом вызове инструкции yield генератор возвращает значение, после чего сохраняет свое состояние и приостанавливает свое выполнение до следующего вызова. Это позволяет генерировать последовательности значений без необходимости создания и хранения всех значений в памяти, что может быть особенно полезно при работе с большими объемами данных. Кроме того, генераторы являются итерируемыми и могут использоваться в циклах for.

35
Q

Чем отличаются \_\_iter\_\_ и \_\_next\_\_?

A

__iter__ и __next__ являются методами специальных методов в Python, которые обеспечивают поддержку итерации для объектов.

Метод __iter__ возвращает объект, который может быть использован для итерации по элементам контейнера. Объект, возвращаемый __iter__, должен содержать метод __next__.

Метод __next__ должен вернуть следующий элемент в итерации или вызвать исключение StopIteration, если элементов больше нет.

Таким образом, метод __iter__ используется для создания итератора, а метод __next__ используется для перехода к следующему элементу в итерации.

В общем случае, класс должен определять метод __iter__, который возвращает сам объект класса, и метод __next__, который определяет, какие элементы будут возвращены при итерации.

Например:

```python
class MyIterator:
def __init__(self, data):
self.index = 0
self.data = data

def \_\_iter\_\_(self):
    return self

def \_\_next\_\_(self):
    if self.index >= len(self.data):
        raise StopIteration
    result = self.data[self.index]
    self.index += 1
    return result ```         Метод \_\_iter\_\_ возвращает сам объект, а метод \_\_next\_\_ возвращает следующий элемент data каждый раз, когда вызывается.
36
Q

Что такое контекстный менеджер?

A

Контекстный менеджер в Python - это объект, который определяет вход и выход из контекста с помощью методов __enter__() и __exit__(). Контекстный менеджер может быть использован в блоке with для выполнения конкретных действий при входе и выходе из блока. Например, контекстный менеджер может устанавливать и закрывать соединение с базой данных, блокировать и разблокировать файлы или временно изменять настройки системы.

Вот простой пример, демонстрирующий использование контекстного менеджера для работы с файлом:

python
with open('file.txt', 'r') as f:
    data = f.read()

В этом примере open() возвращает контекстный менеджер f. Когда блок with начинается, вызывается метод __enter__() контекстного менеджера, который открывает файл. Затем выполняется код в блоке, который использует f для чтения данных из файла. При завершении блока with вызывается метод __exit__() контекстного менеджера, который закрывает файл.

Контекстные менеджеры в Python используются для обращения с ресурсами, которые должны быть корректно открыты и закрыты, включая файлы, сетевые соединения, блокировки и базы данных. Кроме того, их можно использовать для временной модификации состояния системы или окружения в блоках with.

37
Q

Как сделать python-скрипт исполняемым в различных операционных системах?

A

Для того чтобы сделать Python-скрипт исполняемым в различных операционных системах, можно воспользоваться утилитой PyInstaller, которая позволяет упаковать скрипт в исполняемый файл для Windows, Linux и macOS.

Чтобы установить PyInstaller, можно выполнить следующую команду в командной строке:

pip install pyinstaller

После установки PyInstaller необходимо перейти в директорию с Python-скриптом и запустить утилиту с соответствующими параметрами для создания исполняемого файла. Например:

pyinstaller myscript.py --onefile

Эта команда создаст единый исполняемый файл myscript.exe (для Windows) или myscript (для Linux/macOS), который можно запустить на соответствующих операционных системах.

Если нужно создать исполняемый файл с определенными параметрами, можно воспользоваться другими параметрами PyInstaller, такими как –icon для добавления иконки, –name для задания имени исполняемого файла и т.д.

Но стоит отметить, что PyInstaller не является универсальным решением и возможна потребность в использовании других инструментов в зависимости от конкретной задачи и требований к исполняемому файлу.

38
Q

Как сделать копию объекта? Как сделать глубокую копию объекта?

A

Метод copy() создает поверхностную копию объекта, то есть создает новый объект, который содержит ссылки на те же объекты, что и исходный объект. Если вы измените какой-либо из этих объектов, изменения отразятся и на копии, и на исходном объекте.

Метод deepcopy() создает глубокую копию объекта, то есть создает новый объект, который содержит копии всех объектов, на которые ссылаются элементы исходного объекта. Если вы измените какой-либо из этих объектов, изменения не отразятся на копии или на исходном объекте.

Вот примеры использования этих методов:
```python
import copy

создание копии объекта
new_list = old_list.copy()

создание глубокой копии объекта
new_list = copy.deepcopy(old_list)
где old_list - исходный список, а new_list - его копия.
~~~
Примечание: для выполнения глубокого копирования объектов, сами объекты также должны поддерживать копирование. Если объекты в ваших данных не поддерживают копирование, deepcopy() вернет исходный объект, а не его копию.

39
Q

Опишите принцип работы сборщика мусора в python.

A

Python использует автоматическое управление памятью, что означает, что разработчику не нужно явно выделять или освобождать память в своем коде. Вместо этого в Python есть встроенный сборщик мусора, который автоматически управляет памятью для объектов, на которые больше нет ссылок.

Сборщик мусора запускается периодически и ищет объекты, на которые больше не ссылается ни одна переменная в коде. Затем эти объекты идентифицируются как мусор и удаляются из памяти. Сборщик мусора работает, отслеживая ссылки на объекты в памяти, используя механизм подсчета ссылок. Каждый раз, когда создается новая ссылка на объект, счетчик ссылок для этого объекта увеличивается. Точно так же, когда ссылка удаляется, счетчик ссылок уменьшается.

Однако одного подсчета ссылок недостаточно для обработки всех случаев управления памятью. В некоторых случаях могут быть циклические ссылки, когда два или более объекта ссылаются друг на друга и больше не нужны. Для обработки этих случаев сборщик мусора Python использует вторичный механизм, называемый «обнаружение циклов». Этот механизм периодически ищет циклические ссылки среди объектов, и если они найдены, он знает, что нужно удалить циклическую ссылку и освободить память.

В целом, сочетание подсчета ссылок и обнаружения циклов позволяет Python автоматически управлять памятью и обеспечивать очистку объектов, когда они больше не нужны. Это приводит к более эффективному использованию памяти и снижает риск нехватки памяти в приложениях, которые долго работают или интенсивно используют память.

40
Q

Как использовать глобальные переменные? Это хорошая идея?

A

Для использования глобальных переменных достаточно объявить их за пределами функций и классов. Например:
```python
global_var = 42

def my_func():
# можно использовать глобальную переменную
global global_var
print(global_var)

вызываем функцию
my_func()
~~~
Однако, использование глобальных переменных не всегда считается хорошей практикой программирования, так как это может привести к ошибкам при изменении значения переменной в разных частях программы. Вместо этого, рекомендуется использовать локальные переменные внутри функций или передавать значения между функциями через параметры и возвращаемые значения.