함수 내에서 가져 오는 것이 비단뱀인가요?


126

PEP 8 말한다 :

  • 가져 오기는 항상 파일의 맨 위에, 모듈 주석 및 독 스트링 바로 뒤, 모듈 전역 및 상수 앞에 놓입니다.

Occation에서 나는 PEP 8을 위반합니다. 때때로 함수 내부에서 물건을 가져옵니다. 일반적으로 단일 함수 내에서만 사용되는 가져 오기가있는 경우이 작업을 수행합니다.

의견이 있으십니까?

편집 (내가 함수에서 가져 오는 것이 좋은 생각이 될 수 있다고 생각하는 이유) :

주된 이유 : 코드를 더 명확하게 만들 수 있습니다.

  • 함수 코드를 볼 때 "함수 / 클래스 xxx는 무엇입니까?"라고 자문 할 수 있습니다. (기능 내에서 사용되는 xxx). 모듈의 맨 위에 모든 가져 오기가있는 경우 거기에 가서 xxx가 무엇인지 확인해야합니다. 이것은 .NET을 사용할 때 더 많은 문제가됩니다 from m import xxx. m.xxx함수를 보면 더 많은 것을 알 수 있습니다. 무엇에 따라 m: 잘 알려진 최상위 모듈 / 패키지 ( import m)입니까? 아니면 하위 모듈 / 패키지 ( from a.b.c import m)입니까?
  • 어떤 경우에는 추가 정보 ( "xxx는 무엇입니까?")가 xxx가 사용되는 위치에 가까워지면 함수를 더 쉽게 이해할 수 있습니다.

2
성능을 위해 그렇게합니까?
Macarse

4
어떤 경우에는 코드가 더 명확 해집니다. 함수에서 가져올 때 원시 성능이 떨어질 것이라고 생각합니다 (import 문이 함수가 호출 될 때마다 실행되기 때문입니다).
codeape

"기능 / 클래스 xxx는 무엇입니까?"라고 대답 할 수 있습니다. 대신 수입 XYZ 구문을 사용하여 XYZ 가져 오기에서 ABC 구문
톰 Leys

1
명확성이 유일한 요소라면 U는 그 효과에 대한 관련 의견을 포함 할 수도 있습니다. ;)
Lakshman Prasad

5
@becomingGuru : 물론 이죠,하지만 의견은 ... 현실과 동기화 얻을 수 있습니다
codeape

답변:


88

장기적으로는 대부분의 가져 오기를 파일 맨 위에 두는 것이 고맙다고 생각합니다. 이렇게하면 가져와야하는 모듈이 모듈이 얼마나 복잡한 지 한눈에 알 수 있습니다.

기존 파일에 새 코드를 추가하는 경우 일반적으로 필요한 곳에서 가져 오기를 수행 한 다음 코드가 그대로 유지되면 가져 오기 행을 파일 맨 위로 이동하여 작업을 더 영구적으로 만들 것입니다.

한 가지 다른 점 ImportError은 코드가 실행되기 전에 예외 를받는 것을 선호한다는 것입니다. 온 전성 검사를 위해 맨 위에 가져 오는 또 다른 이유입니다.

사용 pyChecker하지 않는 모듈을 확인하는 데 사용합니다.


47

이와 관련하여 내가 PEP 8을 위반하는 두 가지 경우가 있습니다.

  • 순환 가져 오기 : 모듈 A가 모듈 B를 가져 오지만 모듈 B에있는 항목에는 모듈 A가 필요합니다 (이는 순환 종속성을 제거하기 위해 모듈을 리팩터링해야한다는 신호 인 경우가 많지만)
  • pdb 중단 점 삽입 : import pdb; pdb.set_trace()이것은 편리한 b / c입니다. import pdb디버깅하려는 모든 모듈의 맨 위에 배치하고 싶지 않으며 중단 점을 제거 할 때 가져 오기를 제거하는 것을 기억하기 쉽습니다.

이 두 가지 경우를 제외하고 모든 것을 맨 위에 두는 것이 좋습니다. 종속성이 더 명확 해집니다.


7
모듈 전체와 관련하여 종속성을 더 명확하게 만드는 데 동의합니다. 하지만 함수 수준에서 모든 것을 맨 위에 가져 오기 위해 코드를 덜 명확하게 만들 수 있다고 생각합니다. 함수의 코드를 볼 때 "함수 / 클래스 xxx는 무엇입니까?"라고 자문 할 수 있습니다. (xxx는 함수 내에서 사용됩니다). 그리고 xxx의 출처를 확인하려면 파일의 맨 위를 봐야합니다. 이것은 from m import xxx를 사용할 때 더 많은 문제입니다. m.xxx를 보면 더 많은 것을 알 수 있습니다. 적어도 m이 무엇인지 의심 할 여지가 없다면 말입니다.
codeape

