[python] import 문은 항상 모듈 상단에 있어야합니까?

PEP 08 상태 :

가져 오기는 항상 파일의 맨 위에, 모듈 주석 및 문서 문자열 바로 다음과 모듈 전역 및 상수 바로 앞에 배치됩니다.

그러나 가져 오는 클래스 / 메서드 / 함수가 드문 경우에만 사용되는 경우, 필요할 때 가져 오기를 수행하는 것이 더 효율적입니까?

그렇지 않습니까?

class SomeClass(object):

    def not_often_called(self)
        from datetime import datetime
        self.datetime = datetime.now()

이보다 더 효율적입니까?

from datetime import datetime

class SomeClass(object):

    def not_often_called(self)
        self.datetime = datetime.now()



답변

모듈 가져 오기는 매우 빠르지 만 즉각적인 것은 아닙니다. 이것은 다음을 의미합니다.

  • 수입은 모듈 상단에 두는 것이 좋습니다. 한 번만 지불하는 사소한 비용이기 때문입니다.
  • 함수 내에 가져 오기를 넣으면 해당 함수에 대한 호출이 더 오래 걸립니다.

따라서 효율성에 관심이 있다면 수입품을 맨 위에 놓으십시오. 프로파일 링에 도움이 될 것으로 보이는 경우에만 함수로 이동하십시오 ( 성능을 향상시키는 가장 좋은 곳을 프로파일하기 위해 프로파일 했습니까 ?)


게으른 가져 오기를 수행하는 가장 좋은 이유는 다음과 같습니다.

  • 선택적 라이브러리 지원. 코드에 다른 라이브러리를 사용하는 여러 경로가있는 경우 선택적 라이브러리가 설치되지 않은 경우 중단하지 마십시오.
  • 에서 __init__.py수입하지만, 실제로 사용되지 않을 수있는 플러그인의. 예를 들어 bzrlibLazy-loading 프레임 워크 를 사용하는 Bazaar 플러그인이 있습니다 .

답변

import 문을 함수 안에 넣으면 순환 종속성을 막을 수 있습니다. 예를 들어, X.py와 Y.py라는 두 개의 모듈이 있고 두 모듈이 서로를 가져와야하는 경우 무한 루프를 일으키는 모듈 중 하나를 가져올 때 순환 종속성이 발생합니다. 모듈 중 하나에서 import 문을 이동하면 함수가 호출 될 때까지 다른 모듈을 가져 오려고 시도하지 않으며 해당 모듈을 이미 가져 오기 때문에 무한 루프가 없습니다. 자세한 내용은 여기를 참조하십시오 -effbot.org/zone/import-confusion.htm


답변

모듈의 맨 위가 아닌 모든 임포트를 사용하는 함수에 모든 임포트를 배치하는 관행을 채택했습니다.

내가 얻는 이점은보다 안정적으로 리팩토링 할 수 있다는 것입니다. 한 모듈에서 다른 모듈로 함수를 옮길 때, 그 함수는 기존의 모든 테스트에서 그대로 작동한다는 것을 알고 있습니다. 모듈 상단에 가져 오기가 있으면 함수를 이동할 때 새 모듈 가져 오기를 완료하고 최소화하는 데 많은 시간이 소요됩니다. 리팩토링 IDE는 이것을 무의미하게 만들 수 있습니다.

다른 곳에서 언급 한 바와 같이 속도 불이익이 있습니다. 내 응용 프로그램에서 이것을 측정했으며 내 목적에 중요하지 않은 것으로 나타났습니다.

검색에 의존하지 않고 모든 모듈 종속성을 미리 볼 수 있다는 것도 좋습니다 (예 : grep). 그러나 모듈 종속성에 관심이있는 이유는 일반적으로 단일 모듈뿐만 아니라 여러 파일로 구성된 전체 시스템을 설치, 리팩토링 또는 이동하기 때문입니다. 이 경우 어쨌든 시스템 수준의 종속성을 갖도록 전역 검색을 수행 할 것입니다. 따라서 실제로 시스템에 대한 이해를 돕기 위해 전 세계 수입품을 찾지 못했습니다.

