# Как работает компьютер: компоненты, запуск программы и языки программирования<no value>

## В этом уроке

Урок состоит из нескольких коротких глав — в том же порядке, что и в презентации:

1. **Глава 1** — компоненты компьютера: CPU, RAM, накопитель и регистры
2. **Глава 2** — что происходит с момента запуска программы до её выполнения
3. **Глава 3** — виды языков программирования: от машинного кода до Python

## Глава 1: Компоненты компьютера: CPU, RAM, накопитель и регистры

### Что мы изучим?

Мы откроем «крышку» компьютера и познакомимся с четырьмя компонентами, которые должен понимать каждый программист:

| Компонент | В одной строке |
|---|---|
| **CPU** | Мозг — выполняет инструкции. |
| **Регистры** | Крошечные, чрезвычайно быстрые ячейки памяти **внутри** CPU. |
| **RAM** | Рабочий стол — быстрая временная память для программ, работающих прямо сейчас. |
| **Накопитель** | Архив — постоянное хранилище файлов, даже когда компьютер выключен. |

### Зачем это нужно?

Каждая строка кода, которую вы напишете на курсе, проходит через эти компоненты. Поняв их, вы поймёте и то, что сейчас кажется «магией»:

- Почему переменная исчезает, когда программа завершается, а файл остаётся?
- Почему программа, читающая с диска, медленнее программы, работающей только в памяти?
- Почему компьютер «зависает», когда открыто слишком много программ?
- Почему в темах бэкенда и баз данных мы храним информацию в **базе данных** (на накопителе), а не просто в переменной?

На собеседованиях часто спрашивают «в чём разница между RAM и накопителем» — этот вопрос проверяет, понимаете ли вы основы.

### Объяснение с основ

#### CPU — центральный процессор

**CPU** (Central Processing Unit, «процессор») — компонент, который **выполняет** инструкции. Он умеет делать только очень простые операции: сложить два числа, сравнить, скопировать значение из одного места в другое, перейти к другой инструкции. Его сила — **скорость**: миллиарды инструкций в секунду.

- **Тактовая частота**, измеряется в ГГц: 3 GHz ≈ три миллиарда «тактов» в секунду.
- **Ядро**: у современного процессора несколько ядер, и каждое ядро — как маленький отдельный процессор. 8 ядер = 8 дел параллельно.

**Связь с запуском программы:** каждая строка Python, которую вы пишете, в итоге превращается во множество маленьких инструкций, и CPU выполняет их одну за другой.

#### Регистры

**Регистры** — крошечные ячейки памяти (каждая хранит одно число) **внутри самого CPU**. Это самая быстрая память в компьютере. Чтобы сложить два числа, CPU сначала приносит их из RAM в регистры, вычисляет и сохраняет результат в регистре.

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

#### RAM — оперативная память

**RAM** (Random Access Memory) — память, в которой хранятся **программы, работающие прямо сейчас, и их данные**. Когда вы пишете `name = "Dana"`, значение `"Dana"` хранится в RAM.

Два важных свойства:

1. **Быстрая** — намного быстрее накопителя (в тысячи раз).
2. **Временная (volatile)** — когда программа завершается или компьютер выключается, содержимое стирается.

#### Накопитель — постоянное хранилище

**Накопитель** (storage) — это диск: **SSD** (быстрый, без движущихся частей) или **HDD** (вращающийся диск, старее и медленнее). Здесь хранятся операционная система, установленные программы и все ваши файлы, включая `hello.py`.

1. **Постоянный (non-volatile)** — информация остаётся даже при выключенном компьютере.
2. **Большой и дешёвый** — от сотен ГБ до ТБ, по сравнению с 8–32 ГБ RAM.
3. **Медленный** по сравнению с RAM.

{{< box "analogy" "Аналогия с кухней" >}}
- **Накопитель** = кладовая: вмещает много, всё хранится долго, но за вещами нужно идти.
- **RAM** = кухонный стол: на него кладут только то, что готовят прямо сейчас. Удобно и быстро, но в конце дня стол убирают.
- **Регистры** = руки повара: держат только то, с чем работают в этот момент.
- **CPU** = повар: выполняет действия (режет, мешает, вычисляет).
{{< /box >}}

#### Почему не обойтись одним компонентом?

