-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.