Вам интересно, в чем разница между файлами Python.py и.pyc? Вы попали по адресу.
Файлы с расширением .py содержат код Python, который может быть прочитан человеком. С другой стороны, файлы .pyc содержат байт-код, который не может быть прочитан человеком. Файлы с расширением .py компилируются в файлы .pyc, которые затем обрабатываются интерпретатором Python.
Не волнуйтесь, если это покажется вам непонятным, мы рассмотрим несколько примеров, которые все прояснят.
И я также покажу вам, когда происходит компиляция файлов .py в файлы .pyc.
Давайте приступим!
Что такое файлы .py и .pyc в Python?
Файлы с расширением .py — это исходные файлы Python, в которых вы пишете свой код Python.
Код Python, который вы пишете в файлах .py, не выполняется в том же формате на машине, на которой вы запускаете свой код.
Перед выполнением код в файлах .py компилируется в файлы .pyc.
Представьте себе процесс компиляции как перевод с одного языка на другой язык.
Файлы с расширением .pyc являются результатом компиляции файлов с расширением .py. Файл .pyc для данного модуля Python автоматически создается при импорте этого модуля.
Примечание: как разработчик Python вы будете вносить изменения только в файлы .py.
Чтобы увидеть разницу между двумя типами файлов, давайте сначала создадим модуль Python в файле с именем app.py.
Для всех примеров в этом руководстве я создаю app.py внутри каталога /var/tmp/.
Файл app.py содержит код для модуля app, и в этом примере он содержит одну функцию:
def get_full_name(first_name, last_name):
return "{} {}".format(first_name, last_name)
Чтобы показать вам формат файла.pyc, мы сначала будем использовать Python 2.
В следующем разделе вы поймете почему…
Откройте оболочку Python и импортируйте модуль приложения:
$ python2
Python 2.7.16 (default, Dec 21 2020, 23:00:36)
[GCC Apple LLVM 12.0.0 (clang-1200.0.30.4) [+internal-os, ptrauth-isa=sign+stri on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import app
>>>
Теперь выйдите из оболочки Python.
Обратите внимание, что файл app.pyc был создан:
$ ls -al app*
-rw-r--r-- 1 codefather wheel 91 Mar 20 00:11 app.py
-rw-r--r-- 1 codefather wheel 261 Mar 20 00:12 app.pyc
Давайте посмотрим на содержимое файла.pyc…
$ cat app.pyc
?
d?ZdS(cCsdj||?S(Ns{} {}(tformat(t
get_full_namesN(R(((sapp.py<module>t%
Файл .pyc не полностью читаем, поскольку это скомпилированная версия исходного файла .py. Файл app.pyc содержит байт-код.
Что такое байт-код?!?
Подумайте о байт-коде как о низкоуровневом представлении кода Python в вашем файле .py. Низкий уровень означает, что он ближе к языку, который может понять компьютер, по сравнению с исходным кодом Python.
Как создается скомпилированный файл в Python?
Мы видели, что при импорте модуля Python создается скомпилированный файл (.pyc).
Но что создает скомпилированные файлы Python?
Ответ: это зависит от используемой вами реализации Python.
Эталонная реализация Python называется CPython и написана на C и Python. В этой реализации код Python компилируется в байт-код компилятором перед интерпретацией.
Как можно убедиться, что вы используете CPython?
Для проверки реализации Python, которую вы используете на своей машине, вы можете использовать модуль платформы Python. А конкретно функцию python_implementation()
.
Давайте посмотрим, какую реализацию Python 2 я использую на этой машине.
Python 2.7.16 (default, Dec 21 2020, 23:00:36)
[GCC Apple LLVM 12.0.0 (clang-1200.0.30.4) [+internal-os, ptrauth-isa=sign+stri on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import platform
>>> platform.python_implementation()
'CPython'
Реализацией Python на этой машине является CPython, который, как я уже объяснял ранее, является эталонной реализацией Python.
Давайте посмотрим, что получится в результате для Python 3.
Python 3.8.2 (default, Dec 21 2020, 15:06:03)
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import platform
>>> platform.python_implementation()
'CPython'
Та же реализация: CPython.
Где создаются скомпилированные файлы при использовании Python 3?
В предыдущем разделе мы использовали Python 2. Мы видели, что при импорте модуля в том же каталоге, что и файл .py, был создан файл .pyc.
Примечание: Учитывая, что Python 2 очень старый, вам на самом деле следует использовать Python 3. В этом уроке я также использую Python 2, чтобы показать вам разницу в поведении между двумя версиями Python.
Давайте попробуем провести тот же тест с Python 3.
Удалите созданный ранее файл.pyc и откройте оболочку Python с помощью Python 3.
Затем импортируйте модуль приложения …
$ rm app.pyc
$ python3
Python 3.8.2 (default, Dec 21 2020, 15:06:03)
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import app
>>>
Теперь выйдите из оболочки Python и проверьте, существует ли новый файл .pyc.
>>> exit()
$ ls -al app*
-rw-r--r-- 1 codefather wheel 91 Mar 20 00:11 app.py
Это странно…
По какой-то причине скомпилированный файл с расширением.pyc не существует.
Почему?!?
Это потому что…
В Python 3 скомпилированная версия кода для данного модуля создается в другом месте по сравнению с тем, что происходит в Python 2.
Давайте снова откроем оболочку Python 3…
…Я хочу вам кое-что показать.
Python 3.8.2 (default, Dec 21 2020, 15:06:03)
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import app
>>> dir(app)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'get_full_name']
После импорта модуля приложения мы можем использовать встроенную функцию dir()
, чтобы получить список атрибутов модуля, к которым мы можем получить доступ.
Хочу обратить ваше внимание на один атрибут: __cached__
.
Давайте проверим его ценность…
>>> app.__cached__
'/Users/codefather/Library/Caches/com.apple.python/private/var/tmp/app.cpython-38.pyc'
Примечание: как уже упоминалось ранее, во всех примерах этого руководства я создал app.py внутри каталога /var/tmp/.
Атрибут __cached__
для модуля Python — это путь к скомпилированной версии этого модуля. Добавление этого атрибута было частью предложения PEP 3147.
Примечание: PEP означает предложения по улучшению Python.
Вы можете видеть, что формат имени файла.pyc изменился по сравнению с Python 2. При использовании Python 3 имя файла также содержит реализацию Python (cpython) и версию Python (38).
Путь к файлу зависит от вашей операционной системы.
Давайте проверим, что файл app.cpython-38.pyc действительно находится в этом каталоге.
$ ls -al /Users/codefather/Library/Caches/com.apple.python/private/var/tmp/app.cpython-38.pyc
-rw-r--r-- 1 codefather staff 257 Mar 20 00:19 /Users/codefather/Library/Caches/com.apple.python/private/var/tmp/app.cpython-38.pyc
Мы подтвердили, что скомпилированный файл находится в этом каталоге.
Было бы сложнее найти этот путь без извлечения значения атрибута __cached__
!
Когда обновляются файлы.pyc?
Давайте продолжим работу над примером из предыдущего раздела.
Мы хотим понять, когда обновляются файлы .pyc.
Снова откройте оболочку Python 3, импортируйте модуль приложения и проверьте, изменилось ли что-нибудь в файле .pyc:
$ python3
Python 3.8.2 (default, Dec 21 2020, 15:06:03)
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import app
>>> exit()
$ ls -al /Users/codefather/Library/Caches/com.apple.python/private/var/tmp/app.cpython-38.pyc
-rw-r--r-- 1 codefather staff 257 Mar 20 00:19 /Users/codefather/Library/Caches/com.apple.python/private/var/tmp/app.cpython-38.pyc
Как видно из вывода команды ls
, размер файла и дата последнего изменения app.cpython-38.pyc не изменились.
Теперь измените функцию Python, определенную в app.py, и измените имя функции с get_full_name() на get_user_full_name:
def get_user_full_name(first_name, last_name):
return "{} {}".format(first_name, last_name)
Откройте оболочку Python 3, импортируйте модуль приложения и выйдите из оболочки.
>>> import app
>>> exit()
Проверьте, изменилось ли что-нибудь в скомпилированном файле app.cpython-38.pyc:
$ ls -al /Users/codefather/Library/Caches/com.apple.python/private/var/tmp/app.cpython-38.pyc
-rw-r--r-- 1 codefather staff 262 Mar 20 00:31 /Users/codefather/Library/Caches/com.apple.python/private/var/tmp/app.cpython-38.pyc
Изменились размер файла и дата последнего изменения.
Это произошло потому, что интерпретатор Python обнаружил изменение в модуле app.py и перекомпилировал код в новый файл .pyc.
Python воссоздает файл .pyc для данного модуля, когда этот модуль изменяется и повторно импортируется.
Можно ли удалить файлы.pyc?
Вы можете удалить файлы .pyc. Если вы это сделаете, а затем снова импортируете этот модуль, то файл .pyc, связанный с этим модулем, будет создан заново.
Здесь вы можете увидеть созданный ранее.pyc.
$ ls -al /Users/codefather/Library/Caches/com.apple.python/private/var/tmp/app.cpython-38.pyc
-rw-r--r-- 1 codefather staff 262 Mar 20 00:31 /Users/codefather/Library/Caches/com.apple.python/private/var/tmp/app.cpython-38.pyc
Давайте удалим его и снова импортируем модуль приложения…
$ rm /Users/codefather/Library/Caches/com.apple.python/private/var/tmp/app.cpython-38.pyc
$ python3
Python 3.8.2 (default, Dec 21 2020, 15:06:03)
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import app
>>> exit()
$ ls -al /Users/codefather/Library/Caches/com.apple.python/private/var/tmp/app.cpython-38.pyc
-rw-r--r-- 1 codefather staff 262 Mar 20 00:35 /Users/codefather/Library/Caches/com.apple.python/private/var/tmp/app.cpython-38.pyc
Python пересоздал файл .pyc. Он перекомпилировал файл .py в этот файл .pyc.
Можно ли удалить файлы.py с помощью Python 2?
Это интересно…
Давайте попробуем удалить файл app.py, содержащий наш код Python.
Как вы думаете, что произойдет, если мы попытаемся импортировать модуль приложения?
Начнем с Python 2 и перед удалением файла .py убедитесь, что файл .pyc существует в том же каталоге, что и файл .py.
Если файл .pyc не существует, откройте оболочку Python 2 и импортируйте модуль приложения, чтобы заново создать файл .pyc.
$ python2
Python 2.7.16 (default, Dec 21 2020, 23:00:36)
[GCC Apple LLVM 12.0.0 (clang-1200.0.30.4) [+internal-os, ptrauth-isa=sign+stri on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import app
>>> exit()
Теперь удалите app.py и снова откройте оболочку Python 2, чтобы импортировать модуль app.
$ rm app.py
$ python2
Python 2.7.16 (default, Dec 21 2020, 23:00:36)
[GCC Apple LLVM 12.0.0 (clang-1200.0.30.4) [+internal-os, ptrauth-isa=sign+stri on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import app
>>> dir(app)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'get_user_full_name']
>>> app.get_user_full_name('John', 'Smith')
'John Smith'
Интересно, что после удаления файла .py интерпретатор Python 2 не выдает никаких ошибок при импорте этого модуля, если файл .pyc для этого модуля существует.
Можно ли удалить файлы.py с помощью Python 3?
Давайте продолжим с того места, на котором остановились в предыдущем разделе, где мы рассмотрели, как ведет себя Python 2 при удалении файла.py.
А теперь давайте воспользуемся Python 3.
Файл app.py еще не существует в текущем каталоге /var/tmp, поэтому мы можем просто открыть оболочку Python 3 и попытаться импортировать модуль app.
$ python3
Python 3.8.2 (default, Dec 21 2020, 15:06:03)
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import app
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: bad magic number in 'app': b'\x03\xf3\r\n'
Мы получаем странную ошибку: неверное магическое число в «app».
Что это значит?
Одним из сценариев, в котором возникает ошибка неверного магического числа, является ситуация, когда Python 3 пытается загрузить файл .pyc, скомпилированный с помощью Python 2.
По-видимому, это происходит потому, что Python 3 находит файл .pyc в текущем каталоге и пытается загрузить его.
Давайте удалим файл .pyc из текущего каталога, а затем попробуем снова импортировать модуль приложения.
$ pwd
/var/tmp
$ rm app.pyc
$ python3
Python 3.8.2 (default, Dec 21 2020, 15:06:03)
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import app
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'app'
Мы получаем ошибку ModuleNotFoundError, несмотря на то, что файл .pyc все еще существует в каталоге, в котором он был создан при импорте модуля приложения с помощью Python 3 (см. вывод ls
ниже).
$ ls -al /Users/codefather/Library/Caches/com.apple.python/private/var/tmp/app.cpython-38.pyc
-rw-r--r-- 1 codefather staff 262 Mar 20 00:35 /Users/codefather/Library/Caches/com.apple.python/private/var/tmp/app.cpython-38.pyc
Заключение
Теперь вы знаете, в чем разница между файлами.py и.pyc в Python.
Вы также знаете, какую роль играют файлы .pyc в выполнении ваших программ Python: они генерируются путем компиляции файлов .py, а затем интерпретируются.
Мы также увидели, как компиляция файла .pyc различается между Python 2 и Python 3.