20

다음은 우리가 사용하는 네 가지 가져 오기 사용 사례입니다.

  1. import(그리고 from x import y하고 import x as y) 상단

  2. 가져 오기를위한 선택. 맨 위에.

    import settings
    if setting.something:
        import this as foo
    else:
        import that as foo
  3. 조건부 가져 오기. JSON, XML 라이브러리 등과 함께 사용됩니다. 맨 위에.

    try:
        import this as foo
    except ImportError:
        import that as foo
  4. 동적 가져 오기. 지금까지 우리는 이것의 한 가지 예만 가지고 있습니다.

    import settings
    module_stuff = {}
    module= __import__( settings.some_module, module_stuff )
    x = module_stuff['x']

    이 동적 가져 오기는 코드를 가져 오지 않고 Python으로 작성된 복잡한 데이터 구조를 가져옵니다. 손으로 절인 것을 제외하고는 일종의 절인 데이터와 같습니다.

    이것은 또한 모듈의 상단에 있습니다.


코드를 더 명확하게하기 위해 수행하는 작업은 다음과 같습니다.

  • 모듈을 짧게 유지하십시오.

  • 모듈 맨 위에 모든 가져 오기가 있으면 이름이 무엇인지 확인하기 위해 그곳을 찾아야합니다. 모듈이 짧으면 쉽습니다.

  • 어떤 경우에는 이름이 사용되는 위치와 가까운 추가 정보가 있으면 함수를 더 쉽게 이해할 수 있습니다. 모듈이 짧으면 쉽습니다.


모듈을 짧게 유지하는 것은 물론 매우 좋은 생각입니다. 그러나 사용 가능한 기능에 대해 항상 "정보 가져 오기"를 사용하는 이점을 얻으려면 최대 모듈 길이가 한 화면 (아마도 최대 100 줄)이어야합니다. 그리고 대부분의 경우 실용적 이기에는 너무 짧을 것입니다.
codeape

나는 당신이 이것을 논리적 극단으로 취할 수 있다고 생각합니다. 복잡성을 관리하기 위해 멋진 임포트 기술이 필요하지 않을만큼 모듈이 "충분히 작다"는 균형점이있을 수 있다고 생각합니다. 우리의 평균 모듈 크기는 우연히도 약 100 줄입니다.
S.Lott 09-06-22

8

명심해야 할 한 가지는 불필요한 가져 오기로 인해 성능 문제가 발생할 수 있습니다. 따라서 이것이 자주 호출되는 함수라면 가져 오기를 맨 위에 두는 것이 좋습니다. 물론 이것은 이다 함수 내에서 가져 오면, 파일의 상단에 수입보다 더 명확한 것을 만들 수 유효한 경우가 있어요 그렇다면, 최적화 대부분의 경우에 최후의 수단의 성능이.

IronPython을 수행하는 경우 함수 내부를 가져 오는 것이 좋습니다 (IronPython에서 코드를 컴파일하는 속도가 느릴 수 있기 때문에). 따라서 내부 함수를 가져 오는 방법을 얻을 수 있습니다. 하지만 그 외에는 컨벤션에 맞서 싸울 가치가 없다고 주장합니다.

일반적으로 단일 함수 내에서만 사용되는 가져 오기가있는 경우이 작업을 수행합니다.

제가 말하고 싶은 또 다른 요점은 이것이 잠재적 인 유지 보수 문제 일 수 있다는 것입니다. 이전에 하나의 함수에서만 사용했던 모듈을 사용하는 함수를 추가하면 어떻게됩니까? 파일 맨 위에 가져 오기를 추가하는 것을 기억 하시겠습니까? 아니면 가져 오기를 위해 각각의 모든 기능을 스캔 하시겠습니까?

FWIW, 함수 내에서 가져 오는 것이 합당한 경우가 있습니다. 예를 들어 cx_Oracle에서 언어를 설정하려면 가져 오기 전에 NLS _LANG 환경 변수 를 설정해야합니다 . 따라서 다음과 같은 코드를 볼 수 있습니다.

import os

oracle = None

def InitializeOracle(lang):
    global oracle
    os.environ['NLS_LANG'] = lang
    import cx_Oracle
    oracle = cx_Oracle

