모듈 단독 실행 시 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``로 확인할 수 있다.