__ spec __ trăn là gì?

Python được tổ chức thành các mô-đun và gói. Một mô-đun là một tệp Python và một gói là một tập hợp các mô-đun. Xem xét ví dụ sau về nhập mô-đun

import random
random.randint(1,10)

from random import randint
randint(1,10)
8 là một mô-đun tích hợp sẵn của Python. Trong dòng đầu tiên, nó nhập mô-đun
from random import randint
randint(1,10)
9 và làm cho nó có sẵn để sử dụng, sau đó nó truy cập vào
import pandas
pandas.DataFrame()
0. Nếu bạn mở một IDE và gỡ lỗi quá trình nhập, bạn sẽ thấy mã nằm trong tệp
import pandas
pandas.DataFrame()
1

Bạn cũng có thể nhập

import pandas
pandas.DataFrame()
2 như thế này

from random import randint
randint(1,10)

Hãy xem một ví dụ từ một gói

import pandas
pandas.DataFrame()

Thoạt nhìn, bạn thực sự không thể biết đó là mô-đun hay gói. Nhưng nếu bạn gỡ lỗi quá trình nhập, nó sẽ chuyển hướng bạn đến

import pandas
pandas.DataFrame()
3 thay vì
import pandas
pandas.DataFrame()
4. Một gói chứa các mô-đun con hoặc đệ quy, các gói con và
import pandas
pandas.DataFrame()
5 là điểm vào của gói

Nhưng đó không phải là cách duy nhất, các chức năng như

import pandas
pandas.DataFrame()
6 và
import pandas
pandas.DataFrame()
7 tích hợp cũng có thể được sử dụng

>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')

Bưu kiện. __trong đó__. py

Vậy

import pandas
pandas.DataFrame()
5 là gì?

A chứa tệp

import pandas
pandas.DataFrame()
5. Khi gói được nhập, tệp
import pandas
pandas.DataFrame()
5 này được thực thi hoàn toàn và các đối tượng mà nó xác định được liên kết với các tên trong không gian tên của gói. Tập tin này có thể để trống

Hãy xem một ví dụ. Tôi có một cấu trúc thư mục như thế này.

>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
1 là gói của tôi và
>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
2 là mô hình con

cấu trúc thư mục (Được tạo bởi Xiaoxu Gao)

Bên trong

>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
3 , tôi có một biến số
>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
4 mà tôi muốn sử dụng trong biến
>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
5. Tôi sẽ tạo một số phiên bản của
import pandas
pandas.DataFrame()
5 và xem nó ảnh hưởng như thế nào đến việc nhập vào
>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
5

# m1.py
DATE = "2022-01-01"

Trường hợp 1. tập tin

>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
8 trống

Vì tệp

import pandas
pandas.DataFrame()
5 trống khi chúng tôi nhập
>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
1 , không có mô hình con nào được nhập, do đó, nó không biết sự tồn tại của
>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
2. Nếu chúng ta nhập
>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
2 rõ ràng bằng cách sử dụng
# m1.py
DATE = "2022-01-01"
3 , thì mọi thứ bên trong
>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
3 sẽ được nhập. Nhưng sau đó, chúng tôi không thực sự nhập gói mà nhập mô-đun. Như bạn có thể tưởng tượng, nếu gói của bạn có nhiều mô-đun con, bạn cần nhập từng mô-đun một cách rõ ràng, điều này có thể khá tẻ nhạt

# main.py
import p1
p1.m1.DATE
>> AttributeError: module 'p1' has no attribute 'm1'from p1 import m1
from p1 import m2, m3 ...# needs to explictly import every submodule
m1.DATEWorks!!

Trường hợp2. nhập các mô-đun con trong tệp

>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
8

Thay vì để trống, chúng tôi nhập mọi thứ từ

>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
2 vào tệp
import pandas
pandas.DataFrame()
5. Sau đó,
# m1.py
DATE = "2022-01-01"
8 trong tệp
>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
5 sẽ nhận ra các biến trong
>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
3 và bạn có thể gọi trực tiếp
# main.py
import p1
p1.m1.DATE
>> AttributeError: module 'p1' has no attribute 'm1'from p1 import m1
from p1 import m2, m3 ...# needs to explictly import every submodule
m1.DATEWorks!!
1 mà không cần biết nó đến từ mô-đun nào

