Привет, Хабр! (И тебе, случайный читатель, который думает, что “код - это магия”, а процессор - маленький гномик, который внутри ноутбука читает for i in range(10) и послушно бегает кругами.)
Сегодня разберёмся с вопросом, который в какой-то момент приходит в голову каждому разработчику (пока его не вытеснил дедлайн):
Как компьютер "читает" Python, 1С или любой другой язык, если понимает только 0 и 1? И почему идеальный код порой превращается в "segmentation fault", "Неопределённую ошибку" или "Пользователь не найден" (хотя он сидит напротив)?
Мне самому спустя годы в разработке захотелось разобраться в этом "старомодном" Computer Science и понять, что такое программа на самом деле.

Поехали. Будет без хардкора уровня "компилятор за 21 день", но с понятными аналогиями. Я специально всё упростил до минимума, переварил информацию и упаковал в красивую обёртку. Кстати, в статье будут примеры из двух разных миров - Python и 1С, так что будет интересно.
(Статья будет большая, поэтому спойлер для тех, кому лень читать: программирование - это заговор по убеждению миллиардов транзисторов, что они умеют вести бухгалтерию.)
Глава 0. Компьютер тупой. Но очень, очень быстрый и послушный
Начнём с неприятной и фундаментальной правды, которую обычно прячут за красивыми словами вроде «инновации», «AI», «облачная нативная архитектура» и «у нас всё на микросервисах, поэтому мы можем масштабироваться горизонтально». Суровая реальность такова: компьютер вообще ничего не понимает и не осознаёт.
Вот прямо буквально. У него нет ни малейшего представления о мире. Для него не существует ни «документа», ни «отчёта», ни «пользователя». Всё, что у него есть, - это электрические импульсы, интерпретируемые как нули и единицы. Давайте пройдёмся по списку наших абстракций и посмотрим, как они выглядят на «кухне» процессора:
«Переменная totalSum» - для компьютера это просто: «эй, память! Дай-ка мне данные, которые лежат по адресу, скажем, 0x7ffeefbff58c (
011111111111111011101111101111111111010110001100). И не задавай вопросов».«Класс Customer с полями и методами» - это не более чем структурированный набор байтов в памяти. Кто-то (компилятор или интерпретатор) договорился, что первые 4 байта - это id, следующие 50 - это name, а вот по этому смещению лежит указатель на кусок кода, который нужно выполнить, если вызвали метод .save(). Сам объект об этом не «знает».
«Цикл for от 1 до 10» - на низком уровне это серия примитивных команд: 1) положи в регистр значение 1, 2) выполни тело цикла, 3) прибавь к регистру единицу (инкремент), 4) сравни с числом 10, 5) если не равно, безусловным переходом (JMP) прыгни назад к шагу 2. Никакой романтики, только прыжки.
«Табличная часть документа» - это, как правило, участок в памяти или отдельная таблица в базе данных, доступ к которому осуществляется по жёстким правилам, зашитым в платформу (вроде 1С). Для процессора это просто последовательные чтения и записи по разным адресам.
«Красиво вынесенная, абстрагированная и инкапсулированная бизнес-логика» - тут компьютер особенно «радуется». Для него это просто код, разбросанный по разным адресам памяти, связанный через таблицы виртуальных методов или указатели на функции. А если логика вынесена так «красиво», что её не может найти и человек, то для процессора это просто означает меньше работы - он будет счастливо простаивать, ожидая следующей инструкции.
Если свести всё к сухой, железячной истине, то вся работа процессора - это бесконечное повторение одного и того же примитивного набора действий:
FETCH (Выборка – пример на языке ассемблера: ldr x0, [PC, #offset]): Прочитай число (инструкцию или данные) из памяти или кэша.
DECODE (Декодирование - Выполняется аппаратно (контроллером инструкций), явно не кодируется): Разберись (с помощью ALU - арифметико-логического устройства), что эта инструкция означает.
EXECUTE (Исполнение – например сложение: add x1, x2, x3): Сложи/вычти/умножь/сравни/сдвинь биты.
WRITE-BACK (Сохранение - пример сохранения в память: str x1, [x4, #offset]): Запиши результат обратно в регистр или память.
Сделай условный или безусловный переход (JUMP/Branch – пример Безусловный переход: b label_name) на другой адрес в памяти, исходя из результата.
И всё. Цикл «Выборка-Декодирование-Исполнение» (Fetch-Decode-Execute cycle) - это альфа и омега его существования.
Никаких «высокоуровневых концепций», никаких «смыслов», никаких «но я же в коде написал ПровестиДокумент(), разве не очевидно, что нужно также обновить остатки?». Процессор - это супермотивированный, но очень ограниченный калькулятор: он делает примитивные действия со скоростью в миллиарды операций в секунду, создавая у нас иллюзию, будто он «умный» или хотя бы «понимает», что делает.
И вот тут возникает главный вопрос-парадокс: если компьютер настолько тупой, и работает только с нулями, единицами и прыжками, то почему мы, разработчики, не пишем программы на языке «прочитай-сравни-прыгни», а вместо этого используем Python, Java, C# или даже 1С с её «документами» и «справочниками»?
Ответ лежит в области великой человеческой лени и гениальности. Чтобы не общаться с процессором на его примитивном ассемблере (который является лишь читаемой формой машинных кодов), люди придумали абстракции и посредников.
Представьте, что вам нужно давать указания этому быстрому, но тупому работнику. Вы могли бы каждое утро говорить: «Вася, подойди к столу (адрес 0x…), возьми бумажку А (прочитай), отнеси её к столу Б (адрес 0x…), сравни с бумажкой Б, если они одинаковые, иди к шкафу (прыжок)…». Это утомительно и безумно.
Вместо этого вы создаёте слои управления:
Вы пишете инструкцию на человекочитаемом языке: «Вася, сверь приходную накладную со складскими остатками».
Ваш заместитель-менеджер (это компилятор или интерпретатор) берёт эту инструкцию и переводит её в подробный, но ещё понятный Васе список: «1. Иди к папке "Документы". 2. Возьми верхний лист…».
А сам Вася (процессор) тупо и быстро выполняет этот подробный список, не вникая в общий смысл операции.

Так и с программированием. Языки высокого уровня (Python, 1C, JavaScript …) - это наш способ говорить о «документах» и «логике». Компиляторы, интерпретаторы и виртуальные машины (как в 1C или Java) - это те самые менеджеры-переводчики, которые превращают наши высокоуровневые хотелки в миллиарды примитивных, тупых, но невероятно быстрых инструкций для процессора.
Ирония в том, что чем «проще» и «понятнее» для нас язык, тем больше работы приходится делать этим посредникам, чтобы уговорить тупое, но быстрое железо сделать то, что мы хотим. Это и есть фундамент всего программирования: мы строим воздушные замки из абстракций, которые в итоге должны быть возведены с помощью миллиардов кирпичиков-сложений и прыжков-проводов. А понимание этой пропасти между нашим мышлением и мышлением машины - первый шаг к тому, чтобы строить эти замки не только красиво, но и устойчиво.
Глава 1. Как Python превращается в “то, что можно выполнить”
Сто процентов каждый, кто начинал изучать Python, видели в своих курсах Python за 24 часа: «Python - интерпретируемый язык программирования». Начинающий разработчик обычно кивает, пропускает это мимо ушей и сразу переходит к написанию print("Hello, World!"). Но за этими скучными словами скрывается целая фабрика по превращению вашего красивого, почти псевдокода в реальные действия на процессоре. Давайте заглянем за кулисы.
Шаг 1: От вашего кода к «мыслям» интерпретатора (AST)
Вы написали простую и элегантную функцию:
def add(a, b):
return a + b
print(add(2, 3))Для вас это логика. Для операционной системы - просто текстовый файл с расширением .py. Что же происходит, когда вы нажимаете Enter в терминале, запуская python script.py?
Первым делом в дело вступает парсер (parser). Его задача - прочитать ваш текст, как учитель читает сочинение, и проверить его на грамматику. Он не оценивает смысл (пока), а проверяет, правильно ли расставлены двоеточия, скобки и ключевые слова. Если всё хорошо, он строит из вашего кода нечто под названием Абстрактное Синтаксическое Дерево (AST - Abstract Syntax Tree).
Представьте AST как сложную схему-инструкцию, где:
Корень дерева - это весь модуль.
Ветви - это операторы (def, print).
Листья - это конкретные элементы: имена (add, a, b), литералы (2, 3), операторы (+).
AST - это уже не текст, но ещё не инструкции. Это внутреннее, структурированное представление вашей программы, с которым удобно работать дальше. На этом этапе Python уже может кое-что понять о вашем коде, например, обнаружить очевидные синтаксические ошибки, но выполнить его ещё не может.
Шаг 2: Компиляция… в не машинный код (Hello, байткод!)
Вот здесь многих ждёт сюрп��из. Несмотря на статус «интерпретируемого», Python компилирует ваш код. Да, вы не ослышались. Но компилирует он его не в машинные команды для Intel или AMD, а в специальный промежуточный язык - байткод Python.
Это ключевой момент! Байткод - это НЕ машинный код вашего процессора. Это набор команд для так называемой Виртуальной Машины Python (PVM - Python Virtual Machine).
Можно думать об этом так:
Машинный код - это родной язык вашего процессора. Говорить на нём быстро, но сложно и для каждой архитектуры (x86, ARM) он свой.
Байткод Python - это универсальный язык внутреннего пользования для интерпретатора CPython. Это как «эсперанто» для всех Python-программ, независимо от того, на каком железе они запускаются.
Компилятор Python берет ваше AST и превращает его в последовательность этих самых байт-команд. Для нашей функции add байткод будет выглядеть примерно так (если заглянуть с помощью модуля dis):
LOAD_FAST 0 (a) # Загрузи переменную 'a' в стек
LOAD_FAST 1 (b) # Загрузи переменную 'b' в стек
BINARY_ADD # Выполни сложение верхних двух значений в стеке
RETURN_VALUE # Верни результат из стекаКаждая такая команда (например, LOAD_FAST, BINARY_ADD) - это цифровой код (байт), отсюда и название «байткод».
Зачем эти сложности? Именно байткод даёт Python его главные суперсилы:
Кроссплатформенность. Один и тот же файл .pyc (с скомпилированным байткодом) может запускаться на Windows, Linux и macOS. Заботиться о различиях в процессорах будет не ваша программа, а виртуальная машина Python, установленная на каждой из этих систем.
(Некоторая) оптимизация. Компиляция в байткод позволяет один раз проанализировать и оптимизировать код (например, предвычислить константы), чтобы потом интерпретатору было проще его выполнять.
Скорость (относительная). Интерпретировать байткод всё равно быстрее, чем каждый раз с нуля парсить и анализировать исходный текст.
Да, это всё звучит как “человек читает книгу о том, как читать книгу”.
Но это работает и удобно.

А почему тогда Python иногда быстрый?
Потому что:
Многие операции внутри вынесены в C (например, sum, list.append, части numpy)
Есть JIT-решения (PyPy) и спецоптимизации (например, PGO в сборке)
В numeric/ML мире тяжёлая работа часто делается вообще не Python-ом, а библиотеками на C/C++/Fortran
Итак, ваша программа прошла трансформацию: Текст (.py) -> Абстрактное Дерево (AST) -> Байткод (.pyc). Она готова к исполнению. Но кто и как будет выполнять эти байт-команды? Об этом - будет дальше, где на сцену выйдет главный «исполнитель» - виртуальная машина, наш трудолюбивый и немного медлительный посредник между красивым кодом и тупым, но быстрым железом.
Глава 2. А как, к примеру 1С "понимает" ваш код (и иногда делает вид, что понимает)
Ситуация с 1С философски похожа на другие языки, но уникальна в деталях. Вы пишете код на смеси русского, бухгалтерии и программирования, а исполняет его не процессор напрямую, а платформа 1С:Предприятие.
Платформа как менеджер
Представьте её как огромный офис со своими отделами (справочники), складом документов и бухгалтерией. Ваша роль - не строитель, а менеджер, который даёт задания «клеркам» платформы на их специфическом языке.
Технический процесс
Анализ: При запуске платформа читает ваш модуль, проводит синтаксический разбор и строит внутреннее дерево (AST), адаптированное под свои типы данных.
Компиляция: Код компилируется в промежуточный байт-код для собственной виртуальной машины (ВМ) 1С. Эти инструкции оптимизированы для работы с объектами метаданных, запросами и транзакциями.
Выполнение: ВМ 1С исполняет инструкции, взаимодействуя с ядром платформы, которое работает с СУБД и железом через множество слоёв.
Ключевое отличие: программирование платформы
В 1С вы программируете не «железо», а саму платформу. Ваши «Документы» и «Справочники» - это не структуры в памяти, а высокоуровневые абстракции, чьё поведение полностью реализовано внутри платформы.
Например, простая строка кода вызывает сложную цепочку действий платформы: проверку прав, запрос к базе, сериализацию данных. «Проведение документа» - это не ваша функция, а сложный сценарий платформы, который вы лишь инициируете.
Почему это важно?
Магия vs чёрные ящики: Благодаря этому 1С даёт много возможностей «из коробки» (движения регистров, блокировки и т.д.), но многие процессы - «чёрные ящики». Вы не можете изменить их ядро, только добавить обработчики на предоставленные «крючки».
Две реальности: Существует разрыв между вашим кодом и тем, что выполняется (тонны платформенного кода + SQL). Оптимизация часто сводится к тому, чтобы предугадать, как платформа преобразует ваш код.
Философия: Если в классических языках вы управляете памятью и структурами, то в 1С вы находитесь на уровень выше - программируете поверх огромного самодостаточного фреймворка.
Вы не строите дом, а расставляете умную мебель в уже готовом здании со строгими правилами. Понимание этого - ключ к эффективной работе с 1С-кой.
Глава 3. Одна и та же логика - разные пути до нулей и единиц
Давайте возьмём простую и понятную любому человеку мысль: «Если число больше десяти - вывести сообщение». Эту идею можно выразить на сотнях языков программирования. Но что происходит дальше - это удивительное путешествие, где один и тот же конечный пункт назначения достигается двумя совершенно разными дорогами с разными гидами.
Исходный код: человеческий взгляд
Python (человек пишет так, как ему удобно):
x = 12
if x > 10:
print("Большое")1С (человек пишет так, как принято в этой экосистеме):
x = 12;
Если x > 10 Тогда
Сообщить("Большое");
КонецЕсли;
Для нас, людей, разница - лишь в синтаксисе: двоеточия и отступы против точек с запятой и русских ключевых слов. Логика идентична. Но для компьютера это два совершенно разных технических задания, написанные на разных диалектах.
Что в итоге «видит» процессор? Суровая реальность железа
Вспомните теперь главу 0. Процессор не знает ни Если, ни print, ни Сообщить. Его мир - это регистры, ячейки памяти и прыжки. В конечном итоге, после всех трансформаций, он получает и исполняет последовательность примитивных команд, которая будет схожей по сути:
MOV (загрузка): Положить значение из ячейки памяти (где лежит x) в регистр процессора.
CMP (сравнение): Сравнить значение в регистре с числом 10.
JLE (условный переход): Если результат сравнения «меньше или равно» (not greater), то выполнить прыжок (JMP) по адресу за блоком кода вывода. Иначе - идти дальше.
CALL (вызов): Вызвать подпрограмму по конкретному адресу в памяти - ту самую, которая умеет выводить строки на экран или в лог. Перед этим где-то в памяти или регистре должен быть подготовлен адрес строки "Большое".
Продолжить выполнение следующих инструкций.
Вот и вся «интеллектуальная» работа. Это универсальный язык процессора, будь он от Intel, AMD или Apple.
Ключевое различие: кто прокладывает маршрут и водит экскурсию
Так в чём же тогда радикальная разница между запуском скрипта на Python и выполнением кода в 1С? Всё в цепочке посредников, которые берут ваш человеческий код и превращают его в эту примитивную последовательность. Именно здесь пути расходятся.
Путь Python: Ваш код -> Компилятор Python (байткод) -> Виртуальная машина Python (PVM) -> Стандартная библиотека C -> Системные вызовы ОС (например, write) -> Драйвер терминала/окна -> Процессор. Гид здесь - интерпретатор CPython и его байткод. Это относительно прямой и «технический» маршрут. Виртуальная машина Python заточена под общие алгоритмы и структуры данных. Когда вы вызываете print(), в конце концов, это превращается в вызов системной функции операционной системы для вывода текста.
Путь 1С: Ваш код -> Компилятор платформы 1С (внутренний байткод) -> Виртуальная машина 1С -> Ядро платформы 1С -> Менеджер памяти платформы + Менеджер транзакций -> Клиент-серверное взаимодействие (если есть) -> Драйвер СУБД (например, SQL) -> СУБД (например, PostgreSQL) -> Файловая система / Диск -> Процессор. Гид здесь - платформа 1С и её внутренняя система исполнения. Это маршрут через огромный логистический центр. Команда
Сообщить()- это не просто вывод текста. Это событие внутри платформы, которое должно кучу разных действий...
Суть в инфраструктуре
Таким образом, одна и та же бизнес-логика путешествует по разным технологическим ландшафтам. Python-код идёт по относительно прямой асфальтированной дороге общего назначения. Код 1С едет по сложной развязке собственной инфраструктуры платформы, которая заточена под бизнес-приложения: она сама управляет данными, транзакциями, безопасностью и интерфейсом.
Выбор языка - это во многом выбор экосистемы и гида, который будет вести ваш код от высокой идеи до низкоуровневых команд. И понимание глубины этого пути помогает не удивляться, почему одна и та же операция в разных средах может иметь совершенно разную стоимость с точки зрения производительности и отладки.
Глава 4. Мини-детектив: откуда берётся "0 и 1"

Мы постоянно говорим: «всё сводится к нулям и единицам». Но что это на самом деле значит? Это не какой-то тайный шифр или «формат хранения данных». Это фундаментальный физический принцип работы вычислительной техники. Давайте проведём небольшое расследование.
Улика №1: Всё - это числа. Даже команды.
Первое и ключевое откровение: Любая команда, которую исполняет процессор - это тоже число. Процессор не читает буквы. Он читает числа, поступающие на его входные контакты.
Представьте инструкцию для процессора как машинное слово - битовый шаблон с чёткой структурой. Условно, он может выглядеть так:
Старшие биты (opcode): Код операции. Это ответ на вопрос «Что делать?» (например, 1101 - сложить, 1000 - сравнить, 0110 - прыгнуть, если условие истинно).
Средние биты (operands): Операнды. Ответ на «С чем делать?» (номера регистров или адреса памяти: 001 - регистр AX, 010 - регистр BX).
Младшие биты (immediate/address): Непосредственное значение или смещение. «Куда прыгнуть?» (например, число -128 или +64 как относительный адрес прыжка).
Таким образом, ваша высокоуровневая конструкция if (x > 10) после всех трансформаций превращается в примерно такой числовой паёк для процессора:
[CMP] [Регистр_X] [Число_10] // Сравнить
[JG] [Смещение_на_адрес_блока_вывода] // Перейти, если больше (Jump if Greater)Каждая квадратная скобка - это конкретное число в двоичном виде. Процессор, получая на вход поток таких чисел, просто выполняет зашитую в него микроархитектурой логику: «О, код CMP - надо активировать АЛУ для сравнения. О, код JG - проверить флаги и, если нужно, подменить значение счётчика команд».
Ваш if - это, в машинных кодах, буквально число-приказ «прыгни или не прыгай».
Улика №2: Физическая природа двоичности. Почему не троичность?
Почему именно 0 и 1? Почему не 0, 1 и 2? Это не философский выбор, а инженерный императив.
В основе лежит способность простейших электронных компонентов (транзисторов) надёжно находиться в двух легко различимых устойчивых состояниях:
Условный «0»: Низкое напряжение (~0В). «Ключ выключен», тока нет.
Условная «1»: Высокое напряжение (например, +3.3В). «Ключ включен», ток течёт.
Третье, промежуточное состояние («полувключён») было бы неустойчивым, шумным и медленным. Работать с ним надёжно при миллиардах переключений в секунду - инженерный кошмар. (но такие кейсы существовали - Советская троичная ЭВМ «Сетунь»)
Двоичная система (бинарная) - это идеальный компромисс:
Надёжность (Robustness): Легко отличить «есть сигнал» от «нет сигнала» даже при помехах.
Простота (Simplicity): Базовые логические элементы (И, ИЛИ, НЕ) реализуются схемами из считанных транзисторов.
Масштабируемость (Scalability): Можно строить сколь угодно сложную логику, комбинируя эти простые кирпичики. Один транзистор - плохой вычислитель, но миллиарды транзисторов, организованные в правильную структуру, - это уже современный процессор.
Резюме следствия: Абстракция как слоёный пирог
Таким образом, цепочка превращений выглядит как матрёшка или многослойный пирог:
Физический слой (Physical Layer): Транзисторы, ток, напряжение. Устойчивые состояния → биты (0/1).
Логический слой (Logic Layer): Последовательности битов интерпретируются как числа (машинные коды и данные).
Архитектурный слой (Architectural Layer): Числа (машинные коды) заставляют процессор выполнять элементарные действия (сложение, прыжок, запись).
Слой среды исполнения (Runtime Layer): Виртуальные машины (Python, 1С) превращают свои байткоды в последовательности машинных кодов.
Слой языка (Language Layer): Компилятор или интерпретатор превращает ваш if в инструкции для виртуальной машины.
Ваш код (Source Code): Вы пишете
if (x > 10).
Глава 5. “Hello, World!” - это вообще не одна команда
Новичку кажется:
Написал print("Hello") → компьютер вывел Hello
На деле вы запускаете мини-сериал:
Вызвать print
Превратить объект в строку
Закодировать строку в байты (UTF-8)
Отправить в stdout
ОС решит куда "это писать" (терминал/файл/pipe)
Драйвер/терминал нарисует символы
Видеосистема обновит картинку
Монитор зажжёт пиксели
Вы хотели "привет". Получили цепочку из ОС, драйверов и железа, которая делает вид, что это "просто вывод".
Вывод (и немного морали)
Компьютер понимает только машинные инструкции, которые в памяти выглядят как нули и единицы.
Python или 1С или даже Emojicode напрямую процессору не интересны - их исполняют промежуточные слои (интерпретатор/платформа/виртуальная машина).
Весь мир программирования - это слои абстракций, которые спасают нас от необходимости писать “перейти на адрес 0x…” вместо for.
Если ваш код работает - это значит, что миллионы маленьких механизмов правильно договорились между собой. А если не работает - значит, кто-то в этой цепочке решил "я сегодня не в ресурсе" или ваш код полный бред, тут уже решать вам.
Спасибо, что дочитали эту статью до конца, это была моя интерпретация хендбука от Яндекса - Основы компьютерных наук и книг Теоретический минимум по Computer Science (Владстон Феррейра Фило) и Структура и интерпретация компьютерных программ (Гарольд Абельсон, Джеральд Джей Сассман) и годов разработки на разных языках программирования. Погружение во всё это оказалось довольно интересным и от части пугающим, и я надеюсь это даст вам мотивацию так же окунуться в дебри компьютерных наук или как это более красивее называть Computer Science.