나는 보통의 가져 오기를 넣어 sys내부를 if __name__=='__main__'확인하고 (같은 인수를 전달 sys.argv[1:]A를) main()기능. 이를 통해 가져 오지 않은 main컨텍스트에서 사용할 수 있습니다 sys.


답변

대부분의 경우 이것은 명확하고 현명한 작업에 유용하지만 항상 그런 것은 아닙니다. 다음은 모듈 가져 오기가 다른 곳에있을 수있는 몇 가지 상황의 예입니다.

먼저 다음과 같은 형식의 단위 테스트가있는 모듈을 가질 수 있습니다.

if __name__ == '__main__':
    import foo
    aa = foo.xyz()         # initiate something for the test

둘째, 런타임에 다른 모듈을 조건부로 가져와야 할 수도 있습니다.

if [condition]:
    import foo as plugin_api
else:
    import bar as plugin_api
xx = plugin_api.Plugin()
[...]

코드의 다른 부분으로 가져 오기를 수행 할 수있는 다른 상황이있을 수 있습니다.


답변

함수가 0 번 또는 1 번 호출 될 때 첫 번째 변형이 실제로 두 번째 변형보다 더 효율적입니다. 그러나 두 번째 및 후속 호출에서는 “모든 통화 가져 오기”방식이 실제로 덜 효율적입니다. “lazy import”를 수행하여 두 가지 방법 중 최고를 결합한 lazy-loading 기술에 대해서는 이 링크 를 참조하십시오 .

그러나 효율성 이외의 다른 이유가 있습니다. 한 가지 접근 방식은이 모듈의 종속성에 대한 코드를 읽는 사람에게 훨씬 더 명확합니다. 또한 실패 특성이 매우 다릅니다. 첫 번째는 “datetime”모듈이 없으면로드시 실패하고, 두 번째는 메소드가 호출 될 때까지 실패하지 않습니다.

추가 된 참고 : IronPython에서 가져 오기는 코드가 기본적으로 컴파일 될 때 컴파일되므로 CPython보다 가져 오기 비용이 약간 더 비쌉니다.


답변

Curt는 좋은 지적을합니다. 두 번째 버전은 더 명확하고 나중에로드 타임에 예기치 않게 실패합니다.

일반적으로 모듈 로딩의 효율성에 대해 걱정하지 않습니다. 모듈은 (a) 매우 빠르며 (b) 대부분 시작시에만 발생하기 때문입니다.

예기치 않은 시간에 헤비급 모듈을로드해야하는 경우, 그것은 아마로 동적으로로드하는 것이 더 의미가 __import__기능, 수 있는지 캐치에 ImportError예외 및 합리적인 방식으로 그들을 처리 할 수 있습니다.


답변

모듈을 너무 많이로드하는 효율성에 대해 걱정하지 않습니다. 모듈이 차지하는 메모리는 충분히 크지 않으며 (모듈식이라고 가정) 시작 비용은 무시할 수 있습니다.

대부분의 경우 소스 파일 맨 위에 모듈을로드하려고합니다. 코드를 읽는 사람에게는 어떤 모듈에서 어떤 기능이나 객체가 왔는지 훨씬 쉽게 알 수 있습니다.

코드의 다른 곳에서 모듈을 가져 오는 좋은 이유 중 하나는 디버깅 문에서 모듈을 사용하는 것입니다.

예를 들면 다음과 같습니다.

do_something_with_x(x)

나는 이것을 디버깅 할 수있다 :

from pprint import pprint
pprint(x)
do_something_with_x(x)

물론 코드의 다른 곳에서 모듈을 가져 오는 다른 이유는 모듈을 동적으로 가져와야하기 때문입니다. 선택의 여지가 거의 없기 때문입니다.

모듈을 너무 많이로드하는 효율성에 대해 걱정하지 않습니다. 모듈이 차지하는 메모리는 충분히 크지 않으며 (모듈식이라고 가정) 시작 비용은 무시할 수 있습니다.