# __init__.py
from .m1 import * # or from p1.m1 import *
from .m2 import *
# main.py
import p1
p1.DATE

Bạn có thể đã nhận thấy dấu chấm trước khi

>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
2. Đó là một lối tắt bảo nó tìm kiếm trong gói hiện tại. Đó là một ví dụ về nhập khẩu tương đối. Nhập tuyệt đối tương đương sẽ đặt tên rõ ràng cho gói hiện tại như
# main.py
import p1
p1.m1.DATE
>> AttributeError: module 'p1' has no attribute 'm1'from p1 import m1
from p1 import m2, m3 ...# needs to explictly import every submodule
m1.DATEWorks!!
3

Có một báo trước mặc dù. Nếu một mô hình con khác trong gói chứa cùng một biến, thì mô hình con được nhập sau sẽ ghi đè lên mô hình con trước đó

Ưu điểm của việc có một

import pandas
pandas.DataFrame()
5 không trống là làm cho tất cả các mô hình con đã có sẵn cho máy khách khi họ nhập gói, vì vậy mã máy khách trông gọn gàng hơn

Python tìm các mô-đun và gói như thế nào?

Hệ thống tìm kiếm các mô-đun và gói trong Python được gọi là Máy nhập khẩu, bao gồm các công cụ tìm, trình tải, bộ đệm và bộ điều phối

Máy móc nhập khẩu (Tạo bởi Xiaoxu Gao)
  1. Mô-đun tìm kiếm trong bộ đệm ẩn
    # main.py
    import p1
    p1.m1.DATE
    >> AttributeError: module 'p1' has no attribute 'm1'from p1 import m1
    from p1 import m2, m3 ...# needs to explictly import every submodule
    m1.DATEWorks!!
    5

Mỗi khi bạn nhập một mô-đun, thứ đầu tiên được tìm kiếm là từ điển

# main.py
import p1
p1.m1.DATE
>> AttributeError: module 'p1' has no attribute 'm1'from p1 import m1
from p1 import m2, m3 ...# needs to explictly import every submodule
m1.DATEWorks!!
6. Các khóa là tên mô-đun và các giá trị là chính mô-đun thực tế.
# main.py
import p1
p1.m1.DATE
>> AttributeError: module 'p1' has no attribute 'm1'from p1 import m1
from p1 import m2, m3 ...# needs to explictly import every submodule
m1.DATEWorks!!
6 là một từ điển được lưu trong bộ nhớ đệm, nếu mô-đun ở đó thì nó sẽ được trả về ngay lập tức, nếu không, nó sẽ được tìm kiếm trong hệ thống

Quay lại ví dụ trước. Khi chúng tôi nhập

>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
1, hai mục được thêm vào
# main.py
import p1
p1.m1.DATE
>> AttributeError: module 'p1' has no attribute 'm1'from p1 import m1
from p1 import m2, m3 ...# needs to explictly import every submodule
m1.DATEWorks!!
6. Mô-đun cấp cao nhất
import pandas
pandas.DataFrame()
5 và mô-đun con
>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
3

import p1
import sys
print(sys.modules)
{
'p1': ,
'p1.m1':
...
}

Nếu chúng ta nhập hai lần, lần nhập thứ hai sẽ đọc từ bộ đệm. Nhưng nếu chúng ta cố tình xóa mục từ từ điển

# main.py
import p1
p1.m1.DATE
>> AttributeError: module 'p1' has no attribute 'm1'from p1 import m1
from p1 import m2, m3 ...# needs to explictly import every submodule
m1.DATEWorks!!
6, thì lần nhập thứ hai sẽ trả về một đối tượng mô-đun mới

# read from cache
import p1
import sys
old = p1
import p1
new = p1
assert old is new
# read from system
import p1
import sys
old = p1
del sys.modules['p1']
import p1
new = p1
assert not old is new

2. Thông số mô-đun tìm kiếm

Nếu mô-đun không có trong từ điển

# main.py
import p1
p1.m1.DATE
>> AttributeError: module 'p1' has no attribute 'm1'from p1 import m1
from p1 import m2, m3 ...# needs to explictly import every submodule
m1.DATEWorks!!
6, thì nó cần được tìm kiếm theo danh sách các đối tượng có phương thức
# __init__.py
from .m1 import * # or from p1.m1 import *
from .m2 import *
# main.py
import p1
p1.DATE
4 của chúng để xem liệu mô-đun có thể được nhập hay không

