시스템 기본이 3.6 인데 스크립트는 3.7 이상에서만 동작한다. 또는 반대로 옛 스크립트가 새 버전에서 깨진다. 기본 인터프리터를 바꾸면 OS 도구가 함께 깨지므로, 기본은 그대로 두고 그 스크립트만 원하는 버전으로 실행하는 것이 정답이다.
RHEL 계열에서 /usr/bin/python3 를 다른 버전으로 갈아 끼우면 dnf · firewalld 같은 시스템 도구가 동작하지 않는다. 절대 하지 않는다.
가장 확실하다.
python3.7 /opt/app/job.py
/usr/bin/python3.9 /opt/app/job.py
스크립트 첫 줄에 인터프리터를 적어 두면 실행 권한만으로 돌릴 수 있다.
#!/usr/bin/env python3.9
#!/usr/bin/python3 는 그 시스템의 기본에 묶이고, #!/usr/bin/env python3 는 PATH 에서 먼저 발견되는 것을 쓴다. 버전을 고정하려면 env 뒤에 버전을 붙이거나 절대경로를 적는다.
cron 과 systemd 는 로그인 셸의 PATH 를 쓰지 않는다. env 방식은 이 환경에서 다른 인터프리터를 집을 수 있으므로, 배치에서는 절대경로를 쓰는 편이 안전하다.
0 2 * * * /opt/app/.venv/bin/python /opt/app/job.py >> /var/log/app/job.log 2>&1
애플리케이션마다 가상환경을 만들면 인터프리터와 의존성이 함께 묶인다. 운영에서 가장 권장되는 방식이다.
python3.9 -m venv /opt/app/.venv
/opt/app/.venv/bin/python -m pip install -r /opt/app/requirements.txt
/opt/app/.venv/bin/python /opt/app/job.py
.venv/bin/python 은 만들 때 쓴 인터프리터에 묶인 심볼릭 링크다. 원본 파이썬을 지우거나 경로를 옮기면 가상환경이 깨지므로, 시스템 파이썬을 업그레이드할 때는 가상환경을 다시 만든다.
여러 버전을 사용자 단위로 오가야 하면 pyenv 를 쓴다. 시스템 경로를 건드리지 않고 사용자 환경에서만 버전을 고른다.
alternatives --config python3 는 시스템 전체에 영향을 주므로 서버에서는 권하지 않는다.
잘못된 인터프리터로 돌아 알 수 없는 오류를 내는 것보다, 처음에 명확히 멈추는 편이 낫다.
import sys
if sys.version_info < (3, 9):
sys.exit(f"Python 3.9 이상이 필요합니다. 현재: {sys.version}")
SyntaxError: Non-ASCII character '\xec' in file alert.py on line 3,
but no encoding declared; see http://www.python.org/peps/pep-0263.html for details
이것은 Python 2 에서만 나는 오류다. Python 2 는 소스 파일의 기본 인코딩을 ASCII 로 보기 때문에, 한글 주석이나 문자열이 있으면 파일 첫 줄이나 둘째 줄에 인코딩을 선언해야 한다.
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
Python 3 은 소스 기본 인코딩이 UTF-8 이라 이 선언이 필요 없다. 이 오류가 났다는 것은 곧 Python 2 로 실행되고 있다는 신호이므로, 선언을 추가하기 전에 어느 인터프리터로 돌고 있는지부터 확인한다. 의도가 3 이었다면 python3 로 실행하면 그만이다.
Python 2 는 2020년에 지원이 끝났다. 남아 있는 스크립트는 이관 대상으로 기록해 둔다.