| | Регистры | RAM | Накопитель |
|---|---|---|---|
| Скорость | Самые быстрые | Быстрая | Относительно медленный |
| Размер | Крошечный (байты) | Средний (ГБ) | Огромный (сотни ГБ–ТБ) |
| Сохраняется после выключения? | Нет | Нет | **Да** |
| Цена за ГБ | Очень дорого | Дорого | Дёшево |

Ни один компонент не бывает одновременно очень быстрым, огромным, дешёвым и постоянным. Поэтому компьютер сочетает их все: то, что нужно **сейчас**, держится рядом с CPU, а то, что нужно **надолго**, — на диске.

### Как читать характеристики компьютера

Всё, что мы изучили, указано в характеристиках любого компьютера — в магазине, на сайте производителя или в диспетчере задач. Типичные характеристики ноутбука:

```text
CPU       8 cores, 3.2 GHz
RAM       16 GB       (temporary)
Storage   512 GB SSD  (permanent)
OS        Windows 11, 64-bit (x64)
```

| Строка | Что она говорит |
|---|---|
| `8 cores` | Восемь ядер — до восьми дел, которые CPU действительно делает параллельно. |
| `3.2 GHz` | Тактовая частота — около 3,2 миллиарда тактов в секунду. |
| `16 GB` RAM | Сколько места для программ, работающих **сейчас**, и их данных. |
| `512 GB SSD` | Сколько файлов и программ можно хранить **надолго**. |
| `64-bit (x64)` | Архитектура — «язык инструкций», который понимает процессор. |

Те же данные можно увидеть на самом компьютере: в Windows — в **диспетчере задач** (`Ctrl + Shift + Esc`) → **Производительность**, на Mac — в **Мониторинге системы**. Там же в реальном времени видно, сколько RAM занято и как это число растёт, когда открываешь всё больше программ.

### RAM и накопитель на практике

| | RAM | Накопитель |
|---|---|---|
| Что там | Программы, работающие сейчас, и их данные | Файлы, установленные программы, операционная система |
| Скорость | Очень быстрая | Медленнее |
| Типичный размер | 8–32 ГБ | От сотен ГБ до ТБ |
| Когда программа завершается или компьютер выключается | **Стирается** | **Сохраняется** |

**Связь с программированием:** каждая **переменная**, которую вы пишете в программе, живёт в **RAM**. При каждом запуске программа получает новую, пустую память, а когда она завершается — память освобождается, и значения исчезают. Поэтому счётчик внутри программы при каждом новом запуске «начинает с нуля».

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

### Типичная ошибка

**Ошибка — «я добавил RAM, значит, компьютер будет хранить больше файлов»**, или наоборот: «у меня диск на 1 ТБ, значит, памяти мне хватает».

Это два разных ресурса:

- **Мало RAM** → компьютер тормозит, когда открыто много программ. Операционная система начинает переносить части RAM на диск (это называется **swap** / файл подкачки), а диск медленный.
- **Мало места на накопителе** → негде сохранять файлы и устанавливать программы.

**Вторая ошибка — «я сохранил», но только в RAM.** Программа показывает сообщение «Сохранено!», но на самом деле информация лежит только в переменной, то есть в RAM. Пока программа работает — всё выглядит хорошо. Когда она закрывается или компьютер выключается — данные исчезают. Настоящее сохранение — это всегда **запись на накопитель**.

### Итоги

- **CPU** выполняет инструкции. **Ядра** позволяют параллельное выполнение, а **ГГц** измеряет частоту тактов.
- **Регистры** — самая крошечная и быстрая память, **внутри** CPU, хранят то, что вычисляется прямо сейчас.
- **RAM** — быстрая и временная: в ней живут переменные, и они исчезают в конце программы.
- **Накопитель** (SSD/HDD) медленнее, но постоянный: файлы остаются даже после выключения.
- Чтобы сохранённое пережило выключение, нужно записать его на **накопитель** (в файл / в базу данных).

<!-- docs:start — generated by scripts/intro6/site_docs.py; edit the links there -->

### Официальная документация