import sys
print(sys.meta_path)
[ ,
,
]

# __init__.py
from .m1 import * # or from p1.m1 import *
from .m2 import *
# main.py
import p1
p1.DATE
5 được sử dụng cho các mô-đun tích hợp.
# __init__.py
from .m1 import * # or from p1.m1 import *
from .m2 import *
# main.py
import p1
p1.DATE
6 được sử dụng để định vị các mô-đun bị đóng băng.
# __init__.py
from .m1 import * # or from p1.m1 import *
from .m2 import *
# main.py
import p1
p1.DATE
7 chịu trách nhiệm tìm các mô-đun nằm ở một trong những đường dẫn này

  • # __init__.py
    from .m1 import * # or from p1.m1 import *
    from .m2 import *
    # main.py
    import p1
    p1.DATE
    8
  • # __init__.py
    from .m1 import * # or from p1.m1 import *
    from .m2 import *
    # main.py
    import p1
    p1.DATE
    9
  • import p1
    import sys
    print(sys.modules)
    {
    'p1': ,
    'p1.m1':
    ...
    }
    0
  • import p1
    import sys
    print(sys.modules)
    {
    'p1': ,
    'p1.m1':
    ...
    }
    1

Hãy xem có gì trong

# __init__.py
from .m1 import * # or from p1.m1 import *
from .m2 import *
# main.py
import p1
p1.DATE
8

from random import randint
randint(1,10)
0

# __init__.py
from .m1 import * # or from p1.m1 import *
from .m2 import *
# main.py
import p1
p1.DATE
7 sẽ sử dụng phương pháp
import p1
import sys
print(sys.modules)
{
'p1': ,
'p1.m1':
...
}
4 để tìm kiếm
import p1
import sys
print(sys.modules)
{
'p1': ,
'p1.m1':
...
}
5 của mô-đun. Mỗi mô-đun có một đối tượng đặc tả là siêu dữ liệu của mô-đun. Một trong những thuộc tính là
import p1
import sys
print(sys.modules)
{
'p1': ,
'p1.m1':
...
}
6.
import p1
import sys
print(sys.modules)
{
'p1': ,
'p1.m1':
...
}
6 cho biết máy móc nhập khẩu sử dụng bộ tải nào trong khi tạo mô-đun

from random import randint
randint(1,10)
1

3. Tải mô-đun

Sau khi tìm thấy thông số kỹ thuật của mô-đun, máy nhập sẽ sử dụng thuộc tính trình tải để khởi tạo mô-đun và lưu trữ nó trong từ điển

# main.py
import p1
p1.m1.DATE
>> AttributeError: module 'p1' has no attribute 'm1'from p1 import m1
from p1 import m2, m3 ...# needs to explictly import every submodule
m1.DATEWorks!!
6. Bạn có thể đọc phần này để hiểu điều gì xảy ra trong quá trình tải phần nhập

Nhập vòng tròn Python

Cuối cùng, hãy xem xét một vấn đề thú vị về nhập khẩu. Nhập Khẩu Thông Tư. Nhập vòng tròn xảy ra khi hai hoặc nhiều mô-đun phụ thuộc vào nhau. Trong ví dụ này,

import p1
import sys
print(sys.modules)
{
'p1': ,
'p1.m1':
...
}
9 phụ thuộc vào
>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
3 và
>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
3 phụ thuộc vào
import p1
import sys
print(sys.modules)
{
'p1': ,
'p1.m1':
...
}
9

phụ thuộc mô-đun (Tạo bởi Xiaoxu Gao)
from random import randint
randint(1,10)
2

Python không thể tìm thấy thuộc tính

# read from cache
import p1
import sys
old = p1
import p1
new = p1
assert old is new
# read from system
import p1
import sys
old = p1
del sys.modules['p1']
import p1
new = p1
assert not old is new
3 từ mô-đun
>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
2. Vậy tại sao điều này xảy ra? . Khi
# read from cache
import p1
import sys
old = p1
import p1
new = p1
assert old is new
# read from system
import p1
import sys
old = p1
del sys.modules['p1']
import p1
new = p1
assert not old is new
5, Python đi qua
>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
3 từng dòng một. Điều đầu tiên nó tìm thấy là
# read from cache
import p1
import sys
old = p1
import p1
new = p1
assert old is new
# read from system
import p1
import sys
old = p1
del sys.modules['p1']
import p1
new = p1
assert not old is new
7 , vì vậy nó sẽ nhập
import p1
import sys
print(sys.modules)
{
'p1': ,
'p1.m1':
...
}
9. Dòng đầu tiên là nhập
>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
2, nhưng vì Python chưa đi qua mọi thứ trong
>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
3, nên chúng tôi nhận được một đối tượng được khởi tạo một nửa. Khi chúng ta gọi
import sys
print(sys.meta_path)
[ ,
,
]
1 mà python không nhìn thấy nó, nó sẽ đưa ra một ngoại lệ AttributeError

