Есть ли способ узнать, с помощью какой версии Python был скомпилирован файл .pyc?

#python #compilation

#python #Сборник

Вопрос:

Есть ли какой-либо способ узнать, с помощью какой версии Python .pyc был скомпилирован файл?

Ответ №1:

Первые два байта .pyc файла — это магическое число, которое указывает версию байт-кодов. Слово хранится в формате с малым порядком, а известные значения:

Версия Python Десятичный Шестнадцатеричный Комментарий
Python 1.5 20121 0x994e
Python 1.5.1 20121 0x994e
Python 1.5.2 20121 0x994e
Python 1.6 50428 0x4cc4
Python 2.0 50823 0x87c6
Python 2.0.1 50823 0x87c6
Python 2.1 60202 0x2aeb
Python 2.1.1 60202 0x2aeb
Python 2.1.2 60202 0x2aeb
Python 2.2 60717 0x2ded
Python 2.3a0 62011 0x3bf2
Python 2.3a0 62021 0x45f2
Python 2.3a0 62011 0x3bf2 !
Python 2.4a0 62041 0x59f2
Python 2.4a3 62051 0x63f2
Python 2.4b1 62061 0x6df2
Python 2.5a0 62071 0x77f2
Python 2.5a0 62081 0x81f2 ast-ветвь
Python 2.5a0 62091 0x8bf2 with
Python 2.5a0 62092 0x8cf2 изменен WITH_CLEANUP код операции
Python 2.5b3 62101 0x95f2 исправить неправильный код: for x, in ...
Python 2.5b3 62111 0x9ff2 исправить неправильный код: x = yield
Python 2.5c1 62121 0xa9f2 исправьте неправильный lnotab с помощью циклов for и сохранения констант, которые должны были быть удалены
Python 2.5c2 62131 0xb3f2 исправить неправильный код: for x, in ... в listcomp / genexp
Python 2.6a0 62151 0xc7f2 оптимизация глазка и STORE_MAP код операции
Python 2.6a1 62161 0xd1f2 WITH_CLEANUP оптимизация
Python 2.7a0 62171 0xdbf2 оптимизация понимания / изменения списка LIST_APPEND
Python 2.7a0 62181 0xe5f2 оптимизация условных ветвей: введение POP_JUMP_IF_FALSE и POP_JUMP_IF_TRUE
Python 2.7a0 62191 0xeff2 представляем SETUP_WITH
Python 2.7a0 62201 0xf9f2 представляем BUILD_SET
Python 2.7a0 62211 0x03f3 представьте MAP_ADD и SET_ADD
Python 3000 3000 0xb80b
3010 0xc20b Удалено UNARY_CONVERT
3020 0xcc0b добавлено BUILD_SET
3030 0xd60b добавлены параметры только для ключевых слов
3040 0xe00b добавлены аннотации подписи
3050 0xea0b print становится функцией
3060 0xf40b Синтаксис метакласса PEP 3115
3061 0xf50b строковые литералы становятся юникодом
3071 0xff0b PEP 3109 вызывает изменения
3081 0x090c PEP 3137 make __file__ и __name__ unicode
3091 0x130c убейте интернирование str8
3101 0x1d0c слияние с 2.6a0, см. 62151
3103 0x1f0c __file__ указывает на исходный файл
Python 3.0a4 3111 0x270c WITH_CLEANUP оптимизация
Python 3.0a5 3131 0x3b0c лексическое накопление исключений, включая POP_EXCEPT
Python 3.1a0 3141 0x450c оптимизация понимания списков, наборов и диктовок: изменение LIST_APPEND и SET_ADD добавление MAP_ADD
Python 3.1a0 3151 0x4f0c оптимизация условных ветвей: введение POP_JUMP_IF_FALSE и POP_JUMP_IF_TRUE
Python 3.2a0 3160 0x580c добавить SETUP_WITH , тег: cpython-32
Python 3.2a1 3170 0x620c добавить DUP_TOP_TWO , удалить DUP_TOPX и ROT_FOUR , тег: cpython-32
Python 3.2a2 3180 0x6c0c Добавить DELETE_DEREF

