달나라 노트

Python sys : path, path.insert (환경 변수, Python 환경 변수 경로, PYTHONPATH, 환경 변수 추가, library import) 본문

Python/Python sys

Python sys : path, path.insert (환경 변수, Python 환경 변수 경로, PYTHONPATH, 환경 변수 추가, library import)

CosmosProject 2023. 2. 16. 20:31
728x90
반응형

 

 

Python library중 하나인 sys의 path는 환경 변수(PYTHONPATH)의 list를 출력해줍니다.

 

import sys

print(sys.path)


-- Result
[
    '/Users/Documents/Code',
    '/Users/Documents/Code/temporary',
    '/Users/.conda/envs/customs',
    '/Users/.conda/envs/customs/lib/python3.8',
    '/Users/.conda/envs/customs/lib/python3.8/lib-dynload',
    '/Users/.conda/envs/customs/lib/python3.8/site-packages'
]

 

sys.path를 이용해서 그 내용을 출력해보면 위같이 여러 경로가 list에 담긴 형태의 데이터가 출력됩니다.

 

이 경로들은 PYTHONPATH 환경 변수에 저장된 경로들을 의미합니다.

 

 

 

이를 위해하기 위해서는 먼저 PYTHONPATH가 뭐고 어떤 의미를 가지는지를 알아야합니다.

 

my_files/
├── main/
│   ├── calculator.py
│   └── show_result.py
└── libs/
    ├── functions/
    │   ├── sum.py
    │   ├── subtraction.py
    │   ├── multiplication.py
    │   └── division.py
    └── old_files/
        ├── temp_1.py
        └── temp_2.py

예를 들어서 위같은 directory 구조를 구성했다고 가정해봅시다.

현재 저는 calculator.py 파일에 코드를 작성하고 있습니다.

그리고 functions 폴더에 있는 plus.py, subtraction.py, multiplication.py, division.py 파일에 있는 함수들을 calculator.py 파일에서 import할 예정입니다.

 

그러면 대략적으로 느낌상 calculator.py 파일에는 대략적으로 아래처럼 코드가 적힐겁니다.

 

import show_result
from lib.functions import plus
from lib.functions import subtraction
from lib.functions import multiplication
from lib.functions import division


...

plus.py, subtraction.py, multiplication.py, division.py 파일들은 모두 lib/functions/라는 폴더 내부에 있으므로 functions 폴더 안에 있는 각 파일들을 import한다는 내용입니다.

 

show_result의 import까지는 제대로 진행될겁니다.

근데 상황에 따라 위 코드는 functions module이나 plus, subtraction, multiplication, division module들을 찾지 못했다는 에러를 발생시킬 수 있습니다.

분명히 fucnction 폴더 안에 python 파일들이 있는데도 말이죠.

 

