-
91 - (파이썬) 패키지study with Q - 파이썬 2024. 9. 22. 20:27
#패키지
: 모듈의 규모가 커졌을 때, 그 모듈을 나누는 방법
ㄱ) 모듈 : 관심사를 기반으로 함수와 변수를 나누는 것
→ 프로그래밍 언어에 따라서 관심사를 묶는 방법이 매우 다양. 그 중 파이썬은 파일들을 폴더를 활용해서 묶는다.
방법1) 폴더 내부의 있는 모듈을 읽어들이는 방법
[1] school이라는 이름의 폴더를 만든다
[2] 내부에 StudentList를 배치해 볼 studentlist.py라는 파일과 클래스를 배치할 student.py라는 파일을 만든다.
(일반적으로 클래스의 규모가 커지게 되면 클래스 각각을 파일로 만든다.)[3] student.py의 student 클래스 내부에는 수학 성적 입력 / 합계를 입력을 받는 코드를 작성한다.
<student.py>
class Student: def __init__(self, 수학): self.수학 = 수학 def sum(self): return self.수학
[4] studentlist.py에는 studentlist라는 클래스에 다음의 코드를 구성한다.
- init 내부에서 self.list를 초기화 한 뒤에 append 함수를 구현해주고, 학생이 전달되면 self.list에 학생이 append되도록 구성한다.
- 출력을 하면 for 반복문을 활용해서 list 내부에 있는 학생들을 반복을 돌리고 student 내부에 있는 sum을 호출해서 출력하도록 구성한다.
<studentlist.py>
class StudentList(list): def __init__(self): #외부로부터 캡슐화 해서 숨기기 self.__list = [] def append(self, 학생): self.__list.append(학생) #self.__리스트로 수정 def print(self): for student in self.__list: print(student.sum())
[5] main.py에서 읽어 들이기
- from import 구문 등을 사용해서 읽어들이고 StudentList에 append를 해서 Student 클래스에 인스턴스를 추가한다.
- print를 넣고 코드를 실행하면 모듈을 읽어서 작동하는 것을 볼 수 있다.
<main.py>
from school.student import Student #student.py 내부에는 Student 밖에 없어서 import Student 대신 import *을 써도 동일하게 작동한다 from school.studentlist import StudentList sl = StudentList() sl.append(Student(100)) sl.append(Student(75)) sl.append(Student(80)) sl.print() >>> 100 75 80
방법2) 폴더 자체를 모듈로 읽어들이는 방법
- 위의 예시에서 school.student또는 school.studentlist로 각각의 파일에 접근하는 것이 아니라 import school이라고 해서 폴더를 읽어 들이는 방법
🧐 import school일 때 무슨 내용을 읽어 들이는지 어떻게 알지?
→ 폴더를 import했을 때 읽어지는 파일은 폴더 내부에 있는 __init__ .py 파일이다!
<__init__ .py>
a = "내가 모듈이 될 상인가" def b(): print("school의 모듈임다.")
<main.py>
import school print(school.a) school.b() >>> 내가 모듈이 될 상인가 school의 모듈임다.
두 가지 방법을 결합 뾰로롱
- 내부에서 from student import Student라고 해서 student라는 이름의 식별자를 만들면 파일 내부에서 접근할 수 있지 않나?
→ 놉! student라는 모듈과 studentlist라는 모듈을 찾을 수 없다는 오류가 발생한다.
<__init__ .py>
from student import Student from studentlist import StudentList >>> Traceback (most recent call last): File "/home/runner/byeonsuwa-boghabdaeibyeonsanja/main.py", line 1, in <module> from student import Student ModuleNotFoundError: No module named 'student'
✔️ 패키지 내부에 있는(다른 폴더에 있는) 위치에서 해당 폴더에 있는 모듈을 읽어 들이기 위해서는 모듈이 상대적인 경로에 있다는 것을 나타내야 한다.
🧐 어떻게요...?
→ 모듈 이름앞에 점 하나 찍어주슈
<__init__ .py>
from .student import Student from .studentlist import StudentList
이렇게 모듈 이름 앞에 점을 찍게 되면 현재 __init__.py이 있는 위치 기준으로 모듈을 찾게 된다!
<main.py>
import school school.Student school.StudentList
→ 코드를 실행하면 정상적으로 읽어 들이는 것을 알 수 있다.
→ 요러한 형태로 패키지를 구성하게 되면 Student 파일과 StudentList 파일을 한 번에 읽을 수 있다.
✋ 앞에 school.을 계속 입력하는 것이 구찮습니다
→ 사실 나도 그래요.
→ import *을 활용해서 패키지 내부에 있는 모든 것을 읽으면 어떨까염...?
<main.py>
from school import * school.Student school.StudentList
→ 클래스 캡슐화에서 나온 것처럼 너무 많은 권한을 부여해서 위험한 상황이 발생할 수 있다!
그래서
<__init__ .py>에서 __all__ = []라는 변수를 만들어서 패키지에서 무엇을 읽을 것인지 선택적으로 지정할 수 있다.
<__init__ .py>
__all__ = ["Student", "StudentList"] #나는 Student와 StudentList만 읽겠어요 from .student import Student from .studentlist import StudentList a = "내가 모듈이 될 상인가" def b(): print("school의 모듈임다.")
<main.py>
from school import * print(Student) print(a) >>> <class 'school.student.Student'> Traceback (most recent call last): File "/home/runner/byeonsuwa-boghabdaeibyeonsanja/main.py", line 4, in <module> print(a) NameError: name 'a' is not defined
→ Student 클래스는 정상적으로 출력하지만 a는 없다고 나온다!
#__all__ = []로 서브 모듈 만들기
<__init__ .py>
__all__ = [ "student", "studentList" ]
<main.py>
from school import * student.Student studentlist.StudentList
<__init__ .py>에 student와 studentList라는 모듈 이름을 지정하게 되면 <main.py>에서 파일들을 서브 모듈로 읽어 들이게 되어서 student.Student, studentlist.StudentList 등으로 모듈 내부에 있는 클래서를 읽어 들일 수 있다.
이런 것을 기억해서 다른 사람들이 만들 패키지를 분석할 수 있어야 한다!
강사님의 말)
더보기(1) 이후에 패키지를 읽어 들일 때
"이걸 왜 이렇게 읽어들이는가?"를 대충 이해하실 수 있는 정도
예) 다음이 폴더 내부의 파일을 읽어들이는 것이라는걸 떠올릴 수 있으면 됩니다.
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
(2) 나중에 패키지 분석해보면서 __all__을 봤을 때,
"선택적 공개 또는 서브 모듈 공개를 하고 있겠구나"하고만
떠올릴 수 있으시면 됩니다.
예) 예를 들어 tensorflow 폴더 내부의 __init__.py 파일에
keras라는 식별자를 만드는 과정이 없는데
import tf
tf.keras
라는 코드를 사용하고 있는 코드가 나왔을 때
"아.... 잘 모르겠지만 __all__로 읽어들이고 있겠구나...?" 정도 떠올리실 수 있으면 됩니다.
PS. 실제로 보면 `__all__ = [s for s in dir() if s in _exported_dunders or not s.startswith('_')]`과 같은 코드로 현재 폴더의 내용을 패키지로 제공합니다('study with Q - 파이썬' 카테고리의 다른 글
90 - (파이썬) 모듈 만들기 (0) 2024.09.19 89 - (파이썬) 모듈 문제 (0) 2024.09.19 88 - (파이썬) 기본 내장 모듈 (1) 2024.09.13 87 - (파이썬) 모듈을 읽는 방법 (0) 2024.09.13 85 - (파이썬) 스택과 큐 (2) 2024.09.09