- [Windows — Memory Management](https://learn.microsoft.com/en-us/windows/win32/memory/memory-management)
- [Windows — About Memory Management](https://learn.microsoft.com/en-us/windows/win32/memory/about-memory-management)

<!-- docs:end -->

## Глава 2: Что происходит с момента запуска программы до её выполнения

### Что мы изучим?

В предыдущей главе мы познакомились с компонентами по отдельности. Теперь соединим их в одну историю: **что происходит с момента запуска программы до её выполнения.** Пройдём общий путь любой программы, а затем — особый путь файла на Python.

### Зачем это нужно?

- Когда программа «не запускается», вы будете знать, что спросить: **на каком шаге** произошёл сбой? Файл не найден? Нет прав? Не хватает памяти?
- Когда в теме Python пойдёт речь об **ошибке выполнения** и **синтаксической ошибке**, разница между ними вытекает именно из шагов, которые мы здесь изучим.
- В темах бэкенда и баз данных мы будем запускать **сервер** — программу, которая не завершается, а продолжает работать и ждать запросов. Чтобы понять это, сначала нужно понять, что такое работающая программа.

### Объяснение с основ

#### Сохранённая программа и работающая программа

**Программа**, которая не запущена, — это просто **файл на диске**, последовательность байтов на накопителе. Чтобы она что-то «делала», её нужно загрузить в RAM, и CPU должен выполнять её инструкции. Программа во время работы называется **процессом**. Это различие очень важно, и мы углубимся в него в следующем уроке.

#### Общий путь — 6 шагов

1. **Запрос** — пользователь дважды щёлкает по значку или набирает команду в терминале.
2. **Поиск** — **операционная система** ищет файл программы на накопителе.
3. **Проверка прав** — операционная система проверяет, разрешено ли этому пользователю запускать файл.
4. **Создание процесса** — операционная система регистрирует новый процесс, даёт ему идентификационный номер (**PID** — process ID) и выделяет ему собственную область памяти в RAM.
5. **Загрузка в RAM** — операционная система копирует инструкции программы с диска в область памяти процесса и ставит его в очередь CPU.
6. **Выполнение** — CPU начинает выполнять инструкции одну за другой в цикле, который называется **Fetch → Decode → Execute**.

#### Цикл Fetch → Decode → Execute

Это «сердцебиение» любого компьютера. CPU повторяет его миллиарды раз в секунду:

| Шаг | Что происходит | Какой компонент |
|---|---|---|
| **Fetch** | CPU приносит следующую инструкцию из RAM. Специальный регистр (счётчик команд) помнит, где он находится. | RAM → регистры |
| **Decode** | CPU определяет, что это за инструкция: сложить? сравнить? скопировать? | CPU |
| **Execute** | CPU выполняет её. Результат сохраняется в регистре и при необходимости возвращается в RAM. | CPU, регистры, RAM |

{{< box "analogy" "Аналогия" >}}
Повар с рецептом: **Fetch** — читает следующую строку рецепта. **Decode** — понимает, что там написано «нарезать лук». **Execute** — режет. Затем переходит к следующей строке. Рецепт (программа) лежит на столе (RAM), а повар (CPU) держит в руках (регистрах) только то, с чем работает прямо сейчас.
{{< /box >}}

#### А что происходит с Python?

CPU не понимает Python. Он понимает только **машинный код** своей архитектуры. Так что же происходит, когда вы набираете `python hello.py`?

1. Операционная система находит программу `python` (файл `python.exe` в Windows), создаёт **процесс** и загружает в него программу. На CPU работает **интерпретатор**, который сам является программой в машинном коде.
2. Интерпретатор читает `hello.py` с диска.
3. Он **проверяет синтаксис** и **переводит** (компилирует) весь файл в простой промежуточный язык, который называется **байт-код** (bytecode). Если есть синтаксическая ошибка, процесс останавливается здесь, **до того как выполнится хоть одна строка**.
4. **PVM** (Python Virtual Machine) — часть интерпретатора, выполняющая байт-код, — проходит по инструкциям одну за другой и выполняет их. Если какая-то строка падает (например, деление на ноль), ошибка возникает **во время выполнения**, а строки, которые уже выполнились, — выполнились.
5. Когда код заканчивается, процесс завершается, и операционная система освобождает его RAM.

```text
hello.py (Storage)
   │  python reads the file
   ▼
Syntax check + compile  ──►  Bytecode  (in RAM)
   │
   ▼
PVM executes bytecode instruction by instruction
   │  each instruction = many machine instructions
   ▼
CPU: Fetch → Decode → Execute (billions per second)
```

### Каждый запуск — новый процесс

Когда вы запускаете один и тот же файл три раза, операционная система создаёт **три разных процесса** — у каждого свой **PID** (process ID) и новая область памяти:

```text
python hello.py   ->  new Process, PID 14872
python hello.py   ->  new Process, PID 9316
python hello.py   ->  new Process, PID 20480
```

**Программа** (файл `hello.py`) не изменилась. Каждый **процесс** — отдельный её запуск, который рождается, работает и исчезает. Это можно увидеть своими глазами в диспетчере задач: процесс с именем `python` появляется, пока программа работает, и исчезает, когда она завершается.

### Типичная ошибка

**Ошибка: думать, что все ошибки возникают в один и тот же момент.** Есть два совершенно разных момента:

```text
print("Line 1 runs?")
print("Line 3"
→ SyntaxError: '(' was never closed
  (nothing runs at all)

print("Line 1 runs")
print(10 / 0)
→ Line 1 runs
→ ZeroDivisionError: division by zero
```

- **SyntaxError** обнаруживается на шаге **проверки синтаксиса**, до создания байт-кода, — поэтому **не выполняется ни одна строка**, даже первая.
- **ZeroDivisionError** — ошибка **времени выполнения**: PVM уже выполнила строки перед ней и останавливается только тогда, когда доходит до проблемной строки.

Так определяют, **на каком шаге пути** проблема: если ничего не напечаталось — вероятно, синтаксис. Если часть напечаталась — проблема в строке, на которой программа остановилась.

### Итоги

- Программа на диске — просто файл. Когда она работает, это **процесс** со своим **PID** и областью в RAM.
- Операционная система находит файл, проверяет права, создаёт процесс и загружает программу в его память в RAM.
- CPU выполняет инструкции в цикле **Fetch → Decode → Execute** с помощью регистров.
- В Python: код проверяется и переводится в **байт-код**, а затем его выполняет **PVM**.
- **Синтаксическая ошибка** останавливает всё до первой строки. **Ошибка выполнения** останавливает на середине, после того как предыдущие строки уже выполнились.

<!-- docs:start — generated by scripts/intro6/site_docs.py; edit the links there -->

### Официальная документация

- [Windows — About Processes and Threads](https://learn.microsoft.com/en-us/windows/win32/procthread/about-processes-and-threads)
- [Python Glossary — bytecode](https://docs.python.org/3/glossary.html#term-bytecode)

<!-- docs:end -->

## Глава 3: Виды языков программирования: от машинного кода до Python

### Что мы изучим?

В предыдущей главе мы увидели, что CPU выполняет инструкции в цикле Fetch → Decode → Execute. Теперь спросим: **откуда берутся эти инструкции?** Мы изучим:

- Что такое **машинный код** и почему на нём никто не пишет.
- Разницу между **низкоуровневыми** и **высокоуровневыми** языками.
- Два способа перевести код в инструкции: **компилятор** и **интерпретатор**.
- Где находится **Python** и почему мы выбрали его для курса.

### Зачем это нужно?

Когда начинаешь программировать, постоянно слышишь фразы вроде «C быстрый», «Python медленный», «JavaScript работает в браузере» или «это нужно скомпилировать». Без понимания того, **как** код превращается в инструкции, которые выполняет CPU, эти фразы звучат как магия.

Это понимание помогает и на практике:

- Понять, **почему** Python находит синтаксическую ошибку ещё до запуска кода, а другие ошибки — только посреди выполнения.
- Выбрать правильный инструмент для задачи — и понять, почему компании используют несколько языков одновременно.
- Ответить на классический вопрос собеседования: «В чём разница между компилируемым и интерпретируемым языком?»

### Объяснение с основ

#### Что на самом деле понимает CPU

Процессор понимает только **двоичные инструкции** — последовательности нулей и единиц. Каждая инструкция — очень маленькое действие: «скопировать число в эту ячейку», «сложить два числа», «перейти по другому адресу». Это называется **машинным кодом**.

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

**Язык программирования** — это мост: мы пишем на удобном для нас языке, а специальная программа переводит его в инструкции, понятные CPU.

#### Низкий уровень и высокий уровень

Одно и то же действие — сохранить букву `a` — на нескольких уровнях:

```text
Machine Code   10110000 01100001
Assembly       MOV AL, 61h
C              char c = 'a';
Python         c = "a"
```

- **Низкоуровневые** — близко к машине. Вы управляете каждой деталью: памятью, регистрами, каждой инструкцией. Очень быстро, но трудно писать и легко ошибиться. Примеры: ассемблер и в значительной степени C.
- **Высокоуровневые** — близко к человеческому языку. Язык заботится о деталях за нас: управление памятью, типы данных, готовые списки и словари. Легко писать и читать, и обычно медленнее при выполнении. Примеры: Python, JavaScript, Java.

#### Компилируемые — перевести всё заранее

В **компилируемом языке** программа, которая называется **компилятором**, читает весь код **до** запуска, проверяет его и переводит в исполняемый файл в машинном коде. Затем вы запускаете этот файл — сколько угодно раз, не переводя заново.

```text
Compiled (C, Go, Rust):
  source code -> compiler -> program.exe -> run
  translate once, run many times
```

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

#### Интерпретируемые — перевод во время выполнения

В **интерпретируемом языке** программа, которая называется **интерпретатором**, читает код **во время его выполнения** и выполняет его по мере перевода.

```text
Interpreted (Python, JavaScript):
  source code -> interpreter -> run, line by line
  translate every time you run
```

- **Преимущество:** очень удобно для разработки — изменил строку и сразу запустил. Один и тот же код работает на любом компьютере, где установлен интерпретатор.
- **Недостаток:** медленнее при выполнении, потому что перевод происходит каждый раз заново.

{{< box "analogy" "Аналогия: переведённая книга и синхронный переводчик" >}}
**Компилятор** — как переводчик, который переводит всю книгу до того, как она попадёт в магазины. Это занимает время, но потом каждый читатель просто читает — быстро.

**Интерпретатор** — как синхронный переводчик на лекции: переводит предложение за предложением в реальном времени. Не нужно ждать заранее, но для каждой лекции снова нужен переводчик.
{{< /box >}}

#### Известные языки и для чего они используются

| Язык | Уровень | В основном используется для... |
|---|---|---|
| **Python** | Высокоуровневый, интерпретируемый | Данные, искусственный интеллект, серверы, автоматизация |
| **JavaScript** | Высокоуровневый, интерпретируемый | Веб-сайты — в браузере и на сервере |
| **Java / C#** | Высокоуровневые, компилируются в промежуточный шаг | Большие бизнес-системы, приложения |
| **C / C++** | Относительно низкоуровневые, компилируемые | Операционные системы, игры, оборудование |

#### А где же Python?

Python — **высокоуровневый**, **интерпретируемый** язык. Но за кулисами есть промежуточный шаг, как мы видели в предыдущей главе:

1. Python читает весь файл и проверяет синтаксис — поэтому **SyntaxError** останавливает всё до первой строки.
2. Он переводит код в **байт-код** — простые промежуточные инструкции.
3. **PVM** (Python Virtual Machine) выполняет байт-код инструкция за инструкцией — и ошибки вроде **ZeroDivisionError** обнаруживаются только при достижении этой строки.

Ещё одно важное свойство: Python — **динамический** язык: тип переменной не объявляется заранее. Одна и та же переменная может хранить число, а потом текст.

### Типичная ошибка

**«Какой язык лучший?»** — вопрос, на который нет ответа.

- **Лучшего языка нет — есть язык, который подходит для задачи.** 3D-игре нужна скорость C++, анализу данных — библиотеки Python, сайту — JavaScript.
- Язык, быстрый при выполнении, обычно медленнее в написании, и наоборот.
- **Идеи переносятся между языками:** переменные, условия, циклы, функции и объекты есть почти в каждом языке. Тот, кто хорошо выучил один язык, следующий осваивает гораздо быстрее.

Ещё одна ошибка: думать, что «интерпретируемый» значит «ничего не проверяет заранее». Python проверяет синтаксис всего файла перед запуском — он просто не создаёт отдельный исполняемый файл.

### Итоги

- CPU понимает только **машинный код** — нули и единицы. Язык программирования — мост между нами и им.
- **Низкоуровневые** — близко к машине, быстрые и сложные. **Высокоуровневые** — близко к людям, читаемые и удобные.
- **Компилятор** переводит всё заранее в исполняемый файл — быстрое выполнение. **Интерпретатор** переводит во время выполнения — удобная разработка.
- **Python** — высокоуровневый, интерпретируемый и динамический, с шагом **байт-кода**, который выполняет **PVM**.
- Лучшего языка нет — есть язык, подходящий для задачи, и идеи переносятся между языками.

<!-- docs:start — generated by scripts/intro6/site_docs.py; edit the links there -->

### Официальная документация

- [Python FAQ — What is Python?](https://docs.python.org/3/faq/general.html#what-is-python)
- [Python Glossary — interpreted](https://docs.python.org/3/glossary.html#term-interpreted)

<!-- docs:end -->

<!-- exercises:start — generated by scripts/intro6/sync_site_exercises.py; edit scripts/intro6/exercises/ -->
## Практика

Вопросы на понимание материала урока — без кода.

### Упражнение 1: Какой компонент?

Для каждого описания — какой компонент подходит: CPU, регистры, RAM или накопитель?

1. Стирается, когда компьютер выключается, и хранит переменные работающей программы.
2. Выполняет миллиарды инструкций в секунду.
3. Хранит файлы, даже когда нет питания.
4. Крошечные, чрезвычайно быстрые ячейки памяти внутри процессора.

{{< solution >}}
1. **RAM** — быстрая временная (volatile) память.
2. **CPU** — процессор, который выполняет инструкции.
3. **Накопитель** (SSD/HDD) — постоянное (non-volatile) хранилище.
4. **Регистры** — хранят то, с чем CPU работает в данный момент.
{{< /solution >}}

### Упражнение 2: Читаем характеристики

Вот характеристики ноутбука:

```text
CPU       8 cores, 3.2 GHz
RAM       16 GB
Storage   512 GB SSD
```

1. Что означает `8 cores`?
2. Дани говорит: «У меня 512 ГБ, значит, я могу открыть сколько угодно программ, и компьютер не будет тормозить». В чём ошибка?

{{< solution >}}
1. **Восемь ядер** — до восьми дел, которые CPU действительно делает параллельно.
2. 512 ГБ — это **накопитель**, место для сохранения файлов. Программы, работающие сейчас, находятся в **RAM**, а её всего 16 ГБ. Когда RAM заполняется, операционная система переносит её части на диск (swap), и компьютер начинает тормозить.
{{< /solution >}}

### Упражнение 3: От файла к процессу

Дана дважды щёлкает по значку программы, установленной на компьютере. Расставьте четыре шага в порядке, в котором они происходят, — с момента, когда программа сохранена на диске, до её выполнения. Запишите порядок букв.

- (а) Операционная система создаёт новый процесс с PID и собственной областью памяти
- (б) Операционная система находит файл программы на диске (накопителе)
- (в) CPU выполняет инструкции программы одну за другой (fetch, decode, execute)
- (г) Операционная система загружает инструкции программы с диска в область памяти процесса в RAM

{{< solution >}}
Порядок: **(б), (а), (г), (в)**

1. **(б)** Операционная система находит файл программы на накопителе.
2. **(а)** Она создаёт новый процесс — даёт ему PID и выделяет собственную область памяти в RAM.
3. **(г)** Она копирует инструкции программы с диска в область памяти процесса.
4. **(в)** CPU выполняет инструкции одну за другой — приносит, декодирует и выполняет.

Почему (а) перед (г)? Сначала нужен «дом» в памяти — процесс с его областью памяти, — и только потом в него можно скопировать инструкции.
{{< /solution >}}

### Упражнение 4: Ошибка — на каком шаге?

В каждом из следующих случаев: это синтаксическая ошибка (SyntaxError) или ошибка выполнения? И была ли напечатана первая строка?

```text
# Program A
print("Start")
print("End"

# Program B
print("Start")
print(10 / 0)
```

{{< solution >}}
- **Программа A — SyntaxError** (не закрыта скобка). Python проверяет синтаксис всего файла **до** выполнения любой строки, поэтому **ничего не напечаталось**, даже `Start`.
- **Программа B — ошибка выполнения** (`ZeroDivisionError`). Синтаксис в порядке, поэтому программа начала работать: `Start` **напечатался**, а ошибка возникла только при переходе ко второй строке.
{{< /solution >}}

### Упражнение 5: Компилируемый и интерпретируемый

1. В чём разница между компилятором и интерпретатором?
2. Назовите одно преимущество каждого подхода.
3. Где в этой картине находится Python и какова роль байт-кода и PVM?

{{< solution >}}
1. **Компилятор** переводит весь код **заранее** в исполняемый файл в машинном коде. **Интерпретатор** переводит и выполняет код **во время его работы**.
2. Преимущества:
   - **Компилируемый** — быстрое выполнение, потому что перевод уже сделан.
   - **Интерпретируемый** — удобно для разработки: изменил строку и сразу запустил, и один и тот же код работает на любом компьютере, где есть интерпретатор.
3. **Python — высокоуровневый интерпретируемый язык.** За кулисами он проверяет синтаксис и переводит код в **байт-код** (промежуточные инструкции), а затем **PVM** (Python Virtual Machine) выполняет байт-код инструкция за инструкцией.
{{< /solution >}}

<!-- exercises:end -->