Источники:

  • Python / import.c — объединенный aix с Python 2.7.2 и Python 3.2.2
  • Небольшие шестнадцатеричные значения для сравнения первых двух байтов метода Игоря Попова, добавленные jimbob

Комментарии:

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

2. @AamirAdnan: Но что, если у вас случайно нет версии python, которая создала файл .pyc?

3. Нет проблем. Ваш ответ был отличным, и теперь его использует простой поиск по таблице with open('test51.pyc') as f: magic=f.read(2); magic.encode('hex') .

4. @Jefromi О, да, какой смысл, в таком случае @Popov , решение Fails . Поскольку он никогда не будет сопоставлен с python version hex code hex code of first two bytes .pyc файлом of . И я никогда не узнаю, какой была версия. И в конце концов я должен перейти к @aix решению для поиска версии Python. Я прав?:)

5. обновленный список магических чисел @ raw.githubusercontent.com/google/pytype/master/pytype/pyc /…

Ответ №2:

Вы можете получить магическое число вашего Python следующим образом:

 $ python -V
Python 2.6.2
# python
>>> import imp
>>> imp.get_magic().encode('hex')
'd1f20d0a'
  

Чтобы получить магическое число для файла pyc, вы можете сделать следующее:

 >>> f = open('test25.pyc')
>>> magic = f.read(4)
>>> magic.encode('hex')
'b3f20d0a'
>>> f = open('test26.pyc')
>>> magic = f.read(4)
>>> magic.encode('hex')
'd1f20d0a'
  

Сравнивая магические числа, вы узнаете версию python, которая сгенерировала файл pyc.

Комментарии:

1. чтобы сравнить волшебное слово, записанное как целое число в исходном коде Python , с imp.get_magic() байтами (Python 3): int.from_bytes(imp.get_magic()[:2], 'little') (игнорировать b'rn' ), например, imp.get_magic() == b'3rrn' соответствует 3379 (Python 3.6).

Ответ №3:

Или, если у вас система GNU / Linux, вы можете использовать команду «file» в терминале:

 $ file code.pyc
> code.pyc: python 3.5.2 byte-compiled
  

Комментарии:

1. Это намного проще

2. Спасибо. Но я попал test2.cpython-38.pyc: data под Windows WSL Ubuntu с python 3.8.5, я не знаю почему.

3. @Rick это зависит от выпуска самой программы «file», моя команда file взята из общих команд BSD, а моя версия — 5.39. Исходный код можно найти здесь: github.com/freebsd/freebsd/tree/master/contrib/file и файл, в котором записаны правила для файлов .pyc, находится здесь: github.com/freebsd/freebsd/blob/master/contrib/file/magic /…

Ответ №4:

Взгляните на мой скрипт на Python, который обнаруживает и возвращает версию Python, с помощью которой был скомпилирован файл (* .pyc или * .pyo).

Он обнаруживает версии Python от Python 1.5 до последней сборки Python 3.

Комментарии:

1. Я не смог найти свое магическое число в использовании других ответов, спасибо за сценарий!

Ответ №5:

Официальный репозиторий Python github больше не сохраняет список в import.c.

При поиске более актуального списка, чем я мог найти в другом месте, я столкнулся с тем, что выглядит как актуальный список от Google по состоянию на май 2017 года.

https://github.com/google/pytype/blob/master/pytype/pyc/magic.py

Комментарии:

1. исходные данные взяты из репозитория CPython

Ответ №6:

Добавление к ответу @Igor Popov.

Чтобы проверить версию скомпилированного скрипта из более новой версии Python:

 # written in python3

filename = "outfit.cpython-39.pyc"

with open(filename,'rb') as f:
    magic = f.read(4)

print(int.from_bytes(magic[:2], 'little'))
  

Вы можете найти номер вывода здесь:
https://github.com/google/pytype/blob/master/pytype/pyc/magic.py