파이썬 - 고급 사용법 - 데이터 모델(2)

12741 단어

파이썬 - 고급 사용법 - 데이터 모델(2)


많은 사람들이 코드를 쓸 때 코드의 밑바닥 운행 논리를 고려하지 않아 문제가 발생한 후에 문제가 어디에서 발생했는지 알지 못한다. 설령 검색을 통해 문제를 해결했다 하더라도 다시 이 문제를 만났을 때 종종 곤경에 빠진다.
따라서 코드의 실제 운행 규칙을 이해하고 파악한 후에 인코딩을 하는 것이 문법만 알고 직접 쓰는 것보다 함정을 피할 수 있다.
한 언어의 문법 쓰기 규범을 배운 후에 전체 언어의 기초 설계, 번역, 운행 과정을 깊이 이해하면 우리가 이 언어에 대한 파악에 도움이 되고 자신의 업무 효율을 향상시키며 더욱 높은 품질의 코드를 쓰는 데 도움이 된다.
이 장은 modulepython의 모듈 도입 시스템에만 대해 상세하게 설명하였다.

모듈


모듈은 python 코드의 기본 조직 단원으로 에 의해 만들어졌으며 import 문장에 의해 호출되었다.다음은 이 말의 명사를 각각 설명해 봅시다.

module

module 대상도 python 코드의 조직 단위이다.각 모듈은 임의의 python 대상을 포함할 수 있는 독립된 명칭 공간을 가지고 있다.
>>> import os
>>> os

python도 대상이다.
>>> type(os)

>>> type(type(os))

module는 어떻게 시스템에 생성되고 도입되었습니까?

시스템 가져오기

modulepython 내 코드에 접근하는 데 사용되는 논리이다.
호출 시작 module 의 상용 방식: 문장.import 및 내장importlib.import_module() 함수를 통해 호출을 시작할 수 있습니다.
>>> import os
>>> type(os)


__import__() 문은 두 가지 작업을 결합합니다.


