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


111

파이썬 인터프리터에는 "라이브러리 모듈 모듈 을 스크립트로 실행"하는 -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__ 모듈 내부에서 실행되는 스크립트로 라이브러리 모듈을 실행합니다 "라고 설명합니다 . 무슨 뜻인가요?

답변:


169

-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__'].


1
실제로 명령 PYTHONPATH=test python -m foo.bar은 무엇을 의미합니까? 자세히 설명해 주시겠습니까?
Andriy

3
@Andriy : PYTHONPATH환경 변수를 설정합니다. 가져올 때 파이썬이 모듈을 찾을 일련의 디렉토리를 확장합니다. 여기 test에서 해당 시리즈에 디렉토리를 추가합니다 . 동일한 명령 줄에 배치하면 해당 단일 명령 에만 적용 됩니다python . -m를 실행 한 것처럼 특정 모듈을 가져 오도록 Python에 지시합니다 import foo.bar. 그러나 Python은 __main__해당 스위치를 사용할 때 패키지 내의 모듈을 스크립트로 자동으로 실행합니다 .
Martijn Pieters

1
having to use -m always is not that user-.friendly.나는 사용과 사용하지 않는 혼합 -m이 덜 사용자 친화적 이라고 생각 합니다.
Simin Jie

1
@SiminJie : 스크립트는 임의의 경로 에서 열 수 있으며 상위 디렉토리가 모듈 검색 경로에 추가됩니다. -m현재 디렉토리 또는 검색 경로에 이미 등록 된 디렉토리에서만 작동합니다. 그게 내 요점이었다. -m사용성 문제에 대해 최종 사용자에게 제공하는 것이 아닙니다.
Martijn Pieters

1
@ flow2k : from Photos import ...불평 할 것입니다. 그래서 import Photos.<something>. import PhotosPython이 네임 스페이스 패키지를 지원하기 때문에 작동합니다 (두 개의 개별 배포가 별도로 제공 Photos.foo되며 Photos.bar독립적으로 관리 할 수 ​​있음).
Martijn Pieters

25

-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 스위치를 사용할 때 sys.path에 어떤 경로가 추가됩니까?
변수

이미 "-c 옵션과 마찬가지로 현재 디렉토리가 sys.path의 시작 부분에 추가됩니다."라고 인용했습니다. 그러나 인용문이 무엇을 의미하는지 명확히했습니다.
Aaron Hall

내 말은-D : \ test 디렉토리에서 python -m foo.bar.boo 명령을 실행하면 python 설치 폴더 또는 D : \ test 디렉토리가 sys.path에 추가됩니까? 내 이해는 sys.path에 d : \ test를 추가하고, foo.bar를 가져오고, boo 스크립트를 실행한다는 것입니다
변수

@ 변수-예, 시도해보세요.
Aaron Hall

1

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

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

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

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


-m 옵션이 현재 디렉토리를 sys.path에 추가한다는 것은 분명히 보안 문제입니다 (참조 : preload attack ). 이 동작은 Windows의 라이브러리 검색 순서와 유사합니다 (최근에 강화되기 전). Python이 추세를 따르지 않고 .NET 추가를 비활성화하는 간단한 방법을 제공하지 않는 것은 유감입니다. sys.path에.
ddbug
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.