Nhập khẩu tròn (Tạo bởi Xiaoxu Gao)

Vậy cách khắc phục nhập vòng như thế nào? . Hầu hết thời gian, sự phụ thuộc không thực sự cần thiết. Một giải pháp đơn giản là hợp nhất cả hai chức năng thành một mô-đun duy nhất

from random import randint
randint(1,10)
3

Đôi khi, mô-đun hợp nhất có thể trở nên rất lớn. Một giải pháp khác là trì hoãn việc nhập khẩu

import sys
print(sys.meta_path)
[ ,
,
]
2 để nhập khẩu khi cần thiết. Điều này có thể được thực hiện bằng cách đặt
# read from cache
import p1
import sys
old = p1
import p1
new = p1
assert old is new
# read from system
import p1
import sys
old = p1
del sys.modules['p1']
import p1
new = p1
assert not old is new
7 trong hàm
import sys
print(sys.meta_path)
[ ,
,
]
4. Trong trường hợp này, Python sẽ tải tất cả các chức năng trong
>>> import importlib
>>> importlib.import_module('random')
>>> __import__('random')
3 và sau đó chỉ tải
import p1
import sys
print(sys.modules)
{
'p1': ,
'p1.m1':
...
}
9 khi cần thiết

from random import randint
randint(1,10)
4

Nhiều cơ sở mã sử dụng nhập hoãn lại không nhất thiết phải giải quyết vấn đề phụ thuộc vòng tròn mà để tăng tốc thời gian khởi động. Một ví dụ từ là không viết mã cấp cao nhất không cần thiết để tạo DAG. Điều này là do tác động của tốc độ phân tích cú pháp mã cấp cao nhất đối với cả hiệu suất và khả năng mở rộng của Airflow

from random import randint
randint(1,10)
5

Phần kết luận

Như mọi khi, tôi hy vọng bạn thấy bài viết này hữu ích và đầy cảm hứng. Chúng tôi coi nhiều thứ trong Python là điều hiển nhiên, nhưng thật thú vị khi khám phá cách nó hoạt động bên trong. Hy vọng bạn thích nó, Chúc mừng

Thông số mô-đun Python là gì?

máy có tên là “ModuleSpec”. Nó sẽ cung cấp tất cả thông tin liên quan đến nhập được sử dụng để tải mô-đun và sẽ khả dụng mà không cần tải mô-đun trước. Trình tìm kiếm sẽ trực tiếp cung cấp thông số kỹ thuật của mô-đun thay vì trình tải (họ sẽ tiếp tục cung cấp gián tiếp).

__ tất cả __ trong Python là gì?

Danh sách các chuỗi xác định biến nào phải được nhập vào tệp khác được gọi là __all__ trong Python. Các biến được khai báo trong danh sách đó chỉ có thể được sử dụng trong tệp khác sau khi nhập tệp này, các biến còn lại nếu được gọi sẽ báo lỗi.

Sự khác biệt giữa __ nhập __ và nhập trong Python là gì?

Điều này có nghĩa là tất cả ngữ nghĩa của hàm được lấy từ importlib. __nhập khẩu__(). Sự khác biệt quan trọng nhất giữa hai hàm này là import_module() trả về gói hoặc mô-đun đã chỉ định (e. g. pkg. mod ), trong khi __import__() trả về gói hoặc mô-đun cấp cao nhất (e. g. pkg ) .

Hệ thống nhập khẩu trong Python là gì?

Mã Python trong một mô-đun có quyền truy cập vào mã trong một mô-đun khác bằng quá trình nhập mã đó . Câu lệnh nhập khẩu là cách phổ biến nhất để gọi máy móc nhập khẩu, nhưng nó không phải là cách duy nhất.