[python] -m 옵션을 사용하여 Python 코드 실행 여부

파이썬 인터프리터에는 “라이브러리 모듈 모듈 을 스크립트로 실행”하는 -m 모듈 옵션이 있습니다.

이 파이썬 코드 a.py로 :

if __name__ == "__main__":
    print __package__
    print __name__

나는 python -m a얻기 위해 시험 했다

"" <-- Empty String
__main__

반면 python a.py반환

None <-- None
__main__

나에게이 두 호출은 -m 옵션으로 호출 될 때 __package__가 None이 아니라는 점을 제외하면 동일하게 보입니다.

흥미롭게도 를 사용하면 a.pyc를 얻기 위해 컴파일 된 python 모듈과 python -m runpy a동일 python -m a합니다.

이러한 호출의 (실질적인) 차이점은 무엇입니까? 그들 사이에 장단점이 있습니까?

또한 David Beazley의 Python Essential Reference에서는 ” -m 옵션은 기본 스크립트 실행 전에 __main__ 모듈 내부에서 실행되는 스크립트로 라이브러리 모듈을 실행합니다 “라고 설명합니다 . 무슨 뜻인가요?



답변

-m명령 줄 플래그 를 사용하면 Python이 모듈 이나 패키지 를 가져온 다음 스크립트로 실행합니다. -m플래그를 사용하지 않으면 이름을 지정한 파일이 스크립트 로 실행됩니다 .

패키지를 실행하려고 할 때 구별이 중요합니다. 다음 사이에는 큰 차이가 있습니다.

python foo/bar/baz.py

python -m foo.bar.baz

후자의 경우와 같이 foo.bar를 가져 오면 상대 가져 오기가 foo.bar시작점으로 올바르게 작동합니다 .

데모:

$ mkdir -p test/foo/bar
$ touch test/foo/__init__.py
$ touch test/foo/bar/__init__.py
$ cat << EOF > test/foo/bar/baz.py
> if __name__ == "__main__":
>     print __package__
>     print __name__
>
> EOF
$ PYTHONPATH=test python test/foo/bar/baz.py
None
__main__
$ PYTHONPATH=test python -m foo.bar.baz
foo.bar
__main__

결과적으로 파이썬은 -m스위치를 사용할 때 실제로 패키지에 신경을 써야 합니다. 일반 스크립트는 패키지가 수 없으므로 __package__로 설정됩니다 None.

그러나 패키지 또는 모듈 실행 내부 와 패키지를 -m지금 적어도이 가능성 소위, 패키지의 __package__변수가 문자열 값으로 설정됩니다; 위의 데모 foo.bar에서 패키지 안에없는 일반 모듈의 경우으로 설정되어 있으면 빈 문자열로 설정됩니다.

__main__ 모듈에 관해서는 ; Python은 일반 모듈처럼 실행되는 스크립트를 가져옵니다. 에 저장된 전역 네임 스페이스를 보유하기 위해 새 모듈 객체가 생성됩니다 sys.modules['__main__']. 이것이 __name__변수가 가리키는 것이고 그 구조의 핵심입니다.

패키지의 경우 __main__.py모듈을 생성하고 실행할 때 실행할 수 있습니다 python -m package_name. 사실 이것이 패키지를 스크립트로 실행할 있는 유일한 방법입니다 .

$ PYTHONPATH=test python -m foo.bar
python: No module named foo.bar.__main__; 'foo.bar' is a package and cannot be directly executed
$ cp test/foo/bar/baz.py test/foo/bar/__main__.py
$ PYTHONPATH=test python -m foo.bar
foo.bar
__main__

따라서를 사용하여 실행할 패키지의 이름을 지정할 때 -mPython은 __main__해당 패키지에 포함 된 모듈을 찾아 스크립트로 실행합니다. 이름은 여전히로 설정되고 __main__모듈 객체는 여전히에 저장됩니다 sys.modules['__main__'].


답변

-m 옵션을 사용하여 Python 코드 실행 여부

-m플래그를 사용하십시오 .

스크립트가있는 경우 결과는 거의 동일하지만 -m플래그 없이 패키지를 개발할 때 패키지 의 하위 패키지 또는 모듈을 기본 항목으로 실행하려는 경우 가져 오기가 올바르게 작동하도록 할 방법이 없습니다. 당신의 프로그램을 가리킨다 (그리고 나를 믿어 라, 나는 시도했다.)

문서

-m 플래그문서 처럼 다음과 같이 말합니다.

sys.path에서 명명 된 모듈을 검색하고 해당 내용을 __main__모듈 로 실행 합니다.

-c 옵션과 마찬가지로 현재 디렉토리가 sys.path의 시작 부분에 추가됩니다.

그래서

python -m pdb

대략 다음과 같습니다.

python /usr/lib/python3.5/pdb.py