1, 지정한 이름의 모듈을 검색하고 검색 결과를 현재 역할 영역의 이름으로 연결합니다.import 문장의 검색 동작은 import 함수에 대한 매개 변수의 호출로 정의됩니다.
  • 검색을 시작하기 위해서 파이톤은 모듈의 완전한 한정된 이름을 가져와야 합니다.이 명칭은 __import__() 문장에 포함된 각종 매개 변수에서 나올 수도 있고 import 또는 importlib.import_module() 함수에 전달된 인삼에서 나올 수도 있다.
  • 이 명칭은 검색을 가져오는 각 단계에서 사용되며, 하위 모듈의 점호 경로를 가리킬 수도 있다. 예를 들어foo.bar.baz. 이 경우 파이톤은 먼저 foo를 가져오고 그 다음에 foo를 가져옵니다.bar, 마지막은foo.bar.baz. 이러한 가져오기에 실패하면 ModuleNotFoundError가 발생합니다.
  • >>> a = __import__('os')
    >>> a
    
    >>> type(a)
    
    
  • 이때 우리는 가져오지 않고 __import__()만 새로 만들었다os. 그리고 그것을 초기화했다.module라는 이름으로 사용하려면 os명명 공간에 귀속{'os':a}해야 합니다.
  • >>> a = __import__('os')
    >>> globals()['os'] = a
    >>> os
    
    

    2, 우리가 osglobals가 대표하는 전역 이름 공간에 귀속시키면 바로 호출할 수 있습니다.
    주의: import 문장이 실행될 때 표준 내장__import__()이 호출되고 다른 호출 시스템의 메커니즘(예를 들어 importlib.import_module()이 돌아가기__import__()를 선택하고 그들의 해결 방안을 사용하여 도입 메커니즘을 실현할 수 있습니다.

    첫 번째 가져오기: 모듈이 첫 번째 단어로 가져올 때python에서 이 모듈을 검색합니다. 찾으면module 대상을 만들고 초기화합니다.찾지 못하면 ModuleNotFoundError가 던져집니다.

    >>> import osss
    Traceback (most recent call last):
      File "", line 1, in 
    ModuleNotFoundError: No module named 'osss'
    

    네임스페이스:namespace

  • 네임스페이스는 변수를 저장하는 장소입니다.
  • 명명 공간은 국부적, 전역적, 내장되어 있고 대상에 끼워 넣은 명명 공간도 있다(방법 내).
  • 네임스페이스는 네임스페이스의 충돌을 방지하여 모듈화를 지원합니다.

  • 파이톤은 어떻게 명명 공간을 사용합니까?

    먼저python 해석기가 이름 공간에 저장된 내용을 보십시오

    python3
    Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 03:13:28)
    [Clang 6.0 (clang-600.0.57)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> globals()
    {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': }
    >>> import os
    >>> globals()
    {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': , 'os': }
    >>> type(globals())
    
    

    우리가 module를 가져왔을 때 대응하는 명칭 공간globals()에 이 모듈os과 대응하는 key이 기록되어 있는 것을 발견했다. os.전체 네임스페이스는 dict로 저장됩니다.

    다음은 정의된 함수, 변수가 글로벌 ()에 어떻게 저장되는지 살펴보자.


    함수: 함수test()를 정의했는데 globals()에서 'test': 입니다.
    >>> def test(a):
    ...     print(a)
    ...     return a
    ...
    >>> globals()
    {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': , 'os': , 'test': }
    

    우리가 출력test 방법을 내보냈을 때 실제로도 globals()에서 test의 키 값이 존재하는지 찾고 존재할 때 저장된 value 값을 되돌려준다.
    >>> type(test)
    
    >>> test
    
    >>> globals()['test']
    
    

    우리가 test를 호출했을 때도 사실은 호출되었다globals()['test']().실제 대상이 실행될 수 있는지의 여부는 실행 가능python에서 정의한 호출 가능 이 있느냐 없느냐에 달려 있다.
    >>> globals()['test'](1)
    1
    1
    

    변수: 변수를 정의했습니다 a=1.그 결과 저장된 변수'a':1도 나타났다.
    >>> a = 1
    >>> globals()
    {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': , 'os': , 'test': , 'a': 1}
    

    사용자 정의 모듈과 모듈에 정의된 방법과 변수의 사용 방식을 살펴보겠습니다


    먼저 모듈test1을 정의했고 다음은 모듈의 내용으로 함수test와 변수a를 포함한다.
    # test1.py
    import os
    
    def test():
        print(1)
    
    a = 1
    
    print(__name__)
    
    if __name__ == "__main__":
        print(__name__)
        test()
    

    다음은 설명기 메인 프로세스에 test1 가져오려고 합니다.
    [Clang 6.0 (clang-600.0.57)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import test1
    test1
    >>> type(test1)
    
    >>> test1
    
    
    python문장을 통해 import모듈을 가져왔습니다.볼 수 있는 test1의 유형은 test1이고 귀속된 값은 module 파일입니다.
    현재, 우리는 이미 가져왔습니다 test1.py. 다음은 그것을 어떻게 사용하는지 보겠습니다.
    >>> test1.a
    1
    >>> test1.os
    
    >>> test1.test
    
    

    우리가 test1 에서 정의한 변수 test1 를 호출했을 때, 직접 호출할 수 있는 것을 발견했다.aa는 모두 test 모듈에 정의되어 있기 때문에 우리는 가져온 후 모듈에 정의된 변수와 방법을 직접 사용할 수 있고 test1를 사용하여 호출할 수 있다.test1.xxx에서 가져온 모듈도 상술한 방법을 통해 호출할 수 있습니다.
    단, test1 모듈은 os에서 가져왔습니다. 가져오는 주 프로세스에서 직접 사용할 수 있습니까?
    >>> os
    Traceback (most recent call last):
      File "", line 1, in 
    NameError: name 'os' is not defined
    >>> test1.os
    
    

    답은 안되지.
    가져오기test1 모듈은 test1이기 때문에 os의 전역 이름 공간test1에 저장test1되어 있고 globals()를 통해 호출할 수 있습니다.그러나 현재 프로세스에서 우리는 {'os':이 없기 때문에 test1에는 import os만 저장하고 globals()와 관련된 정보는 없다.
    >>> globals()
    {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': , 'a': 1, 'test1': }
    

    따라서 현재 프로세스에서 test1 를 다시 가져와야만 사용할 수 있습니다.그럼 os 두 번 도입됐는데 두 개의 다른 모듈이 생기지 않을까요?
    >>> test1.os
    
    >>> import os
    >>> os
    
    >>> id(test1.os)
    4537473368
    >>> id(os)
    4537473368
    

    물론 Python은 같은 모듈을 두 번 가져오지 않습니다. 이전에 가져온 모듈을 다시 가져오려고 시도할 때, Python 해석기는 가져오려고 시도합니다. 이 이름이 있는 모듈이 이미 가져온 것을 발견하면 가져온 모듈을 현재 이름 공간에 다시 도입하고 가져온 이름에 연결합니다.이렇게 하면 우리는 중복 가져오지 않는 상황에서 모듈을 사용할 수 있다.
    그러나 가져온 모듈을 업데이트하려면 어떻게 해야 합니까?
    예를 들어 가져온 os 모듈에 변수를 추가하고 싶습니다os.
    b = "test on reload"
    

    우리는 어떻게 사용합니까?
    Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 03:13:28)
    [Clang 6.0 (clang-600.0.57)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import test1
    test1
    >>> id(test1)
    4510694920
    >>> test1.a
    1
    >>> test1.b
    Traceback (most recent call last):
      File "", line 1, in 
    AttributeError: module 'test1' has no attribute 'b'
    

    내가 추가를 끝낸 후에 우리는 방문을 시도했다. test1 결과는 찾지 못했다. 설령 우리가 다시 가져오더라도 b 가져올 수 없었다. b 앞에서 우리가 말했듯이, 이미 쏟아진 모듈을 다시 가져올 때 다시 가져올 수 없기 때문에,python은 이전에 가져온 대상을 효율적으로 직접 사용할 수 없기 때문이다. test1그래서 우리는 사용해야 한다b.
    >>> import importlib
    >>> importlib.reload(test1)
    test1
    
    >>> id(test1)
    4510694920
    >>> test1.b
    'test on reload'
    

    사용module은 새로운 대상을 다시 생성하지 않는다. importlib.reload()를 통해 이전에 가져온 importlib.reload() 대상을 볼 수 있지만 id() 대상의 내용을 업데이트했고 가져올 때도 실행module 출력module을 했다.
    루프 가져오기 정보
    모듈print('test')에서 test를 사용하고 a에서 b.b_test 모듈을 동시에 사용하면 해석기가 오류를 알려 줍니다.
    # a.py
    from b import b_test
    print(b_test)
    a_test = 1
    
    # b.py
    from a import a_test
    print(a_test)
    b_test = 2
    
    >>> import a
    Traceback (most recent call last):
      File "", line 1, in 
      File "/Users/mengwei/workspace/mine/python_test/a.py", line 1, in 
        from b import b_test
      File "/Users/mengwei/workspace/mine/python_test/b.py", line 1, in 
        from a import a_test
    ImportError: cannot import name 'a_test' from 'a' (/Users/mengwei/workspace/mine/python_test/a.py)
    

    도입환은 어떻게 생겼을까요?
    1, 사실 우리가 b 모듈을 가져왔을 때 가져오기 작업을 시작했는데 결과a.a_test에서 a 모듈의 정보를 인용했고 b의 가장 가까운 위치에 있었다.현재a는 초기화되었지만 정보a는 비어 있습니다.
    2, 도입 시스템은 현재 도입b 모듈을 가져왔는데 a의 가장 앞쪽 위치가 도입a module이라는 것을 발견했다.
    3, 그러나 지금까지 __dict__ 모듈은 아무런 조작도 실행하지 않았기 때문에 b 변수는 ba에 아예 놓여 있지 않았다.
    4, 가져오기 시스템 오류 보고, a 모듈에서 a_test 요소가 발견되지 않았습니다.
    코드를 조금만 바꾸면 상술한 문제는 다시 나타나지 않을 것입니다. 그것은 가져오기 module a 전에 __dict__ 조작을 실행하는 것입니다.
    # a.py
    a_test = 1
    from b import b_test
    print(b_test)
    

    이제 가져오기 작업을 수행하여 a 모듈을 순조롭게 가져올 수 있습니다.이때a_test 모듈은 b에서 가져왔기 때문에 오류가 없습니다.
    >>> import a
    1
    2
    >>> import b
    

    그러나 a_test 모듈이 처음 도입되면 이전과 같다. a 모듈이 b 모듈 정의a의 문장을 실행하기 전에 도입했기 때문이다b.
    >>> import b
    Traceback (most recent call last):
      File "", line 1, in 
      File "/Users/mengwei/workspace/mine/python_test/b.py", line 1, in 
        from a import a_test
      File "/Users/mengwei/workspace/mine/python_test/a.py", line 2, in 
        from b import b_test
    ImportError: cannot import name 'b_test' from 'b' (/Users/mengwei/workspace/mine/python_test/b.py)
    

    그래서 가끔은 코드를 쓸 때 먼저 가져오는 것a이 정상적이고 먼저 가져오는 것b이 실패하고 오류가 발생하는 경우가 많습니다. 그 문제점이 어디에 있는지 아시겠죠?
    글로벌,local 키워드,name,import,from import,가져오기 경로 검색 우선순위 등에 대해 다음 장에서 설명합니다.

    좋은 웹페이지 즐겨찾기