import show_result 까지는 잘 진행되는데 왜 그 이후의 functions ~~ 는 import에서 에러가 발생할 가능성이 있을까요? (물론 개발 환경에 따라 그 결과는 다를 수 있습니다.

그 이유를 정확히 알려면 먼저 python이 library를 import할때 무슨 행동을 하는지를 알아야합니다.

 

Python은 코드를 실행하고, 그 코드 안에 import 구문이 있다면 어떠한 경로들을 찾아보게 됩니다.

그래서 이러한 경로들 안에서 import 구문에 적힌 library들이 있는지 찾아보고 있다면 그 내용을 가져와서 코드를 실행하게 되죠.

Python이 library 정보를 가져오기 위해 탐색하는 경로는 무엇일까요? 그것은 바로 PYTHONPATH라는 환경변수에 저장된 경로들을 의미합니다.

기본적으로 Python을 설치하면 PYTHONPATH라는 환경변수가 본인의 컴퓨터 시스템에 등록되고 그것은 아까 봤던 sys.path로 출력되는 경로들을 의미합니다.

 

[
    '/Users/Documents/Code',
    '/Users/Documents/Code/temporary',
    '/Users/.conda/envs/customs',
    '/Users/.conda/envs/customs/lib/python3.8',
    '/Users/.conda/envs/customs/lib/python3.8/lib-dynload',
    '/Users/.conda/envs/customs/lib/python3.8/site-packages'
]

개발 환경에 따라 약간씩은 다를 수 있습니다만, 대략적으로 보통 위같은 경로가 PYTHONPATH 환경변수에 등록된 기본 경로들입니다.

 

따라서 어떤 library가 import되는 과정은 위 PYTHONPATH에 해당 library들이 설치되어있고, Python은 위 경로를 하나씩 모두 찾아보면서 library를 import하는 것이죠.

여기에 추가로 실행하는 python파일과 동일한 위치(= 동일한 폴더 속)에 있는 python 파일도 기본적으로 찾아보고 import를 진행합니다.

 

예를 들어 pandas를 import한다고 했을 때 저는 pandas가 /Users/.conda/envs/customs/lib/python3.8/site-packages 경로에 설치되어 있습니다. 또한 이 경로는 위 PYTHONPATH 중 하나이므로 pandas library는 정상적으로 import될 수 있는 것이죠.

 

정리해보면 python 파일이 실행되면 python은 여러 library를 import하기 위해 크게 아래 두 종류의 directory들을 탐색합니다.

1. 현재 실행되고 있는 python 파일과 동일한 directory

2. 환경 변수 PYTHONPATH에 저장된 모든 directory

 

 

 

 

 

my_files/
├── main/
│   ├── calculator.py
│   └── show_result.py
└── libs/
    ├── functions/
    │   ├── sum.py
    │   ├── subtraction.py
    │   ├── multiplication.py
    │   └── division.py
    └── old_files/
        ├── temp_1.py
        └── temp_2.py

 

import show_result
from lib.functions import plus
from lib.functions import subtraction
from lib.functions import multiplication
from lib.functions import division


...

이를 토대로 다시 예시로 돌아오면 일단 제가 실행한 파일은 calculator.py입니다.

import show_result는 show_result.py 파일을 import하는 것인데 show_result.py 파일은 calculator.py 파일과 동일한 위치에 있으니 제대로 import됩니다.

 

저희 입장에서는 lib 폴더와 functions 폴더가 어디에 있는지 그리고 plus.py는 어디에 있는지 알고있지만 python 입장에서는 from lib.functions import plus 라고 적어준다고해도 functions 폴더는 어디에 있고, plus.py라는 파일이 어디에 있는지 모릅니다.

왜냐면 libs 폴더는 calcaultor.py 파일과 동일한 경로에 있는 것도 아니고, PYTHONPATH에 등록된 경로도 아니거든요.

 

 

그러면 영원히 libs 폴더 내에 있는 functions 폴더의 여러 python file들은 import할 수 없는걸까요?

물론 방법이 있습니다.

바로 PYTHONPATH를 조절하는 것입니다.

PYTHONPATH에 제가 원하는 경로를 추가해주면 python은 제가 추가한 경로까지도 module을 찾을 때 탐색하게 됩니다.

따라서 my_files/libs 이런 경로를 등록해주면 libs 안에 있는 파일들도 모두 python의 탐색 대상이 되겠죠.

 

먼저 sys.path.insert() method를 사용하는 방법을 알아봅시다.

 

import sys

sys.path.insert(0, '/Users/documents/libs')

import show_result
from lib.functions import plus
from lib.functions import subtraction
from lib.functions import multiplication
from lib.functions import division


...

위 코드처럼 import 전에 sys.path.insert() method를 통해 libs 디렉토리를 PYTHONPATH에 추가시켜주면 python은 lib 디렉토리를 찾아보면서 functions 폴더와 그 아래에 있는 파일들을 발견하여 import를 정상적으로 진행할 수 있게 됩니다.

 

insert() method는 어떤 경로를 PYTHONPATH에 일시적으로 추가해주는 기능을 합니다.

 

sys.path.insert(0, '/Users/documents/libs')

insert method의 첫 번째 인자를 보면 0이 적혀있습니다.

이것은 list형태로 존재하는 PYTHONPATH에 새로운 경로를 추가할 때 어느 위치에 추가할것인지를 알려주는 index입니다.

0이 적혀있으므로 index = 0 위치에 새로운 값을 삽입하라는 의미이며 이는 list의 가장 첫 번째를 의미합니다.

 

그리고 insert method의 두 번째 인자로는 libs 디렉토리의 절대 경로가 적혀있죠.

 

만약 위 코드로도 에러가 발생하면 아래처럼 functions directory도 추가해주면 됩니다.

 

import sys

sys.path.insert(0, '/Users/documents/libs')
sys.path.insert(0, '/Users/documents/libs/documents')

import show_result
from lib.functions import plus
from lib.functions import subtraction
from lib.functions import multiplication
from lib.functions import division


...

 

 

 

 

 

 

import sys

sys.path.insert(0, '/Users/documents/libs')
sys.path.insert(0, '/Users/documents/libs/documents')

print(sys.path)


-- Result
[
    '/Users/documents/libs/documents',
    '/Users/documents/libs',
    '/Users/Documents/Code',
    '/Users/Documents/Code/temporary',
    '/Users/.conda/envs/customs',
    '/Users/.conda/envs/customs/lib/python3.8',
    '/Users/.conda/envs/customs/lib/python3.8/lib-dynload',
    '/Users/.conda/envs/customs/lib/python3.8/site-packages'
]

insert method로 두 개의 경로를 추가한 후 path를 출력한 결과입니다.

가장 앞쪽에 추가한 2개의 libs, libs/documents 경로가 보이는 것을 확인할 수 있죠.

 

 

 

 

 

근데 위 방법에는 문제가 있습니다.

sys.path.insert() method는 단순히 이 파일이 실행되는 도중에만 PYTHONPATH에 조작을 가하는 겁니다.

즉, 이 파일의 실행이 끝나면 PYTHONPATH에 있는 경로들은 다시 원상복귀되어 libs~ 디렉토리에 관한 정보가 없게 될겁니다.

 

만약 영구적으로 PYTHONPATH를 조절하고 싶다면 시스템 환경 변수 자체를 건드려야 합니다.

Mac에서 환경 변수를 설정하는 방법은 아래 링크를 참조하면 됩니다.

Mac 환경 변수 설정 = https://cosmosproject.tistory.com/269

 

 

export PYTHONPATH="/Users/documents/libs/documents:/Users/documents/libs:/Users/Documents/Code:/Users/Documents/Code/temporary:/Users/.conda/envs/customs:/Users/.conda/envs/customs/lib/python3.8:/Users/.conda/envs/customs/lib/python3.8/lib-dynload:/Users/.conda/envs/customs/lib/python3.8/site-packages"

.bash_profile (또는 .zprofile)에 위처럼 PYTHONPATH라는 이름의 환경변수를 만들고 여기에 내가 원하는 경로를 모두 적어주면 됩니다.

경로끼리의 구분은 콜론(:)으로 해줘야한다는 점에 주의합시다.

 

이렇게 해두면 파일을 종료하고 다시 돌려도, 컴퓨터를 재부팅해도 PYTHONPATH 값이 시스템에 남아있으므로 포맷을 하지 않는 한 계속 유지되는 PYTHONPATH를 설정할 수 있습니다.

(참고로 환경 변수 설정 후에는 재부팅을 해야 제대로 적용될 수 있습니다.)

 

 

 

 

 

 

728x90
반응형
Comments