(현재 디렉토리에 pdb.py라는 패키지 나 스크립트가 없다고 가정)

설명:

동작은 스크립트와 “고의적으로 유사”하게됩니다.

많은 표준 라이브러리 모듈에는 스크립트로 실행시 호출되는 코드가 포함되어 있습니다. 예는 timeit 모듈입니다.

일부 파이썬 코드는 모듈실행되도록 의도되었습니다 : (이 예제가 명령 줄 옵션 문서 예제보다 낫다고 생각합니다)

$ python -m timeit '"-".join(str(n) for n in range(100))'
10000 loops, best of 3: 40.3 usec per loop
$ python -m timeit '"-".join([str(n) for n in range(100)])'
10000 loops, best of 3: 33.4 usec per loop
$ python -m timeit '"-".join(map(str, range(100)))'
10000 loops, best of 3: 25.2 usec per loop

그리고 Python 2.4의 릴리스 노트 하이라이트에서 :

-m 명령 줄 옵션-python -m modulename은 표준 라이브러리에서 모듈을 찾아 호출합니다. 예를 들어 다음과 python -m pdb
같습니다.python /usr/lib/python2.4/pdb.py

후속 질문

또한 David Beazley의 Python Essential Reference에서는 “-m 옵션은 라이브러리 모듈을 __main__기본 스크립트 실행 전에 모듈 내부에서 실행되는 스크립트로 실행합니다 “라고 설명합니다.

이는 import 문으로 조회 할 수있는 모든 모듈이 프로그램의 진입 점으로 실행될 수 있음을 의미합니다. 일반적으로 끝에 코드 블록이있는 경우 if __name__ == '__main__':.

-m 현재 디렉토리를 경로에 추가하지 않고 :

여기에 다른 의견은 다음과 같습니다.

-m 옵션이 현재 디렉토리를 sys.path에 추가한다는 것은 분명히 보안 문제입니다 (참조 : 사전로드 공격). 이 동작은 Windows의 라이브러리 검색 순서와 유사합니다 (최근에 강화되기 전). Python이 추세를 따르지 않고 .NET 추가를 비활성화하는 간단한 방법을 제공하지 않는 것은 유감입니다. sys.path에

음, 이것은 가능한 문제를 보여줍니다-(창에서 따옴표를 제거하십시오) :

echo "import sys; print(sys.version)" > pdb.py

python -m pdb
3.5.2 |Anaconda 4.1.1 (64-bit)| (default, Jul  5 2016, 11:41:13) [MSC v.1900 64 bit (AMD64)]

-I플래그를 사용하여 프로덕션 환경에 대해이를 잠급니다 (버전 3.4의 새로운 기능).

python -Im pdb
usage: pdb.py [-c command] ... pyfile [arg] ...
etc...

에서 워드 프로세서 :

-I

격리 모드에서 Python을 실행합니다. 이것은 또한 -E 및 -s를 의미합니다. 격리 모드에서 sys.path에는 스크립트의 디렉토리 나 사용자의 사이트 패키지 디렉토리가 없습니다. 모든 PYTHON * 환경 변수도 무시됩니다. 사용자가 악성 코드를 삽입하는 것을 방지하기 위해 추가 제한이 적용될 수 있습니다.

무엇을 __package__합니까?

이 질문과 특별히 연관되지는 않지만 명시적인 상대적 가져 오기를 가능하게합니다. 여기 답변을 참조하십시오. Python에서 “__package__”속성의 목적은 무엇입니까?


답변

-m을 사용하여 모듈 (또는 패키지)을 스크립트로 실행하는 주된 이유는 특히 Windows에서 배포를 단순화하기위한 것입니다. PATH 또는 ~ / .local과 같은 전역 실행 디렉터리를 오염시키는 대신 모듈이 일반적으로 이동하는 Python 라이브러리의 동일한 위치에 스크립트를 설치할 수 있습니다 (사용자 별 스크립트 디렉터리는 Windows에서 찾기가 엄청나게 어렵습니다).

그런 다음 -m을 입력하면 Python이 자동으로 스크립트를 찾습니다. 예를 들어는 python -m pip이를 실행하는 동일한 Python 인터프리터 인스턴스에 대해 올바른 pip를 찾습니다. -m이 없으면 사용자가 여러 Python 버전을 설치 한 경우 “글로벌”pip는 무엇입니까?

사용자가 명령 줄 스크립트에 대해 “클래식”진입 점을 선호하는 경우 PATH의 어딘가에 작은 스크립트로 쉽게 추가 할 수 있습니다. 또는 pip는 setup.py의 entry_points 매개 변수를 사용하여 설치할 때이를 만들 수 있습니다.

따라서 __name__ == '__main__'다른 신뢰할 수없는 구현 세부 정보를 확인 하고 무시하십시오.


답변