[python] import 관련 : 모듈, 패키지, __init__.py, __all__
모듈 단독 실행 시 import 경로 문제
```
├── common
│ ├── __init__.py
│ ├── copy.py
│ └── clean.py
├── T1036
│ ├── __init__.py
│ ├── bar.py
│ ├── foo.py
├── run.py
```
우선, 기본적인 import 동작 방식
python run.py 커맨드로 실행하는 경우, foo.py 파일 내에서 모듈 참조는 아래와 같다.
```python
from .bar import BarCls
# .으로 참조하는 경우 그 파일 자체의 위치(T1036) 기준 찾는다
from common.copy import CopyNoMetaCls
# 절대 경로로 명시하는 경우는 python 커맨드 대상이 되는 파일(run.py 디렉터리) 위치 기준 찾는다.
```
foo.py에서 다른 hierarch에 있는 common.copy에 접근하기
```python
import sys, os
sys.path.append(os.path.dirname(os.path.abspath(os.path.dirname(__file__))))
# sys.path.insert(0, os.path.abspath('..')) 이건 별로 좋은 방법이 아니다.
# python foo.py 하면 제대로 되는데, run.py에서 subprocess.run("python T1036/foo.py")하면
# run.py가 위치한 디렉토리에서 ".."이 적용되어 common을 못찾는다.
# 그래서 위와 같이 지정하는게 더 확실하다.
import common
common.copy.copyNoMeta()
```
common.__init__.py 설정
```python
from .copy import *
from .clean import *
### from common import * 했을 때도 import 되도록 동작하게 하려면 __all__을 정의.
# __all__ = ['copyNoMeta', 'copyWithMeta', 'remove']
### 위처럼 하는 것 보다, 아래 처럼 각각의 모듈에 __all__을 정의하고
### __init__.py에서 이를 한 번에 종합하는 식으로 구성하는 것이 좋다.
# __all__ = (copy.__all__ +
# clean.__all__)
```
외부에 공개하고 싶지 않은 내용이 있다면 `` __all__ = []``로 비워두어야 한다. 따로 설정하지 않으면 기본적으로 그 모듈에서 ``py import``한 다른 모듈이나, 함수등이 모두 노출되도록 되어 있어서 ``py dir()``로 조회해보면 다 나온다.
dynamic module & package import
동적으로 모듈 임포트하기.
```python
############ Dynamic module & package import ##############
from importlib import import_module
from pathlib import Path
p = {}
def dynamicImport():
path = Path('.')
attack_packages = [x for x in path.iterdir()
if x.is_dir()
and x.name not in ("__pycache__", "common", "T1097A_Pass_the_Ticket")]
for package in attack_packages:
module_py = list(package.glob("*.py"))
modules = list(map(lambda x: x.stem, filter(lambda x: x.name not in ("__init__.py", "test.py"), module_py)))
try:
name_as = package.name[:package.name.index("_")]
except:
name_as = package
p[name_as] = {}
for m in modules:
p[name_as][m] = import_module("." + m, package.name)
###########################################################
```
pkgutil을 사용해 패키지 내의 모듈 리스트 가져오기
```python
package = import_module(package.name)
for importer, modname, ispkg in pkgutil.iter_modules(package.__path__):
print("Found submodule %s (is a package: %s)" % (modname, ispkg))
```
그 외 정보를 조회하려면 inspect 모듈을 사용한다.
```python
from inspect import Signature
```
모듈을 싱글턴 처럼 쓸 수는 있지만 이렇게 쓰는건 별로다.
파이썬 모듈은 참조된 횟수에 상관없이 단 하나의 복사본만 불러온다.
따라서 모듈 자체를 하나의 싱글턴으로 사용할 수 있다.
그래서 모듈 하나에 전역 변수 선언해놓고, 다른데서 이 변수를 ``py import``해서 쓰더라도 값이 복사되는게 아니라 공유된다. 여기서도 써야하고 저기서도 써야하는 파라미터를 이리저리 넘기는게 지저분한 경우가 있는데, 그럴 때 사용할 수 있다.
근데 이 변수에 다시 값을 할당 하는 경우는 import를 어떻게 했느냐에 따라서 동작이 달라진다!!!!!!!
일반적으로 다음과 같은 순서로 import해야 보기좋다.
```py
import 표준 모듈
import 서드파티 모듈/패키지
import 로컬 어플리케이션 모듈/패키지
```
- 설치된 package list는 ``pip list`` 또는 ``pip freeze``로 확인할 수 있다.
'Languages & Frameworks > Python' 카테고리의 다른 글
[python] 파일 배포, python with C (0) | 2017.02.26 |
---|---|
[Regex] Python (0) | 2017.02.23 |
[python] 함수, 클래스, 객체, *args, **kwargs (0) | 2017.02.23 |
[python] List, Tuple, Dictionary, Set, Enumerate, sort 정렬 (0) | 2017.02.23 |
[python] 정수 실수 자료형 (0) | 2017.02.15 |