Python의 pathlib모듈을 사용하면, 파일, 디렉토리(폴더)의 경로를 객체로써 조작하거나 처리할 수 있다.
파일명 혹은 부모 디렉토리를 알아내거나, 경로의 목록을 얻어내거나, 파일을 작성하거나 삭제하는 등, 대략적인 파일관련된 처리가 가능하다. 익숙해지면 경로 문자열을 이용하는 기존의 os.path보다는 사용하기 편할 것이다.
pathlib는 Python 3.4부터 추가된 모듈이다. 표준 라이브러리에 포함되어있으므로 별도의 인스톨이 필요하지 않다(물론 , 사용 전에 import 구문 작성은 필요하다) .
여기서 pathlib모듈의 기본적인 사용법으로 아래의 내용에 대해서 살펴 볼 것이다.
- Path 오브젝트의 생성·처리
- 컨스트럭터 pathlb.Path()
- 메소드의 실행
- 존재하지 않는 경로에 대한 처리
- 경로의 이동 : / 연산자, joinpath(), parent
- 경로의 연결·추가
- 새로운 디렉토리로의 이동
- Path 오브젝트를 문자열(str)으로 변환
- os 모듈의 함수 인수에 Path 오브젝트를 지정
- os 모듈과 pathlib모듈 비교표
아래와 같이 파일·디렉토리 구성되어 있다는 가정하에 설명하도록 하겠다.
temp
├── dir
│ └── sub_dir
│ └── file2.txt
└── file.txt
Path 오브젝트의 생성·처리
컨스트럭터 pathlib.Path()
pathlib 모듈에서는 경로를 객체로써 조작한다.
컨스트럭터 pathlib.Path()로 Path 객체를 생성할 수 있다. 인수로 경로의 문자열을 지정한다. 상대경로든 절대경로든 상관없이 모두 가능하다.
import pathlib
import os
import pprint
p_file = pathlib.Path('temp/file.txt')
print(p_file)
# temp/file.txt
print(type(p_file))
# <class 'pathlib.PosixPath'>
예를 Mac에서 실행한다면, Mac을 포함한 Unix계 OS의 클래스인 PosixPath형의 인스턴스가 생성된다. 한편, Windows에서 실행한다면 WindowsPath형이 된다.
Unix의 머신으로 Windows의 경로를 다루고 싶은 경우나 반대로 Windows의 머신에서 Unix의 경로를 다루고 싶은 경우 등 어떠한 특별한 상황에서는 단순 경로의 클래스인 PureWindowsPath형이나 PurePosixPath형의 인스턴스를 생성할 필요가 있지만, 실제의 파일이나 디렉토리를 처리할 경우는 pathlib.Path()를 사용하면 문제없다.
디렉터리의 경우도 작성법은 위와 동일하다.
p_dir = pathlib.Path('temp/dir')
print(p_dir)
# temp/dir
print(type(p_dir))
# <class 'pathlib.PosixPath'>
메소드의 실행
오브젝트로 메소드를 호출하는 것으로 다양한 처리가 가능하게 된다. 예를 들어, 객체가 파일인지 아닌지를 판정하는 is_file() 메소드를 실행하는 예는 아래와 같다.
print(p_file.is_file())
# True
print(p_dir.is_file())
# False
참고로, 디렉토리인지 아닌지를 판별하는 메소드는 is_dir()이다.
존재하지 않는 경로에 대한 처리
존재하지 않는 경로 객체를 생성하는 것도 가능하다. 경로의 존재를 확인하는 메소드인 exists()를 적용하면, False가 반환된다.
p_new_file = pathlib.Path('temp/new_file.txt')
print(p_new_file.exists())
# False
존재하지 않는 경로의 객체로부터 새로운 파일이나 디렉토리를 생성하는 메소드를 실행할 수 있다. touch()는 빈 파일을 생성하는 메소드이다. 따라서 다시 exists()메소드를 적용하면 True가 반환되는 것을 확인할 수 있다.
p_new_file.touch()
print(p_new_file.exists())
# True
메소드를 연결시켜 하나의 행으로 작성하는 것도 물론 가능하다.
pathlib.Path('temp/new_file2.txt').touch()
디렉토리 값 아래의 경로 목록의 이터레이터로 취득해서 iterdir()를 사용하면 파일이 새로 생성되어 있다는 것을 확인할 수 있다.
pprint.pprint(list(pathlib.Path('temp').iterdir()))
# [PosixPath('temp/file.txt'),
# PosixPath('temp/new_file.txt'),
# PosixPath('temp/new_file2.txt'),
# PosixPath('temp/dir')]
경로의 이동 : / 연산자, joinpath(), parent
디렉토리 트리 내에서 이동할 수 있도록 어떤 Path 객체를 기준으로한 다른 디렉토리나 파일을 표시하는 Path 객체를 생성할 수 있다.
경로의 연결·추가
Path 객체에 대해서 / 연산자를 사용하면 경로가 연결된다.
p_sub_dir_file = p_dir / 'sub_dir' / 'file2.txt'
print(p_sub_dir_file)
# temp/dir/sub_dir/file2.txt
print(p_sub_dir_file.is_file())
# True
joinpath() 메소드에서도 돌일하다. 여러 개를 연결할 경우는 인수를 여러 개 지정한다. os.path.join()에 상응한다.
p_sub_dir_file = p_dir.joinpath('sub_dir', 'file2.txt')
print(p_sub_dir_file)
# temp/dir/sub_dir/file2.txt
print(p_sub_dir_file.is_file())
# True
새로운 디렉토리로의 이동
상대경로 ..를 연결하면 부모 디렉토리(상위 디렉토리)로의 이동할 수 있다.
p_sub_dir_file = p_dir.joinpath('sub_dir', 'file2.txt')
print(p_sub_dir_file)
# temp/dir/sub_dir/file2.txt
print(p_sub_dir_file.is_file())
# True
경로가 참고하는 파일이 같은지에 대한 판정은 samefile() 메소드로 할 수 있다. 확인해보면, .. 를 사용하지 않는 Path 객체와 동일 파일을 참고하고 있는가를 확인할 수 있다. 이 경우는 == 연산자로는 확인할 수 없음을 주의하자.
print(p_file)
# temp/file.txt
print(p_file.samefile(p_file_join))
# True
print(p_file == p_file_join)
# False
.. 를 포함한 상대 경로를 절대 경로로 변환하기 위해서는 resolve() 메소드를 사용할 수 있다. resolve()를 이용해 절대 경로로 변환하면 == 연산자로 일치여부를 확인할 수 있다.
print(p_file_join.resolve())
# /Users/mbp/Documents/my-project/python-snippets/notebook/temp/file.txt
print(p_file.resolve())
# /Users/mbp/Documents/my-project/python-snippets/notebook/temp/file.txt
print(p_file_join.resolve() == p_file.resolve())
# True
resolve() 메소드가 리턴하는 것은 Path 객체이다(문자열이 아니다).
print(type(p_file.resolve()))
# <class 'pathlib.PosixPath'>
반대로 절대경로를 상대경로로 변환하는 것은 relative_to()메소드를 사용한다. 인수로 지정한 경로를 기준으로 하는 상대경로를 반환한다.
Python이 실행되고 있는 작업 디렉토리(현재 디렉토리)는 cwd()로 확인할 수 있으므로, 절대경로를 현재 디렉토리로부터의 상대경로로 변환하기 위해서는 아래의 코드를 이용한다.
print(p_file_join.resolve().relative_to(pathlib.Path.cwd()))
# temp/file.txt
새로운 디렉토리에 이동하는 경우, parent 속성을 사용하는 방법이 있다. 이 방법은 이해하기 쉽다는 장점이 있다.
print(p_dir.parent)
# temp
print(p_dir.parent.joinpath('file.txt'))
# temp/file.txt
parent는 단순히 문자열 조작이다. 원래 객체가 ..를 포함하고 있는 경우, 특별히 이러한 것을 해석하지 않는다는 것을 주의하자.
print(p_file_join.parent)
# temp/dir/..
Path 오브젝트를 문자열(str)로 변환
위의 예와 같이, Path형의 객체를 print()로 출력하면 경로의 문자열이 표시되지만, 데이터형 자체는 어디까지나 Path(PosixPath 혹은 WindowsPath)로 즉 사실상 문자열 (str형)이 아니다.
p_file = pathlib.Path('temp/file.txt')
print(p_file)
# temp/file.txt
print(type(p_file))
# <class 'pathlib.PosixPath'>
문자열로 변환하고 싶은 경우는 str()를 사용한다.
s = str(p_file)
print(s)
# temp/file.txt
print(type(s))
# <class 'str'>
또한, Path의 속성 name으로 파일명을 문자열로 취득하거나, suffix속성으로 확장자를 문자열로 얻어내는 것이 가능하다.
os 모듈의 함수 인수에 Path 오브젝트를 지정
os.path의 각 함수는 인수로 경로의 문자열을 지정하지만, Python3.6이후는 많은 함수로 Path 오브젝트도 인수로 지정할 수 있게 되었다.
os.path.isfile()를 예는 다음과 같다. 경로 문자열에서도 Path 오브젝트이든 어느쪽이든 올바르게 동작한다.
print(os.path.isfile('temp/file.txt'))
# True
print(os.path.isfile(p_file))
# True
위에서 언급했듯 Path 오브젝트에서는 os.path.isfile()에 대응하는 is_file()메소드가 있다.
os 모듈과 pathlib모듈 비교표
마지막으로 os 모듈의 함수가 pathlib 모듈의 Path 오브젝트의 어떤 메소드에 대응하고 있는지를 표로 정리해보았다.
처리내용 | os 및 os.path | pathlib |
현재의 디렉토리를 취득 | os.getcwd() | Path.cwd() |
맨 앞의 ~를 홈 디렉토리에 치환 | os.path.expanduser() | Path.expanduser(), Path.home() |
경로의 존재 확인 | os.path.exists() | Path.exists() |
디렉토리인가를 판단 | os.path.isdir() | Path.is_dir() |
파일인가를 판단 | os.path.isfile() | Path.is_file() |
심볼릭 링크인가를 판단 | os.path.islink() | Path.is_symlink() |
절대경로인가를 판단 | os.path.isabs() | PurePath.is_absolute() |
절대경로로 변환 | os.path.abspath() | Path.resolve() |
status를 취득 | os.stat() | Path.stat(), Path.owner(), Path.group() |
경로를 연결 | os.path.join() | PurePath.joinpath() |
파일명을 취득 | os.path.basename() | PurePath.name |
새로운 디렉토리를 취득 | os.path.dirname() | PurePath.parent |
확장자를 분할·취득 | os.path.splitext() | PurePath.suffix |
참고자료
'IT > 언어' 카테고리의 다른 글
[python] python으로 JSON 파일 다루는 기초적인 방법 (0) | 2021.05.22 |
---|---|
[python] pandas로 요소, 행, 열에 함수를 적용하는 map, applymapp, apply (0) | 2021.05.17 |
[python] python의 self와 __init__의 이해 (6) | 2021.05.14 |
[python] Python 정규표현 모듈 re 사용법 (match, search, sub등) (0) | 2021.05.12 |
[python] os.path.join사용법 (0) | 2021.05.11 |