2
귀하의 유지 보수 문제에 동의합니다. 리팩토링 코드는 약간 문제가 될 수 있습니다. 이전에 한 함수에서만 사용했던 모듈을 사용하는 두 번째 함수를 추가하면 가져 오기를 맨 위로 이동하거나 두 번째 함수에서도 모듈을 가져 와서 내 자신의 일반 규칙을 위반합니다.
codeape

2
성능 논쟁도 반대 방향으로 갈 수 있다고 생각합니다. 모듈 가져 오기는 시간이 많이 걸릴 수 있습니다. 슈퍼 컴퓨터와 같은 분산 파일 시스템에서는 numpy와 같은 큰 모듈을 가져 오는 데 몇 초가 걸릴 수 있습니다. 모듈이 거의 사용되지 않는 단일 함수에만 필요한 경우 함수에서 가져 오면 일반적인 경우의 속도가 크게 빨라집니다.
amaurea

6

자체 테스트 모듈에 대해 이전에이 규칙을 어겼습니다. 즉, 일반적으로 지원용으로 만 사용되지만 자체적으로 실행하면 기능을 테스트 할 수 있도록 메인을 정의합니다. 이 경우 가끔 수입 getopt하고 cmd나는 그것이 이러한 모듈은 모듈의 정상적인 작동과는 아무 상관이 없습니다 만 테스트에 포함되고 있다는 코드를 읽는 사람에게 명확하게 원하기 때문에, 단지 주이다.


5

모듈을 두 번로드하는 것에 대한 질문에서 -왜 둘 다 아닌가?

스크립트 상단의 가져 오기는이 함수를 더 원자 적으로 만드는 함수의 종속성 및 또 다른 가져 오기를 나타내며, 연속 가져 오기가 저렴하기 때문에 성능 저하를 일으키지 않는 것처럼 보입니다.


3

import아닌 from x import *한 상단에 배치해야합니다. 전역 네임 스페이스에 하나의 이름 만 추가하고 PEP 8을 고수합니다. 또한 나중에 다른 곳에서 필요할 경우 다른 곳으로 이동할 필요가 없습니다.

큰 문제는 아니지만 거의 차이가 없기 때문에 PEP 8이 말하는 것을 권장합니다.


3
실제로 from x import *함수 안에 넣으면 적어도 2.5에서 SyntaxWarning이 생성됩니다.
Rick Copeland

3

sqlalchemy : 종속성 주입에서 사용되는 대체 방법을 살펴보십시오.

@util.dependencies("sqlalchemy.orm.query")
def merge_result(query, *args):
    #...
    query.Query(...)

가져온 라이브러리가 데코레이터에서 선언되고 함수에 인수로 전달 되는 방법에 주목 하십시오 !

이 접근 방식은 코드를 깔끔하게 만들고 문 보다 4.5 배 더 빠르게 작동 import합니다!

벤치 마크 : https://gist.github.com/kolypto/589e84fbcfb6312532658df2fabdb796


2

'일반'모듈이고 실행할 수있는 (즉 if __name__ == '__main__':,-섹션이있는) 모듈에서는 일반적으로 메인 섹션 내에서 모듈을 실행할 때만 사용되는 모듈을 가져옵니다.

예:

def really_useful_function(data):
    ...


def main():
    from pathlib import Path
    from argparse import ArgumentParser
    from dataloader import load_data_from_directory

    parser = ArgumentParser()
    parser.add_argument('directory')
    args = parser.parse_args()
    data = load_data_from_directory(Path(args.directory))
    print(really_useful_function(data)


if __name__ == '__main__':
    main()

1

import거의 사용하지 않는 기능 내부에 도움이 될 수있는 또 다른 (아마도 "코너") 경우가 있습니다 . 시작 시간을 단축하는 것입니다.

작은 IoT 서버에서 실행되는 다소 복잡한 프로그램이 직렬 회선에서 명령을 받고 작업을 수행하는 것으로 한 번 벽에 부딪 혔습니다.

서버 시작 전에 모든 가져 오기가 처리 import되도록 파일 맨 위에 명령문을 배치 합니다 . 때문에 목록에 포함 , , 및 기타 "무거운 무게"(와의 SoC는 매우 강력하지 않았다)이 의미 importjinja2lxmlsignxml 첫 번째 명령 전에 실제로 실행되었다.

OTOH는 대부분의 가져 오기를 함수에 배치하여 몇 초 만에 직렬 회선에서 서버를 "살아"게 할 수있었습니다. 물론 모듈이 실제로 필요했을 때 비용을 지불해야했습니다 (참고 : import유휴 시간에 s를 수행하는 백그라운드 작업을 생성하여 완화 할 수도 있습니다 ).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.