-
-
Notifications
You must be signed in to change notification settings - Fork 225
Expand file tree
/
Copy pathimport.html
More file actions
781 lines (733 loc) · 118 KB
/
Copy pathimport.html
File metadata and controls
781 lines (733 loc) · 118 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
<!DOCTYPE html>
<html lang="zh-TW" data-content_root="../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<title>5. 模組引入系統 — Python 3.14.7 說明文件</title><meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=b86133f3" />
<link rel="stylesheet" type="text/css" href="../_static/classic.css?v=234b1a7c" />
<link rel="stylesheet" type="text/css" href="../_static/pydoctheme.css?v=4365c8fe" />
<link id="pygments_dark_css" media="(prefers-color-scheme: dark)" rel="stylesheet" type="text/css" href="../_static/pygments_dark.css?v=5349f25f" />
<script src="../_static/documentation_options.js?v=a9d878bf"></script>
<script src="../_static/doctools.js?v=9bcbadda"></script>
<script src="../_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="../_static/translations.js?v=cbf116e0"></script>
<script src="../_static/sidebar.js"></script>
<link rel="search" type="application/opensearchdescription+xml"
title="在 Python 3.14.7 說明文件 中搜尋"
href="../_static/opensearch.xml"/>
<link rel="author" title="關於這些文件" href="../about.html" />
<link rel="index" title="索引" href="../genindex.html" />
<link rel="search" title="搜尋" href="../search.html" />
<link rel="copyright" title="版權所有" href="../copyright.html" />
<link rel="next" title="6. 運算式" href="expressions.html" />
<link rel="prev" title="4. 執行模型" href="executionmodel.html" />
<link rel="canonical" href="https://docs.python.org/3/reference/import.html">
<style>
@media only screen {
table.full-width-table {
width: 100%;
}
}
</style>
<link rel="stylesheet" href="../_static/pydoctheme_dark.css" media="(prefers-color-scheme: dark)" id="pydoctheme_dark_css">
<link rel="shortcut icon" type="image/png" href="../_static/py.svg">
<script type="text/javascript" src="../_static/copybutton.js"></script>
<script type="text/javascript" src="../_static/menu.js"></script>
<script type="text/javascript" src="../_static/search-focus.js"></script>
<script type="text/javascript" src="../_static/themetoggle.js"></script>
<script type="text/javascript" src="../_static/rtd_switcher.js"></script>
<meta name="readthedocs-addons-api-version" content="1">
</head>
<body>
<div class="mobile-nav">
<input type="checkbox" id="menuToggler" class="toggler__input" aria-controls="navigation"
aria-pressed="false" aria-expanded="false" role="button" aria-label="選單">
<nav class="nav-content" role="navigation">
<label for="menuToggler" class="toggler__label">
<span></span>
</label>
<span class="nav-items-wrapper">
<a href="https://www.python.org/" class="nav-logo">
<img src="../_static/py.svg" alt="Python logo">
</a>
<span class="version_switcher_placeholder"></span>
<form role="search" class="search" action="../search.html" method="get">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" class="search-icon">
<path fill-rule="nonzero" fill="currentColor" d="M15.5 14h-.79l-.28-.27a6.5 6.5 0 001.48-5.34c-.47-2.78-2.79-5-5.59-5.34a6.505 6.505 0 00-7.27 7.27c.34 2.8 2.56 5.12 5.34 5.59a6.5 6.5 0 005.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path>
</svg>
<input placeholder="快速搜索" aria-label="快速搜索" type="search" name="q">
<input type="submit" value="前往">
</form>
</span>
</nav>
<div class="menu-wrapper">
<nav class="menu" role="navigation" aria-label="main navigation">
<div class="language_switcher_placeholder"></div>
<label class="theme-selector-label">
主題
<select class="theme-selector" oninput="activateTheme(this.value)">
<option value="auto" selected>自動</option>
<option value="light">淺色模式</option>
<option value="dark">深色模式</option>
</select>
</label>
<div>
<h3><a href="../contents.html">目錄</a></h3>
<ul>
<li><a class="reference internal" href="#">5. 模組引入系統</a><ul>
<li><a class="reference internal" href="#importlib">5.1. <code class="xref py py-mod docutils literal notranslate"><span class="pre">importlib</span></code></a></li>
<li><a class="reference internal" href="#packages">5.2. 套件</a><ul>
<li><a class="reference internal" href="#regular-packages">5.2.1. 一般套件</a></li>
<li><a class="reference internal" href="#namespace-packages">5.2.2. 命名空間套件</a></li>
</ul>
</li>
<li><a class="reference internal" href="#searching">5.3. 搜尋</a><ul>
<li><a class="reference internal" href="#the-module-cache">5.3.1. 模組快取</a></li>
<li><a class="reference internal" href="#finders-and-loaders">5.3.2. 尋檢器 (Finder) 與載入器 (Loader)</a></li>
<li><a class="reference internal" href="#import-hooks">5.3.3. 引入掛鉤 (Import hooks)</a></li>
<li><a class="reference internal" href="#the-meta-path">5.3.4. 元路徑</a></li>
</ul>
</li>
<li><a class="reference internal" href="#loading">5.4. 載入</a><ul>
<li><a class="reference internal" href="#loaders">5.4.1. 載入器</a></li>
<li><a class="reference internal" href="#submodules">5.4.2. 子模組</a></li>
<li><a class="reference internal" href="#module-specs">5.4.3. 模組規格</a></li>
<li><a class="reference internal" href="#path-attributes-on-modules">5.4.4. 模組上的 __path__ 屬性</a></li>
<li><a class="reference internal" href="#module-reprs">5.4.5. 模組的 reprs</a></li>
<li><a class="reference internal" href="#cached-bytecode-invalidation">5.4.6. 被快取的位元組碼的無效化</a></li>
</ul>
</li>
<li><a class="reference internal" href="#the-path-based-finder">5.5. 基於路徑的尋檢器</a><ul>
<li><a class="reference internal" href="#path-entry-finders">5.5.1. 路徑條目尋檢器</a></li>
<li><a class="reference internal" href="#path-entry-finder-protocol">5.5.2. 路徑條目尋檢器協定</a></li>
</ul>
</li>
<li><a class="reference internal" href="#replacing-the-standard-import-system">5.6. 取代標準引入系統</a></li>
<li><a class="reference internal" href="#package-relative-imports">5.7. 套件相對引入</a></li>
<li><a class="reference internal" href="#special-considerations-for-main">5.8. __main__ 的特殊考量</a><ul>
<li><a class="reference internal" href="#main-spec">5.8.1. __main__.__spec__</a></li>
</ul>
</li>
<li><a class="reference internal" href="#references">5.9. 參考資料</a></li>
</ul>
</li>
</ul>
</div>
<div>
<h4>上個主題</h4>
<p class="topless"><a href="executionmodel.html"
title="上一章"><span class="section-number">4. </span>執行模型</a></p>
</div>
<div>
<h4>下個主題</h4>
<p class="topless"><a href="expressions.html"
title="下一章"><span class="section-number">6. </span>運算式</a></p>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const title = document.querySelector('meta[property="og:title"]').content;
const elements = document.querySelectorAll('.improvepage');
const pageurl = window.location.href.split('?')[0];
elements.forEach(element => {
const url = new URL(element.href.split('?')[0].replace("-nojs", ""));
url.searchParams.set('pagetitle', title);
url.searchParams.set('pageurl', pageurl);
url.searchParams.set('pagesource', "reference/import.rst");
element.href = url.toString();
});
});
</script>
<div role="note" aria-label="source link">
<h3>此頁面</h3>
<ul class="this-page-menu">
<li><a href="../bugs.html">回報錯誤</a></li>
<li><a class="improvepage" href="../improve-page-nojs.html">改進此頁面</a></li>
<li>
<a href="https://github.com/python/cpython/blob/main/Doc/reference/import.rst?plain=1"
rel="nofollow">顯示原始碼
</a>
</li>
<li>
<a href="https://github.com/python/python-docs-zh-TW/blob/3.14/reference/import.po?plain=1"
rel="nofollow">顯示翻譯原始碼</a>
</li>
</ul>
</div>
</nav>
</div>
</div>
<div class="related" role="navigation" aria-label="Related">
<h3>導航</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="總索引"
accesskey="I">索引</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python 模組索引"
>模組</a> |</li>
<li class="right" >
<a href="expressions.html" title="6. 運算式"
accesskey="N">下一頁</a> |</li>
<li class="right" >
<a href="executionmodel.html" title="4. 執行模型"
accesskey="P">上一頁</a> |</li>
<li><img src="../_static/py.svg" alt="Python logo" style="vertical-align: middle; margin-top: -1px"></li>
<li><a href="https://www.python.org/">Python</a> »</li>
<li class="switchers">
<div class="language_switcher_placeholder"></div>
<div class="version_switcher_placeholder"></div>
</li>
<li>
</li>
<li id="cpython-language-and-version">
<a href="../index.html">3.14.7 Documentation</a> »
</li>
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python 語言參考手冊</a> »</li>
<li class="nav-item nav-item-this"><a href=""><span class="section-number">5. </span>模組引入系統</a></li>
<li class="right">
<div class="inline-search" role="search">
<form class="inline-search" action="../search.html" method="get">
<input placeholder="快速搜索" aria-label="快速搜索" type="search" name="q" id="search-box">
<input type="submit" value="前往">
</form>
</div>
|
</li>
<li class="right">
<label class="theme-selector-label">
主題
<select class="theme-selector" oninput="activateTheme(this.value)">
<option value="auto" selected>自動</option>
<option value="light">淺色模式</option>
<option value="dark">深色模式</option>
</select>
</label> |</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="the-import-system">
<span id="importsystem"></span><h1><span class="section-number">5. </span>模組引入系統<a class="headerlink" href="#the-import-system" title="連結到這個標頭">¶</a></h1>
<p id="index-0">一個 <a class="reference internal" href="../glossary.html#term-module"><span class="xref std std-term">module</span></a> 中的 Python 程式碼透過 <a class="reference internal" href="../glossary.html#term-importing"><span class="xref std std-term">importing</span></a> 的過程來存取另一個模組中的程式碼。<a class="reference internal" href="simple_stmts.html#import"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">import</span></code></a> 陳述式是叫用 (invoke) 引入機制最常見的方法,但這不是唯一的方法。函式如 <a class="reference internal" href="../library/importlib.html#importlib.import_module" title="importlib.import_module"><code class="xref py py-func docutils literal notranslate"><span class="pre">importlib.import_module()</span></code></a> 以及內建函式 <a class="reference internal" href="../library/functions.html#import__" title="__import__"><code class="xref py py-func docutils literal notranslate"><span class="pre">__import__()</span></code></a> 也可以用來叫用引入機制。</p>
<p><a class="reference internal" href="simple_stmts.html#import"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">import</span></code></a> 陳述式結合了兩個操作:首先搜尋指定的模組,然後將搜尋結果繫結到本地作用域中的一個名稱。<code class="xref std std-keyword docutils literal notranslate"><span class="pre">import</span></code> 陳述式的搜尋操作被定義為一個對 <a class="reference internal" href="../library/functions.html#import__" title="__import__"><code class="xref py py-func docutils literal notranslate"><span class="pre">__import__()</span></code></a> 函式的呼叫,並帶有相應的引數。<a class="reference internal" href="../library/functions.html#import__" title="__import__"><code class="xref py py-func docutils literal notranslate"><span class="pre">__import__()</span></code></a> 的回傳值用於執行 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">import</span></code> 陳述式的名稱繫結操作。有關名稱繫結操作的詳細資訊,請參見 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">import</span></code> 陳述式。</p>
<p>直接呼叫 <a class="reference internal" href="../library/functions.html#import__" title="__import__"><code class="xref py py-func docutils literal notranslate"><span class="pre">__import__()</span></code></a> 只會執行模組搜尋操作,以及在找到時執行模組的建立操作。雖然某些副作用可能會發生,例如引入父套件 (parent package),以及更新各種快取(包括 <a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a>),但只有 <a class="reference internal" href="simple_stmts.html#import"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">import</span></code></a> 陳述式會執行名稱繫結操作。</p>
<p>當執行 <a class="reference internal" href="simple_stmts.html#import"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">import</span></code></a> 陳述式時,會呼叫內建的 <a class="reference internal" href="../library/functions.html#import__" title="__import__"><code class="xref py py-func docutils literal notranslate"><span class="pre">__import__()</span></code></a> 函式。其他叫用引入系統的機制(如 <a class="reference internal" href="../library/importlib.html#importlib.import_module" title="importlib.import_module"><code class="xref py py-func docutils literal notranslate"><span class="pre">importlib.import_module()</span></code></a>)可以選擇略過 <a class="reference internal" href="../library/functions.html#import__" title="__import__"><code class="xref py py-func docutils literal notranslate"><span class="pre">__import__()</span></code></a>,並使用它們自己的解決方案來實作引入語意。</p>
<p>當模組首次被引入時,Python 會搜尋該模組,若找到則會建立一個模組物件 <a class="footnote-reference brackets" href="#fnmo" id="id1" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a>,並對其進行初始化。如果找不到指定的模組,則會引發 <a class="reference internal" href="../library/exceptions.html#ModuleNotFoundError" title="ModuleNotFoundError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ModuleNotFoundError</span></code></a>。當引入機制被叫用時,Python 會實作各種策略來搜尋指定的模組。這些策略可以透過使用以下章節描述的各種 hook(掛鉤)來修改和擴展。</p>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.3 版的變更: </span>引入系統已被更新,以完全實作 <span class="target" id="index-41"></span><a class="pep reference external" href="https://peps.python.org/pep-0302/"><strong>PEP 302</strong></a> 的第二階段。不再有隱式引入機制——完整的引入系統已透過 <a class="reference internal" href="../library/sys.html#sys.meta_path" title="sys.meta_path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.meta_path</span></code></a> 公開。此外,原生命名空間套件支援(請參閱 <span class="target" id="index-42"></span><a class="pep reference external" href="https://peps.python.org/pep-0420/"><strong>PEP 420</strong></a>)也已被實作。</p>
</div>
<section id="importlib">
<h2><span class="section-number">5.1. </span><a class="reference internal" href="../library/importlib.html#module-importlib" title="importlib: The implementation of the import machinery."><code class="xref py py-mod docutils literal notranslate"><span class="pre">importlib</span></code></a><a class="headerlink" href="#importlib" title="連結到這個標頭">¶</a></h2>
<p><a class="reference internal" href="../library/importlib.html#module-importlib" title="importlib: The implementation of the import machinery."><code class="xref py py-mod docutils literal notranslate"><span class="pre">importlib</span></code></a> 模組提供了豐富的 API 來與引入系統互動。例如,<a class="reference internal" href="../library/importlib.html#importlib.import_module" title="importlib.import_module"><code class="xref py py-func docutils literal notranslate"><span class="pre">importlib.import_module()</span></code></a> 提供了一個比內建的 <a class="reference internal" href="../library/functions.html#import__" title="__import__"><code class="xref py py-func docutils literal notranslate"><span class="pre">__import__()</span></code></a> 更推薦且更簡單的 API 來叫用引入機制。更多詳細資訊請參閱 <a class="reference internal" href="../library/importlib.html#module-importlib" title="importlib: The implementation of the import machinery."><code class="xref py py-mod docutils literal notranslate"><span class="pre">importlib</span></code></a> 函式庫文件。</p>
</section>
<section id="packages">
<h2><span class="section-number">5.2. </span>套件<a class="headerlink" href="#packages" title="連結到這個標頭">¶</a></h2>
<p id="index-3">Python 只有一種類型的模組物件,且所有模組,無論其是使用 Python、C 還是其他語言實作,都是這種類型。為了幫助組織模組並提供命名階層,Python 導入了<a class="reference internal" href="../glossary.html#term-package"><span class="xref std std-term">套件</span></a>的概念。</p>
<p>你可以將套件視為檔案系統中的目錄,模組則是目錄中的檔案,但不要過於字面地理解這個比喻,因為套件和模組不一定來自檔案系統。為了方便解釋,我們將使用這個目錄和檔案的比喻。就像檔案系統目錄一樣,套件是分層組織的,套件本身可以包含子套件以及一般模組。</p>
<p>請記住,所有的套件都是模組,但並非所有模組都是套件。換句話說,套件只是一種特殊的模組。具體來說,任何包含 <code class="docutils literal notranslate"><span class="pre">__path__</span></code> 屬性的模組都被視為套件。</p>
<p>所有模組都有一個名稱。子套件的名稱與其父套件名稱之間用一個點來分隔,類似於 Python 的標準屬性存取語法。因此,你可能會有一個名為 <a class="reference internal" href="../library/email.html#module-email" title="email: Package supporting the parsing, manipulating, and generating email messages."><code class="xref py py-mod docutils literal notranslate"><span class="pre">email</span></code></a> 的套件,該套件又有一個名為 <a class="reference internal" href="../library/email.mime.html#module-email.mime" title="email.mime: Build MIME messages."><code class="xref py py-mod docutils literal notranslate"><span class="pre">email.mime</span></code></a> 的子套件,並且該子套件中有一個名為 <a class="reference internal" href="../library/email.mime.html#module-email.mime.text" title="email.mime.text"><code class="xref py py-mod docutils literal notranslate"><span class="pre">email.mime.text</span></code></a> 的模組。</p>
<section id="regular-packages">
<h3><span class="section-number">5.2.1. </span>一般套件<a class="headerlink" href="#regular-packages" title="連結到這個標頭">¶</a></h3>
<p id="index-4">Python 定義了兩種類型的套件,<a class="reference internal" href="../glossary.html#term-regular-package"><span class="xref std std-term">一般套件</span></a>和<a class="reference internal" href="../glossary.html#term-namespace-package"><span class="xref std std-term">命名空間套件</span></a>。一般套件是 Python 3.2 及更早版本中存在的傳統套件。一般套件通常實作成一個包含 <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> 檔案的目錄。當引入一般套件時,該 <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> 檔案會被隱式執行,其定義的物件會繫結到該套件的命名空間中的名稱。<code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> 檔案可以包含與任何其他模組相同的 Python 程式碼,並且 Python 會在引入時為該模組增加一些額外的屬性。</p>
<p>例如,以下檔案系統布置定義了一個頂層的 <code class="docutils literal notranslate"><span class="pre">parent</span></code> 套件,該套件包含三個子套件:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">parent</span><span class="o">/</span>
<span class="fm">__init__</span><span class="o">.</span><span class="n">py</span>
<span class="n">one</span><span class="o">/</span>
<span class="fm">__init__</span><span class="o">.</span><span class="n">py</span>
<span class="n">two</span><span class="o">/</span>
<span class="fm">__init__</span><span class="o">.</span><span class="n">py</span>
<span class="n">three</span><span class="o">/</span>
<span class="fm">__init__</span><span class="o">.</span><span class="n">py</span>
</pre></div>
</div>
<p>引入 <code class="docutils literal notranslate"><span class="pre">parent.one</span></code> 將隱式執行 <code class="docutils literal notranslate"><span class="pre">parent/__init__.py</span></code> 和 <code class="docutils literal notranslate"><span class="pre">parent/one/__init__.py</span></code>。隨後引入 <code class="docutils literal notranslate"><span class="pre">parent.two</span></code> 或 <code class="docutils literal notranslate"><span class="pre">parent.three</span></code> 將分別執行 <code class="docutils literal notranslate"><span class="pre">parent/two/__init__.py</span></code> 和 <code class="docutils literal notranslate"><span class="pre">parent/three/__init__.py</span></code>。</p>
<p>A subdirectory inside a regular package that does not contain an
<code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> file is treated as an implicit
<a class="reference internal" href="#reference-namespace-package"><span class="std std-ref">namespace package</span></a> (a "namespace
subpackage") rooted in that parent. See <span class="target" id="index-5"></span><a class="pep reference external" href="https://peps.python.org/pep-0420/"><strong>PEP 420</strong></a> for the underlying
specification.</p>
</section>
<section id="namespace-packages">
<span id="reference-namespace-package"></span><h3><span class="section-number">5.2.2. </span>命名空間套件<a class="headerlink" href="#namespace-packages" title="連結到這個標頭">¶</a></h3>
<p id="index-6">命名空間套件是由不同的<a class="reference internal" href="../glossary.html#term-portion"><span class="xref std std-term">部分</span></a> 組成的,每個部分都為父套件提供一個子套件。這些部分可以位於檔案系統上的不同位置。部分可能也存在於壓縮檔案中、網路上,或 Python 在引入時搜尋的任何其他地方。命名空間套件不一定直接對應於檔案系統中的物件;它們可能是沒有具體表示的虛擬模組。</p>
<p>命名空間套件的 <code class="docutils literal notranslate"><span class="pre">__path__</span></code> 屬性不使用普通的串列。它們使用自訂的可疊代型別,當父套件的路徑(或頂層套件的 <a class="reference internal" href="../library/sys.html#sys.path" title="sys.path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path</span></code></a>)發生變化時,會在下一次引入嘗試時自動執行新一輪的套件部分搜尋。</p>
<p>在命名空間套件中,不存在 <code class="docutils literal notranslate"><span class="pre">parent/__init__.py</span></code> 檔案。實際上,在引入搜尋過程中可能會找到多個 <code class="docutils literal notranslate"><span class="pre">parent</span></code> 目錄,每個目錄由不同的部分提供。因此,<code class="docutils literal notranslate"><span class="pre">parent/one</span></code> 可能與 <code class="docutils literal notranslate"><span class="pre">parent/two</span></code> 不會實際位於一起。在這種情況下,每當引入頂層 <code class="docutils literal notranslate"><span class="pre">parent</span></code> 套件或其子套件之一時,Python 會為頂層 <code class="docutils literal notranslate"><span class="pre">parent</span></code> 套件建立一個命名空間套件。</p>
<p>Namespace packages may also be nested inside a regular package. When the
import system searches a regular package's <code class="docutils literal notranslate"><span class="pre">__path__</span></code> and encounters a
subdirectory that does not contain an <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> file, that
subdirectory becomes a <a class="reference internal" href="../glossary.html#term-portion"><span class="xref std std-term">portion</span></a> contributing to a namespace
subpackage of the enclosing regular package.</p>
<p>有關命名空間套件的規格,請參見 <span class="target" id="index-43"></span><a class="pep reference external" href="https://peps.python.org/pep-0420/"><strong>PEP 420</strong></a>。</p>
</section>
</section>
<section id="searching">
<h2><span class="section-number">5.3. </span>搜尋<a class="headerlink" href="#searching" title="連結到這個標頭">¶</a></h2>
<p>在開始搜尋之前,Python 需要被引入模組(或套件,但在本討論中,兩者的區別無關緊要)的完整<a class="reference internal" href="../glossary.html#term-qualified-name"><span class="xref std std-term">限定名稱 (qualified name)</span></a>。此名稱可能來自 <a class="reference internal" href="simple_stmts.html#import"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">import</span></code></a> 陳述式的各種引數,或來自 <a class="reference internal" href="../library/importlib.html#importlib.import_module" title="importlib.import_module"><code class="xref py py-func docutils literal notranslate"><span class="pre">importlib.import_module()</span></code></a> 或 <a class="reference internal" href="../library/functions.html#import__" title="__import__"><code class="xref py py-func docutils literal notranslate"><span class="pre">__import__()</span></code></a> 函式的參數。</p>
<p>此名稱將在引入搜尋的各個階段中使用,並且它可能是指向子模組的點分隔路徑,例如 <code class="docutils literal notranslate"><span class="pre">foo.bar.baz</span></code>。在這種情況下,Python 會首先嘗試引入 <code class="docutils literal notranslate"><span class="pre">foo</span></code>,然後是 <code class="docutils literal notranslate"><span class="pre">foo.bar</span></code>,最後是 <code class="docutils literal notranslate"><span class="pre">foo.bar.baz</span></code>。如果任何中間引入失敗,則會引發 <a class="reference internal" href="../library/exceptions.html#ModuleNotFoundError" title="ModuleNotFoundError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ModuleNotFoundError</span></code></a>。</p>
<section id="the-module-cache">
<h3><span class="section-number">5.3.1. </span>模組快取<a class="headerlink" href="#the-module-cache" title="連結到這個標頭">¶</a></h3>
<p id="index-8">在引入搜尋過程中首先檢查的地方是 <a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a>。此對映用作所有先前引入過的模組的快取,包括中間路徑。因此,如果 <code class="docutils literal notranslate"><span class="pre">foo.bar.baz</span></code> 之前已被引入,<a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a> 將包含 <code class="docutils literal notranslate"><span class="pre">foo</span></code>、<code class="docutils literal notranslate"><span class="pre">foo.bar</span></code> 和 <code class="docutils literal notranslate"><span class="pre">foo.bar.baz</span></code> 的條目。每個鍵的值都是相應的模組物件。</p>
<p>在引入過程中,會在 <a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a> 中查找模組名稱,如果存在,則相關的值為滿足此引入的模組,此引入過程即完成。然而,如果值是 <code class="docutils literal notranslate"><span class="pre">None</span></code>,則會引發 <a class="reference internal" href="../library/exceptions.html#ModuleNotFoundError" title="ModuleNotFoundError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ModuleNotFoundError</span></code></a>。如果模組名稱不存在,Python 會繼續搜尋該模組。</p>
<p><a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a> 是可寫入的。刪除一個鍵可能不會銷毀相關聯的模組(因為其他模組可能持有對它的參照),但會使指定的模組的快取條目失效,導致 Python 在下一次引入該模組時重新搜尋。也可以將鍵賦值為 <code class="docutils literal notranslate"><span class="pre">None</span></code>,這會強制下一次引入該模組時引發 <a class="reference internal" href="../library/exceptions.html#ModuleNotFoundError" title="ModuleNotFoundError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ModuleNotFoundError</span></code></a>。</p>
<p>但請注意,如果你保留了對模組物件的參照,並在 <a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a> 中使其快取條目失效,然後重新引入指定的模組,這兩個模組物件將<em>不會</em>相同。相比之下,<a class="reference internal" href="../library/importlib.html#importlib.reload" title="importlib.reload"><code class="xref py py-func docutils literal notranslate"><span class="pre">importlib.reload()</span></code></a> 會重用<em>相同的</em>模組物件,並透過重新執行模組的程式碼來簡單地重新初始化模組內容。</p>
</section>
<section id="finders-and-loaders">
<span id="id2"></span><h3><span class="section-number">5.3.2. </span>尋檢器 (Finder) 與載入器 (Loader)<a class="headerlink" href="#finders-and-loaders" title="連結到這個標頭">¶</a></h3>
<p id="index-9">如果在 <a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a> 中找不到指定的模組,則會叫用 Python 的引入協定來尋找並載入該模組。這個協定由兩個概念性物件組成,<a class="reference internal" href="../glossary.html#term-finder"><span class="xref std std-term">尋檢器</span></a> 和<a class="reference internal" href="../glossary.html#term-loader"><span class="xref std std-term">載入器</span></a>。尋檢器的任務是使用其已知的策略來確定是否能找到命名模組。實作這兩個介面的物件稱為<a class="reference internal" href="../glossary.html#term-importer"><span class="xref std std-term">引入器 (importer)</span></a> ——當它們發現可以載入所請求的模組時,會回傳它們自己。</p>
<p>Python 包含多個預設的尋檢器和引入器。第一個尋檢器知道如何定位內建模組,第二個尋檢器知道如何定位凍結模組。第三個預設尋檢器會在 <a class="reference internal" href="../glossary.html#term-import-path"><span class="xref std std-term">import path</span></a> 中搜尋模組。<a class="reference internal" href="../glossary.html#term-import-path"><span class="xref std std-term">import path</span></a> 是一個位置的列表,這些位置可能是檔案系統路徑或壓縮檔案,也可以擴充以搜尋任何可定位的資源,例如由 URL 識別的資源。</p>
<p>引入機制是可擴充的,因此可以增加新的尋檢器來擴充模組搜尋的範圍和作用域。</p>
<p>尋檢器實際上不會載入模組。如果它們能找到指定的模組,它們會回傳一個<em class="dfn">模組規格</em>,這是一個模組的引入相關資訊的封裝,引入機制會在載入模組時使用這些資訊。</p>
<p>以下各節將更詳細地描述尋檢器和載入器的協定,包括如何建立和註冊新的尋檢器和載入器來擴充引入機制。</p>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.4 版的變更: </span>Python 在之前的版本中,尋檢器會直接回傳<a class="reference internal" href="../glossary.html#term-loader"><span class="xref std std-term">載入器</span></a>,而現在它們回傳的是<em>包含</em>載入器的模組規格。載入器仍在引入過程中使用,但其責任減少了。</p>
</div>
</section>
<section id="import-hooks">
<h3><span class="section-number">5.3.3. </span>引入掛鉤 (Import hooks)<a class="headerlink" href="#import-hooks" title="連結到這個標頭">¶</a></h3>
<p id="index-10">引入機制的設計是可擴充的;其主要機制是<em>引入掛鉤</em>。引入掛鉤有兩種類型:<em>元掛鉤 (meta hooks)</em> 和<em>引入路徑掛鉤</em>。</p>
<p>元掛鉤會在引入處理的開始階段被呼叫,除了查找 <a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a> 快取外,其他引入處理還未發生時就會呼叫。這允許元掛鉤覆蓋 <a class="reference internal" href="../library/sys.html#sys.path" title="sys.path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path</span></code></a> 的處理、凍結模組,甚至是內建模組。元掛鉤透過將新的尋檢器物件新增到 <a class="reference internal" href="../library/sys.html#sys.meta_path" title="sys.meta_path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.meta_path</span></code></a> 中來註冊,具體描述請參閱以下段落。</p>
<p>引入路徑掛鉤被視為 <a class="reference internal" href="../library/sys.html#sys.path" title="sys.path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path</span></code></a>(或 <code class="docutils literal notranslate"><span class="pre">package.__path__</span></code>)處理過程的一部分來呼叫,當遇到與其相關聯的路徑項目時就會被觸發。引入路徑掛鉤透過將新的可呼叫物件增加到 <a class="reference internal" href="../library/sys.html#sys.path_hooks" title="sys.path_hooks"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path_hooks</span></code></a> 中來註冊,具體描述請參閱以下段落。</p>
</section>
<section id="the-meta-path">
<h3><span class="section-number">5.3.4. </span>元路徑<a class="headerlink" href="#the-meta-path" title="連結到這個標頭">¶</a></h3>
<p id="index-11">當在 <a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a> 中找不到命名模組時,Python 接下來會搜尋 <a class="reference internal" href="../library/sys.html#sys.meta_path" title="sys.meta_path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.meta_path</span></code></a>,其中包含一個元路徑尋檢器物件串列。這些尋檢器會依次被查詢,看它們是否知道如何處理命名模組。元路徑尋檢器必須實作一個名為 <a class="reference internal" href="../library/importlib.html#importlib.abc.MetaPathFinder.find_spec" title="importlib.abc.MetaPathFinder.find_spec"><code class="xref py py-meth docutils literal notranslate"><span class="pre">find_spec()</span></code></a> 的方法,該方法接收三個引數:名稱、引入路徑和(可選的)目標模組。元路徑尋檢器可以使用任何策略來確定它是否能處理命名模組。</p>
<p>如果元路徑尋檢器知道如何處理命名模組,它會回傳一個規格物件。如果它無法處理命名模組,則回傳 <code class="docutils literal notranslate"><span class="pre">None</span></code>。如果 <a class="reference internal" href="../library/sys.html#sys.meta_path" title="sys.meta_path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.meta_path</span></code></a> 的處理到達串列的末尾仍未回傳規格,則會引發 <a class="reference internal" href="../library/exceptions.html#ModuleNotFoundError" title="ModuleNotFoundError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ModuleNotFoundError</span></code></a>。任何其他引發的例外將直接向上傳播,並中止引入過程。</p>
<p>元路徑尋檢器的 <a class="reference internal" href="../library/importlib.html#importlib.abc.MetaPathFinder.find_spec" title="importlib.abc.MetaPathFinder.find_spec"><code class="xref py py-meth docutils literal notranslate"><span class="pre">find_spec()</span></code></a> 方法會以兩個或三個引數來呼叫。第一個是被引入模組的完全限定名稱,例如 <code class="docutils literal notranslate"><span class="pre">foo.bar.baz</span></code>。第二個引數是用於模組搜尋的路徑條目。對於頂層模組,第二個引數是 <code class="docutils literal notranslate"><span class="pre">None</span></code>,但對於子模組或子套件,第二個引數是父套件的 <code class="docutils literal notranslate"><span class="pre">__path__</span></code> 屬性的值。如果無法存取相應的 <code class="docutils literal notranslate"><span class="pre">__path__</span></code> 屬性,將引發 <a class="reference internal" href="../library/exceptions.html#ModuleNotFoundError" title="ModuleNotFoundError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ModuleNotFoundError</span></code></a>。第三個引數是一個現有的模組物件,該物件將成為後續載入的目標。引入系統只會在重新載入時傳入目標模組。</p>
<p>對於一個引入請求,元路徑可能會被遍歷多次。例如,假設參與的模組都沒有被快取,則引入 <code class="docutils literal notranslate"><span class="pre">foo.bar.baz</span></code> 將首先執行頂層引入,對每個元路徑尋檢器(<code class="docutils literal notranslate"><span class="pre">mpf</span></code>)呼叫 <code class="docutils literal notranslate"><span class="pre">mpf.find_spec("foo",</span> <span class="pre">None,</span> <span class="pre">None)</span></code>。當 <code class="docutils literal notranslate"><span class="pre">foo</span></code> 被引入後,將再次藉由遍歷元路徑引入 <code class="docutils literal notranslate"><span class="pre">foo.bar</span></code>,並呼叫 <code class="docutils literal notranslate"><span class="pre">mpf.find_spec("foo.bar",</span> <span class="pre">foo.__path__,</span> <span class="pre">None)</span></code>。當 <code class="docutils literal notranslate"><span class="pre">foo.bar</span></code> 被引入後,最後一次遍歷會呼叫 <code class="docutils literal notranslate"><span class="pre">mpf.find_spec("foo.bar.baz",</span> <span class="pre">foo.bar.__path__,</span> <span class="pre">None)</span></code>。</p>
<p>一些元路徑尋檢器僅支援頂層引入。當第二個引數傳入 <code class="docutils literal notranslate"><span class="pre">None</span></code> 以外的值時,這些引入器將始終回傳 <code class="docutils literal notranslate"><span class="pre">None</span></code>。</p>
<p>Python 的預設 <a class="reference internal" href="../library/sys.html#sys.meta_path" title="sys.meta_path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.meta_path</span></code></a> 有三個元路徑尋檢器,一個知道如何引入內建模組,一個知道如何引入凍結模組,還有一個知道如何從 <a class="reference internal" href="../glossary.html#term-import-path"><span class="xref std std-term">import path</span></a> 引入模組(即 <a class="reference internal" href="../glossary.html#term-path-based-finder"><span class="xref std std-term">path based finder</span></a>)。</p>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.4 版的變更: </span>元路徑尋檢器的 <a class="reference internal" href="../library/importlib.html#importlib.abc.MetaPathFinder.find_spec" title="importlib.abc.MetaPathFinder.find_spec"><code class="xref py py-meth docutils literal notranslate"><span class="pre">find_spec()</span></code></a> 方法取代了 <code class="xref py py-meth docutils literal notranslate"><span class="pre">find_module()</span></code>,後者現在已被棄用。雖然它將繼續正常工作,但引入機制僅在尋檢器未實作 <a class="reference internal" href="../library/importlib.html#importlib.abc.MetaPathFinder.find_spec" title="importlib.abc.MetaPathFinder.find_spec"><code class="xref py py-meth docutils literal notranslate"><span class="pre">find_spec()</span></code></a> 時才會嘗試使用它。</p>
</div>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.10 版的變更: </span>引入系統現在使用 <code class="xref py py-meth docutils literal notranslate"><span class="pre">find_module()</span></code> 時將引發 <a class="reference internal" href="../library/exceptions.html#ImportWarning" title="ImportWarning"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ImportWarning</span></code></a>。</p>
</div>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.12 版的變更: </span><code class="xref py py-meth docutils literal notranslate"><span class="pre">find_module()</span></code> 已被移除。請改用 <a class="reference internal" href="../library/importlib.html#importlib.abc.MetaPathFinder.find_spec" title="importlib.abc.MetaPathFinder.find_spec"><code class="xref py py-meth docutils literal notranslate"><span class="pre">find_spec()</span></code></a>。</p>
</div>
</section>
</section>
<section id="loading">
<h2><span class="section-number">5.4. </span>載入<a class="headerlink" href="#loading" title="連結到這個標頭">¶</a></h2>
<p>如果找到模組規格,引入機制會在載入模組時使用該規格(以及它包含的載入器)。以下是引入過程中載入部分的大致情況:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">module</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">if</span> <span class="n">spec</span><span class="o">.</span><span class="n">loader</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">spec</span><span class="o">.</span><span class="n">loader</span><span class="p">,</span> <span class="s1">'create_module'</span><span class="p">):</span>
<span class="c1"># 這裡假設載入器上也會定義 'exec_module'</span>
<span class="n">module</span> <span class="o">=</span> <span class="n">spec</span><span class="o">.</span><span class="n">loader</span><span class="o">.</span><span class="n">create_module</span><span class="p">(</span><span class="n">spec</span><span class="p">)</span>
<span class="k">if</span> <span class="n">module</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">module</span> <span class="o">=</span> <span class="n">ModuleType</span><span class="p">(</span><span class="n">spec</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
<span class="c1"># 與引入相關的模組屬性會在此處設定:</span>
<span class="n">_init_module_attrs</span><span class="p">(</span><span class="n">spec</span><span class="p">,</span> <span class="n">module</span><span class="p">)</span>
<span class="k">if</span> <span class="n">spec</span><span class="o">.</span><span class="n">loader</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="c1"># 不支援</span>
<span class="k">raise</span> <span class="ne">ImportError</span>
<span class="k">if</span> <span class="n">spec</span><span class="o">.</span><span class="n">origin</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">spec</span><span class="o">.</span><span class="n">submodule_search_locations</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="c1"># 命名空間套件</span>
<span class="n">sys</span><span class="o">.</span><span class="n">modules</span><span class="p">[</span><span class="n">spec</span><span class="o">.</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">module</span>
<span class="k">elif</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">spec</span><span class="o">.</span><span class="n">loader</span><span class="p">,</span> <span class="s1">'exec_module'</span><span class="p">):</span>
<span class="n">module</span> <span class="o">=</span> <span class="n">spec</span><span class="o">.</span><span class="n">loader</span><span class="o">.</span><span class="n">load_module</span><span class="p">(</span><span class="n">spec</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">sys</span><span class="o">.</span><span class="n">modules</span><span class="p">[</span><span class="n">spec</span><span class="o">.</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">module</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">spec</span><span class="o">.</span><span class="n">loader</span><span class="o">.</span><span class="n">exec_module</span><span class="p">(</span><span class="n">module</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">BaseException</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">del</span> <span class="n">sys</span><span class="o">.</span><span class="n">modules</span><span class="p">[</span><span class="n">spec</span><span class="o">.</span><span class="n">name</span><span class="p">]</span>
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
<span class="k">pass</span>
<span class="k">raise</span>
<span class="k">return</span> <span class="n">sys</span><span class="o">.</span><span class="n">modules</span><span class="p">[</span><span class="n">spec</span><span class="o">.</span><span class="n">name</span><span class="p">]</span>
</pre></div>
</div>
<p>請注意下列細節:</p>
<ul class="simple">
<li><p>如果 <a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a> 中已存在具有給定名稱的模組物件,引入會已回傳該物件。</p></li>
<li><p>在載入器執行模組程式碼之前,模組將已存在於 <a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a> 中。這一點至關重要,因為模組程式碼可能會(直接或間接)引入自己;事先將其增加到 <a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a> 可以預防類似無限遞迴以及多次重複載入等情形。</p></li>
<li><p>如果載入失敗,只有載入失敗的模組會從 <a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a> 中刪除。任何已存在於 <a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a> 快取中的模組,以及任何在載入失敗前成功載入的模組,都必須保留在快取中。此情形與重新載入不同,在重新載入時,即使載入失敗的模組也會保留在 <a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a> 中。</p></li>
<li><p>模組建立後、在執行之前,引入機制會設定與引入相關的模組屬性(在上面的偽程式碼範例中為 "_init_module_attrs"),具體內容在<a class="reference internal" href="datamodel.html#import-mod-attrs"><span class="std std-ref">之後的段落</span></a>會總結。</p></li>
<li><p>模組執行是載入過程中的關鍵時刻,此時模組的命名空間會被新增名稱。執行過程完全交由載入器處理,由其決定如何新增以及新增什麼。</p></li>
<li><p>在載入過程中建立並傳遞給 exec_module() 的模組,可能不會是引入結束時回傳的模組 <a class="footnote-reference brackets" href="#fnlo" id="id3" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a>。</p></li>
</ul>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.4 版的變更: </span>引入系統已接管載入器的模板 (boilerplate) 責任。之前是由 <a class="reference internal" href="../library/importlib.html#importlib.abc.Loader.load_module" title="importlib.abc.Loader.load_module"><code class="xref py py-meth docutils literal notranslate"><span class="pre">importlib.abc.Loader.load_module()</span></code></a> 方法執行的。</p>
</div>
<section id="loaders">
<h3><span class="section-number">5.4.1. </span>載入器<a class="headerlink" href="#loaders" title="連結到這個標頭">¶</a></h3>
<p>模組載入器提供了載入的關鍵功能:模組執行。引入機制會以單一引數(即要執行的模組物件)呼叫 <a class="reference internal" href="../library/importlib.html#importlib.abc.Loader.exec_module" title="importlib.abc.Loader.exec_module"><code class="xref py py-meth docutils literal notranslate"><span class="pre">importlib.abc.Loader.exec_module()</span></code></a> 方法。任何從 <a class="reference internal" href="../library/importlib.html#importlib.abc.Loader.exec_module" title="importlib.abc.Loader.exec_module"><code class="xref py py-meth docutils literal notranslate"><span class="pre">exec_module()</span></code></a> 回傳的值都會被忽略。</p>
<p>載入器必須滿足以下要求:</p>
<ul class="simple">
<li><p>如果模組是 Python 模組(而非內建模組或動態載入的擴充),載入器應在模組的全域命名空間 (<code class="docutils literal notranslate"><span class="pre">module.__dict__</span></code>) 中執行該模組的程式碼。</p></li>
<li><p>如果載入器無法執行該模組,應引發 <a class="reference internal" href="../library/exceptions.html#ImportError" title="ImportError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ImportError</span></code></a>。不過,在 <a class="reference internal" href="../library/importlib.html#importlib.abc.Loader.exec_module" title="importlib.abc.Loader.exec_module"><code class="xref py py-meth docutils literal notranslate"><span class="pre">exec_module()</span></code></a> 中引發的任何其他例外也會被傳播。</p></li>
</ul>
<p>在許多情況下,尋檢器和載入器可以是同一個物件;在這種情況下,<a class="reference internal" href="../library/importlib.html#importlib.abc.MetaPathFinder.find_spec" title="importlib.abc.MetaPathFinder.find_spec"><code class="xref py py-meth docutils literal notranslate"><span class="pre">find_spec()</span></code></a> 方法只需回傳一個載入器設為 <code class="docutils literal notranslate"><span class="pre">self</span></code> 的規格即可。</p>
<p>模組載入器可以選擇透過實作 <a class="reference internal" href="../library/importlib.html#importlib.abc.Loader.create_module" title="importlib.abc.Loader.create_module"><code class="xref py py-meth docutils literal notranslate"><span class="pre">create_module()</span></code></a> 方法,在載入過程中建立模組物件。該方法接受一個引數,即模組規格,並回傳在載入過程中要使用的新的模組物件。<code class="docutils literal notranslate"><span class="pre">create_module()</span></code> 不需要在模組物件上設定任何屬性。如果該方法回傳 <code class="docutils literal notranslate"><span class="pre">None</span></code>,引入機制將自行建立新的模組。</p>
<div class="versionadded">
<p><span class="versionmodified added">在 3.4 版被加入: </span>載入器的 <a class="reference internal" href="../library/importlib.html#importlib.abc.Loader.create_module" title="importlib.abc.Loader.create_module"><code class="xref py py-meth docutils literal notranslate"><span class="pre">create_module()</span></code></a> 方法。</p>
</div>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.4 版的變更: </span><a class="reference internal" href="../library/importlib.html#importlib.abc.Loader.load_module" title="importlib.abc.Loader.load_module"><code class="xref py py-meth docutils literal notranslate"><span class="pre">load_module()</span></code></a> 方法已被 <a class="reference internal" href="../library/importlib.html#importlib.abc.Loader.exec_module" title="importlib.abc.Loader.exec_module"><code class="xref py py-meth docutils literal notranslate"><span class="pre">exec_module()</span></code></a> 取代,引入機制已承擔所有載入的模板責任。</p>
<p>為了與現有的載入器相容,引入機制會在載入器未實作 <code class="docutils literal notranslate"><span class="pre">exec_module()</span></code> 且存在 <code class="docutils literal notranslate"><span class="pre">load_module()</span></code> 方法時使用該方法。然而,<code class="docutils literal notranslate"><span class="pre">load_module()</span></code> 已被棄用,載入器應改為實作 <code class="docutils literal notranslate"><span class="pre">exec_module()</span></code>。</p>
<p><code class="docutils literal notranslate"><span class="pre">load_module()</span></code> 方法除了執行模組外,還必須實作上述全部的模板載入功能。所有相同的限制依然適用,並且還有一些額外的說明:</p>
<ul class="simple">
<li><p>如果 <a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a> 中已存在具有給定名稱的模組物件,載入器必須使用該模組(否則 <a class="reference internal" href="../library/importlib.html#importlib.reload" title="importlib.reload"><code class="xref py py-func docutils literal notranslate"><span class="pre">importlib.reload()</span></code></a> 將無法正常運作)。如果命名模組不存在於 <a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a> 中,載入器必須建立一個新的模組物件並將其新增至 <a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a>。</p></li>
<li><p>在載入器執行模組程式碼之前,該模組<em>必須</em>已存在於 <a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a> 中,以防止無限遞迴或多次載入。</p></li>
<li><p>如果載入失敗,載入器必須移除已經插入到 <a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a> 中的任何模組,但<strong>只能</strong>移除失敗的模組(們),且僅在載入器本身明確載入這些模組時才需移除。</p></li>
</ul>
</div>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.5 版的變更: </span>當 <code class="docutils literal notranslate"><span class="pre">exec_module()</span></code> 已定義但未定義 <code class="docutils literal notranslate"><span class="pre">create_module()</span></code> 時,將引發 <a class="reference internal" href="../library/exceptions.html#DeprecationWarning" title="DeprecationWarning"><code class="xref py py-exc docutils literal notranslate"><span class="pre">DeprecationWarning</span></code></a>。</p>
</div>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.6 版的變更: </span>當 <code class="docutils literal notranslate"><span class="pre">exec_module()</span></code> 已定義但未定義 <code class="docutils literal notranslate"><span class="pre">create_module()</span></code> 時,將引發 <a class="reference internal" href="../library/exceptions.html#ImportError" title="ImportError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ImportError</span></code></a>。</p>
</div>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.10 版的變更: </span>使用 <code class="docutils literal notranslate"><span class="pre">load_module()</span></code> 將引發 <a class="reference internal" href="../library/exceptions.html#ImportWarning" title="ImportWarning"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ImportWarning</span></code></a>。</p>
</div>
</section>
<section id="submodules">
<h3><span class="section-number">5.4.2. </span>子模組<a class="headerlink" href="#submodules" title="連結到這個標頭">¶</a></h3>
<p>當使用任何機制(例如 <code class="docutils literal notranslate"><span class="pre">importlib</span></code> APIs、<code class="docutils literal notranslate"><span class="pre">import</span></code> 或 <code class="docutils literal notranslate"><span class="pre">import-from</span></code> 陳述式,或內建的 <code class="docutils literal notranslate"><span class="pre">__import__()</span></code>)載入子模組時,會將子模組物件繫結到父模組的命名空間中。例如,如果套件 <code class="docutils literal notranslate"><span class="pre">spam</span></code> 有一個子模組 <code class="docutils literal notranslate"><span class="pre">foo</span></code>,則在引入 <code class="docutils literal notranslate"><span class="pre">spam.foo</span></code> 之後,<code class="docutils literal notranslate"><span class="pre">spam</span></code> 將擁有一個名為 <code class="docutils literal notranslate"><span class="pre">foo</span></code> 的屬性,該屬性繫結到子模組。我們假設你有以下的目錄結構:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">spam</span><span class="o">/</span>
<span class="fm">__init__</span><span class="o">.</span><span class="n">py</span>
<span class="n">foo</span><span class="o">.</span><span class="n">py</span>
</pre></div>
</div>
<p>並且 <code class="docutils literal notranslate"><span class="pre">spam/__init__.py</span></code> 中包含以下程式碼:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">.foo</span><span class="w"> </span><span class="kn">import</span> <span class="n">Foo</span>
</pre></div>
</div>
<p>那麼執行以下程式碼會將 <code class="docutils literal notranslate"><span class="pre">foo</span></code> 和 <code class="docutils literal notranslate"><span class="pre">Foo</span></code> 的名稱繫結到 <code class="docutils literal notranslate"><span class="pre">spam</span></code> 模組中:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">import</span><span class="w"> </span><span class="nn">spam</span>
<span class="gp">>>> </span><span class="n">spam</span><span class="o">.</span><span class="n">foo</span>
<span class="go"><module 'spam.foo' from '/tmp/imports/spam/foo.py'></span>
<span class="gp">>>> </span><span class="n">spam</span><span class="o">.</span><span class="n">Foo</span>
<span class="go"><class 'spam.foo.Foo'></span>
</pre></div>
</div>
<p>鑑於 Python 相似的名稱繫結規則,這可能看起來有些出人意料,但這實際上是引入系統的一個基本特性。不變的是如果你擁有 <code class="docutils literal notranslate"><span class="pre">sys.modules['spam']</span></code> 和 <code class="docutils literal notranslate"><span class="pre">sys.modules['spam.foo']</span></code>(就像上述引入後那樣),那麼後者必須作為前者的 <code class="docutils literal notranslate"><span class="pre">foo</span></code> 屬性出現。</p>
</section>
<section id="module-specs">
<span id="id4"></span><h3><span class="section-number">5.4.3. </span>模組規格<a class="headerlink" href="#module-specs" title="連結到這個標頭">¶</a></h3>
<p>引入機制在引入過程中使用有關每個模組的各種資訊,尤其是在載入之前。大多數資訊對所有模組來說都是通用的。模組規格的目的是以每個模組為基礎封裝這些與引入相關的資訊。</p>
<p>在引入過程中使用規格允許在引入系統的各個組件之間傳遞狀態,例如在建立模組規格的尋檢器和執行該規格的載入器之間傳遞。最重要的是,這允許引入機制執行載入的模板操作,而在沒有模組規格的情況下,這些操作則是載入器的責任。</p>
<p>模組的規格以 <a class="reference internal" href="datamodel.html#module.__spec__" title="module.__spec__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">module.__spec__</span></code></a> 的形式公開。適當地設定 <code class="xref py py-attr docutils literal notranslate"><span class="pre">__spec__</span></code> 同樣適用於<a class="reference internal" href="toplevel_components.html#programs"><span class="std std-ref">在直譯器啟動期間初始化的模組</span></a>。唯一的例外是 <code class="docutils literal notranslate"><span class="pre">__main__</span></code>,其中 <code class="xref py py-attr docutils literal notranslate"><span class="pre">__spec__</span></code> 會<a class="reference internal" href="#main-spec"><span class="std std-ref">在某些情況下被設定成 None</span></a>。</p>
<p>有關模組規格內容的詳細資訊,請參閱 <a class="reference internal" href="../library/importlib.html#importlib.machinery.ModuleSpec" title="importlib.machinery.ModuleSpec"><code class="xref py py-class docutils literal notranslate"><span class="pre">ModuleSpec</span></code></a>。</p>
<div class="versionadded">
<p><span class="versionmodified added">在 3.4 版被加入.</span></p>
</div>
</section>
<section id="path-attributes-on-modules">
<span id="package-path-rules"></span><h3><span class="section-number">5.4.4. </span>模組上的 __path__ 屬性<a class="headerlink" href="#path-attributes-on-modules" title="連結到這個標頭">¶</a></h3>
<p><a class="reference internal" href="datamodel.html#module.__path__" title="module.__path__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__path__</span></code></a> 屬性應該是一個(可能為空的)<a class="reference internal" href="../glossary.html#term-sequence"><span class="xref std std-term">sequence</span></a>,其包含列舉套件子模組位置的字串。根據定義,如果一個模組有 <code class="xref py py-attr docutils literal notranslate"><span class="pre">__path__</span></code> 屬性,那麼它就是一個 <a class="reference internal" href="../glossary.html#term-package"><span class="xref std std-term">package</span></a>。</p>
<p>套件的 <a class="reference internal" href="datamodel.html#module.__path__" title="module.__path__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__path__</span></code></a> 屬性在引入其子套件時被使用。在引入機制中,其功能與 <a class="reference internal" href="../library/sys.html#sys.path" title="sys.path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path</span></code></a> 類似,即提供在引入期間搜尋模組的位置串列。然而,<code class="xref py py-attr docutils literal notranslate"><span class="pre">__path__</span></code> 通常比 <code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path</span></code> 更受限制。</p>
<p><a class="reference internal" href="../library/sys.html#sys.path" title="sys.path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path</span></code></a> 適用的規則同樣也適用於套件的 <code class="xref py py-attr docutils literal notranslate"><span class="pre">__path__</span></code>。 <a class="reference internal" href="../library/sys.html#sys.path_hooks" title="sys.path_hooks"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path_hooks</span></code></a> 會在遍歷套件的 <code class="xref py py-attr docutils literal notranslate"><span class="pre">__path__</span></code> 時被參考(於後文詳述)。</p>
<p>套件的 <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> 檔案可以設定或修改套件的 <a class="reference internal" href="datamodel.html#module.__path__" title="module.__path__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__path__</span></code></a> 屬性,這通常是 <span class="target" id="index-44"></span><a class="pep reference external" href="https://peps.python.org/pep-0420/"><strong>PEP 420</strong></a> 之前實作命名空間套件的方式。隨著 <span class="target" id="index-45"></span><a class="pep reference external" href="https://peps.python.org/pep-0420/"><strong>PEP 420</strong></a> 的採用,命名空間套件不再需要提供僅包含 <code class="xref py py-attr docutils literal notranslate"><span class="pre">__path__</span></code> 操作程式碼的 <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> 檔案;引入機制會自動為命名空間套件正確地設定 <code class="xref py py-attr docutils literal notranslate"><span class="pre">__path__</span></code>。</p>
</section>
<section id="module-reprs">
<h3><span class="section-number">5.4.5. </span>模組的 reprs<a class="headerlink" href="#module-reprs" title="連結到這個標頭">¶</a></h3>
<p>預設情況下,所有模組都有可用的 repr,然而根據上述設定及模組規格中的屬性,你可以更明確地控制模組物件的 repr。</p>
<p>如果模組具有規格(<code class="docutils literal notranslate"><span class="pre">__spec__</span></code>),引入機制將嘗試從規格中產生 repr。如果失敗或沒有規格,引入系統將使用模組上可用的資訊製作一個預設的 repr。它會嘗試使用 <code class="docutils literal notranslate"><span class="pre">module.__name__</span></code>、<code class="docutils literal notranslate"><span class="pre">module.__file__</span></code> 和 <code class="docutils literal notranslate"><span class="pre">module.__loader__</span></code> 作為 repr 的輸入,並為缺少的資訊提供預設值。</p>
<p>以下是具體的使用規則:</p>
<ul class="simple">
<li><p>如果模組具有 <code class="docutils literal notranslate"><span class="pre">__spec__</span></code> 屬性,則使用規格中的資訊產生 repr。會參考 "name"、"loader"、"origin" 和 "has_location" 屬性。</p></li>
<li><p>如果模組具有 <code class="docutils literal notranslate"><span class="pre">__file__</span></code> 屬性,則會將其作為模組 repr 的一部分。</p></li>
<li><p>如果模組沒有 <code class="docutils literal notranslate"><span class="pre">__file__</span></code> 但有一個不為 <code class="docutils literal notranslate"><span class="pre">None</span></code> 的 <code class="docutils literal notranslate"><span class="pre">__loader__</span></code> ,則會將載入器的 repr 作為模組 repr 的一部分。</p></li>
<li><p>否則,在 repr 中只使用模組的 <code class="docutils literal notranslate"><span class="pre">__name__</span></code>。</p></li>
</ul>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.12 版的變更: </span><code class="xref py py-meth docutils literal notranslate"><span class="pre">module_repr()</span></code> 自 Python 3.4 起被棄用,並在 Python 3.12 中移除,且不會在解析模組的 repr 時被呼叫。</p>
</div>
</section>
<section id="cached-bytecode-invalidation">
<span id="pyc-invalidation"></span><h3><span class="section-number">5.4.6. </span>被快取的位元組碼的無效化<a class="headerlink" href="#cached-bytecode-invalidation" title="連結到這個標頭">¶</a></h3>
<p>在 Python 從 <code class="docutils literal notranslate"><span class="pre">.pyc</span></code> 檔案載入被快取的位元組碼之前,會檢查該快取是否與來源的 <code class="docutils literal notranslate"><span class="pre">.py</span></code> 檔案保持同步。預設情況下,Python 透過在寫入快取檔案時儲存來源檔案的最後修改時間戳和大小來完成此操作。在 runtime,引入系統會透過將快取檔案中儲存的詮釋資料 (metadata) 與來源檔案的詮釋資料進行比對來驗證快取檔案。</p>
<p>Python 還支援「基於雜湊」的快取檔案,這些檔案儲存源頭檔案內容的雜湊值,而不是其詮釋資料。基於雜湊的 <code class="docutils literal notranslate"><span class="pre">.pyc</span></code> 檔案有兩種變體:需檢查和不需要檢查的。對於需檢查的基於雜湊的 <code class="docutils literal notranslate"><span class="pre">.pyc</span></code> 檔案, Python 會對來源檔案進行雜湊,並將結果與快取檔案中的雜湊進行比較來驗證快取檔案。如果發現需檢查的基於雜湊的快取檔案無效,Python 會重新產生並寫入新的需檢查的基於雜湊的快取檔案。對於不需要檢查的基於雜湊的 <code class="docutils literal notranslate"><span class="pre">.pyc</span></code> 檔案,只要檔案存在,Python 就假設快取檔案是有效的。可以使用 <a class="reference internal" href="../using/cmdline.html#cmdoption-check-hash-based-pycs"><code class="xref std std-option docutils literal notranslate"><span class="pre">--check-hash-based-pycs</span></code></a> 旗標覆蓋基於雜湊的 <code class="docutils literal notranslate"><span class="pre">.pyc</span></code> 檔案的驗證行為。</p>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.7 版的變更: </span>新增了基於雜湊的 <code class="docutils literal notranslate"><span class="pre">.pyc</span></code> 檔案。此前,Python 只支援基於時間戳的位元組碼快取無效化。</p>
</div>
</section>
</section>
<section id="the-path-based-finder">
<h2><span class="section-number">5.5. </span>基於路徑的尋檢器<a class="headerlink" href="#the-path-based-finder" title="連結到這個標頭">¶</a></h2>
<p id="index-14">如前所述,Python 附帶了幾個預設的元路徑尋檢器。其中之一稱為 <a class="reference internal" href="../glossary.html#term-path-based-finder"><span class="xref std std-term">path based finder</span></a>(<a class="reference internal" href="../library/importlib.html#importlib.machinery.PathFinder" title="importlib.machinery.PathFinder"><code class="xref py py-class docutils literal notranslate"><span class="pre">PathFinder</span></code></a>),它搜尋 <a class="reference internal" href="../glossary.html#term-import-path"><span class="xref std std-term">import path</span></a>,該路徑包含一個<a class="reference internal" href="../glossary.html#term-path-entry"><span class="xref std std-term">路徑條目</span></a>的串列。每個路徑條目都指定了一個用於搜尋模組的位置。</p>
<p>基於路徑的尋檢器本身並不知道如何引入任何東西。實際上它會遍歷各個路徑條目,並將每個路徑條目與一個知道如何處理該特定路徑類型的路徑條目尋檢器關聯起來。</p>
<p>預設的一組路徑條目尋檢器實作了在檔案系統中尋找模組的所有語意,包括處理特殊檔案類型,例如 Python 原始程式碼檔案(<code class="docutils literal notranslate"><span class="pre">.py</span></code> 檔案)、Python 位元組程式碼檔案(<code class="docutils literal notranslate"><span class="pre">.pyc</span></code> 檔案)以及共享函式庫(例如 <code class="docutils literal notranslate"><span class="pre">.so</span></code> 檔案)。當標準函式庫中的 <a class="reference internal" href="../library/zipimport.html#module-zipimport" title="zipimport: Support for importing Python modules from ZIP archives."><code class="xref py py-mod docutils literal notranslate"><span class="pre">zipimport</span></code></a> 模組支援時,預設的路徑條目尋檢器也能處理從壓縮檔案中載入這些檔案類型(共享函式庫除外)。</p>
<p>路徑條目不必侷限於檔案系統位置。它們可以參照 URL、資料庫查詢或任何可以作為字串指定的位置。</p>
<p>基於路徑的尋檢器提供了額外的掛鉤和協定,讓你可以擴充和自訂可搜尋的路徑條目類型。例如,如果你希望支援將路徑條目作為網路 URLs,你可以撰寫一個實作 HTTP 語意的掛鉤,用於在網路上尋找模組。這個掛鉤(一個可呼叫物件)會回傳一個支援下述協定的 <a class="reference internal" href="../glossary.html#term-path-entry-finder"><span class="xref std std-term">path entry finder</span></a> ,該尋檢器隨後用於從網路中取得模組的載入器。</p>
<p>提醒一句:本節與前一節都使用了 <em>尋檢器</em> 這個術語,並透過使用術語 <a class="reference internal" href="../glossary.html#term-meta-path-finder"><span class="xref std std-term">meta path finder</span></a> 和 <a class="reference internal" href="../glossary.html#term-path-entry-finder"><span class="xref std std-term">path entry finder</span></a> 來區分它們。這兩種類型的尋檢器非常相似,它們支援類似的協定,並在引入過程中以類似的方式運作,但請記住,它們之間仍有些許的差異。尤其元路徑尋檢器會在引入過程開始時運作,並通過 <a class="reference internal" href="../library/sys.html#sys.meta_path" title="sys.meta_path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.meta_path</span></code></a> 的遍歷關閉 (key off)。</p>
<p>相比之下,路徑條目尋檢器在某種意義上是基於路徑的尋檢器的一個實作細節。事實上,如果基於路徑的尋檢器從 <a class="reference internal" href="../library/sys.html#sys.meta_path" title="sys.meta_path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.meta_path</span></code></a> 中移除,路徑條目尋檢器的任何語意都不會被叫用。</p>
<section id="path-entry-finders">
<h3><span class="section-number">5.5.1. </span>路徑條目尋檢器<a class="headerlink" href="#path-entry-finders" title="連結到這個標頭">¶</a></h3>
<p id="index-15"><a class="reference internal" href="../glossary.html#term-path-based-finder"><span class="xref std std-term">path based finder</span></a> 負責尋找並載入其位置以字串 <a class="reference internal" href="../glossary.html#term-path-entry"><span class="xref std std-term">path entry</span></a> 指定的 Python 模組與套件。大多數路徑條目指向檔案系統中的位置,但不必侷限於此。</p>
<p>作為元路徑尋檢器,<a class="reference internal" href="../glossary.html#term-path-based-finder"><span class="xref std std-term">path based finder</span></a> 實作了先前描述的 <a class="reference internal" href="../library/importlib.html#importlib.abc.MetaPathFinder.find_spec" title="importlib.abc.MetaPathFinder.find_spec"><code class="xref py py-meth docutils literal notranslate"><span class="pre">find_spec()</span></code></a> 協定,但它另外提供了可用來自訂模組如何從 <a class="reference internal" href="../glossary.html#term-import-path"><span class="xref std std-term">import path</span></a> 被找到並載入的掛鉤。</p>
<p><a class="reference internal" href="../glossary.html#term-path-based-finder"><span class="xref std std-term">path based finder</span></a> 會使用三個變數:<a class="reference internal" href="../library/sys.html#sys.path" title="sys.path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path</span></code></a>、<a class="reference internal" href="../library/sys.html#sys.path_hooks" title="sys.path_hooks"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path_hooks</span></code></a> 和 <a class="reference internal" href="../library/sys.html#sys.path_importer_cache" title="sys.path_importer_cache"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path_importer_cache</span></code></a>。套件物件上的 <code class="docutils literal notranslate"><span class="pre">__path__</span></code> 屬性也會被使用。這些提供了額外的方法來自訂引入機制。</p>
<p><a class="reference internal" href="../library/sys.html#sys.path" title="sys.path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path</span></code></a> 包含一個字串的 list,用來提供模組與套件的搜尋位置。它會從 <span class="target" id="index-46"></span><a class="reference internal" href="../using/cmdline.html#envvar-PYTHONPATH"><code class="xref std std-envvar docutils literal notranslate"><span class="pre">PYTHONPATH</span></code></a> 環境變數,以及各種安裝與實作相關的預設值初始化。<a class="reference internal" href="../library/sys.html#sys.path" title="sys.path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path</span></code></a> 中的條目可以指定檔案系統上的目錄、zip 檔案,或其他可能需要搜尋模組的「位置」(參閱 <a class="reference internal" href="../library/site.html#module-site" title="site: Module responsible for site-specific configuration."><code class="xref py py-mod docutils literal notranslate"><span class="pre">site</span></code></a> 模組),例如 URL 或資料庫查詢。<a class="reference internal" href="../library/sys.html#sys.path" title="sys.path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path</span></code></a> 中只能包含字串;其他資料型別都會被忽略。</p>
<p><a class="reference internal" href="../glossary.html#term-path-based-finder"><span class="xref std std-term">path based finder</span></a> 也是一種 <a class="reference internal" href="../glossary.html#term-meta-path-finder"><span class="xref std std-term">meta path finder</span></a>,因此引入機制會如前所述般透過呼叫基於路徑的尋檢器的 <a class="reference internal" href="../library/importlib.html#importlib.machinery.PathFinder.find_spec" title="importlib.machinery.PathFinder.find_spec"><code class="xref py py-meth docutils literal notranslate"><span class="pre">find_spec()</span></code></a> 方法來開始 <a class="reference internal" href="../glossary.html#term-import-path"><span class="xref std std-term">import path</span></a> 的搜尋。當有提供 <a class="reference internal" href="../library/importlib.html#importlib.machinery.PathFinder.find_spec" title="importlib.machinery.PathFinder.find_spec"><code class="xref py py-meth docutils literal notranslate"><span class="pre">find_spec()</span></code></a> 的 <code class="docutils literal notranslate"><span class="pre">path</span></code> 引數時,它會是一個要遍歷的字串路徑 list——通常是在套件內引入時使用該套件的 <code class="docutils literal notranslate"><span class="pre">__path__</span></code> 屬性。如果 <code class="docutils literal notranslate"><span class="pre">path</span></code> 引數為 <code class="docutils literal notranslate"><span class="pre">None</span></code>,則表示為頂層引入並使用 <a class="reference internal" href="../library/sys.html#sys.path" title="sys.path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path</span></code></a>。</p>
<p>基於路徑的尋檢器會遍歷搜尋路徑中的每個條目,並為每個條目尋找適當的 <a class="reference internal" href="../glossary.html#term-path-entry-finder"><span class="xref std std-term">path entry finder</span></a> (<a class="reference internal" href="../library/importlib.html#importlib.abc.PathEntryFinder" title="importlib.abc.PathEntryFinder"><code class="xref py py-class docutils literal notranslate"><span class="pre">PathEntryFinder</span></code></a>)。由於這可能是代價高昂的操作(例如此搜尋可能會有 <code class="docutils literal notranslate"><span class="pre">stat()</span></code> 呼叫的額外開銷),基於路徑的尋檢器會維護一個將路徑條目對映到路徑條目尋檢器的快取。此快取存放於 <a class="reference internal" href="../library/sys.html#sys.path_importer_cache" title="sys.path_importer_cache"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path_importer_cache</span></code></a>(儘管名稱如此,該快取實際上儲存的是尋檢器物件,而非僅限於 <a class="reference internal" href="../glossary.html#term-importer"><span class="xref std std-term">importer</span></a> 物件)。如此一來,針對特定 <a class="reference internal" href="../glossary.html#term-path-entry"><span class="xref std std-term">path entry</span></a> 位置的 <a class="reference internal" href="../glossary.html#term-path-entry-finder"><span class="xref std std-term">path entry finder</span></a> 的高代價搜尋只需進行一次。使用者程式碼可以移除 <a class="reference internal" href="../library/sys.html#sys.path_importer_cache" title="sys.path_importer_cache"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path_importer_cache</span></code></a> 中的快取條目,以強制基於路徑的尋檢器再次執行路徑條目搜尋。</p>
<p>如果該路徑條目不在快取中,基於路徑的尋檢器會遍歷 <a class="reference internal" href="../library/sys.html#sys.path_hooks" title="sys.path_hooks"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path_hooks</span></code></a> 中的每個可呼叫物件。此 list 中的每個 <a class="reference internal" href="../glossary.html#term-path-entry-hook"><span class="xref std std-term">路徑條目掛鉤</span></a> 都會以單一引數被呼叫,即要搜尋的路徑條目。這個可呼叫物件可以回傳一個能處理該路徑條目的 <a class="reference internal" href="../glossary.html#term-path-entry-finder"><span class="xref std std-term">path entry finder</span></a>,也可以引發 <a class="reference internal" href="../library/exceptions.html#ImportError" title="ImportError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ImportError</span></code></a>。基於路徑的尋檢器會使用 <a class="reference internal" href="../library/exceptions.html#ImportError" title="ImportError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ImportError</span></code></a> 來表示該掛鉤無法為該 <a class="reference internal" href="../glossary.html#term-path-entry"><span class="xref std std-term">path entry</span></a> 找到 <a class="reference internal" href="../glossary.html#term-path-entry-finder"><span class="xref std std-term">path entry finder</span></a>。此例外會被忽略,並繼續疊代 <a class="reference internal" href="../glossary.html#term-import-path"><span class="xref std std-term">import path</span></a>。該掛鉤應預期接收字串或 bytes 物件;bytes 物件的編碼由掛鉤決定(例如檔案系統編碼、UTF-8 或其他),若掛鉤無法解碼該引數,則應引發 <a class="reference internal" href="../library/exceptions.html#ImportError" title="ImportError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ImportError</span></code></a>。</p>
<p>若 <a class="reference internal" href="../library/sys.html#sys.path_hooks" title="sys.path_hooks"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path_hooks</span></code></a> 的疊代結束後仍未回傳任何 <a class="reference internal" href="../glossary.html#term-path-entry-finder"><span class="xref std std-term">path entry finder</span></a>,則基於路徑的尋檢器的 <a class="reference internal" href="../library/importlib.html#importlib.machinery.PathFinder.find_spec" title="importlib.machinery.PathFinder.find_spec"><code class="xref py py-meth docutils literal notranslate"><span class="pre">find_spec()</span></code></a> 方法會在 <a class="reference internal" href="../library/sys.html#sys.path_importer_cache" title="sys.path_importer_cache"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path_importer_cache</span></code></a> 中存入 <code class="docutils literal notranslate"><span class="pre">None</span></code>(表示此路徑條目沒有尋檢器),並回傳 <code class="docutils literal notranslate"><span class="pre">None</span></code>,表示此 <a class="reference internal" href="../glossary.html#term-meta-path-finder"><span class="xref std std-term">meta path finder</span></a> 無法找到該模組。</p>
<p>若 <a class="reference internal" href="../library/sys.html#sys.path_hooks" title="sys.path_hooks"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path_hooks</span></code></a> 上的某個 <a class="reference internal" href="../glossary.html#term-path-entry-hook"><span class="xref std std-term">路徑條目掛鉤</span></a> 可呼叫物件 <em>確實</em> 回傳了 <a class="reference internal" href="../glossary.html#term-path-entry-finder"><span class="xref std std-term">path entry finder</span></a>,則會使用以下協定向該尋檢器要求模組規格,並在載入模組時使用該規格。</p>
<p>目前工作目錄——以空字串表示——的處理方式與 <a class="reference internal" href="../library/sys.html#sys.path" title="sys.path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path</span></code></a> 上其他條目略有不同。第一,如果目前工作目錄無法判定或被發現不存在,便不會在 <a class="reference internal" href="../library/sys.html#sys.path_importer_cache" title="sys.path_importer_cache"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path_importer_cache</span></code></a> 中儲存任何值。第二,對於每次模組查找,都會重新查詢目前工作目錄的值。第三,供 <a class="reference internal" href="../library/sys.html#sys.path_importer_cache" title="sys.path_importer_cache"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path_importer_cache</span></code></a> 使用並由 <a class="reference internal" href="../library/importlib.html#importlib.machinery.PathFinder.find_spec" title="importlib.machinery.PathFinder.find_spec"><code class="xref py py-meth docutils literal notranslate"><span class="pre">importlib.machinery.PathFinder.find_spec()</span></code></a> 回傳的路徑會是實際的目前工作目錄,而不是空字串。</p>
</section>
<section id="path-entry-finder-protocol">
<h3><span class="section-number">5.5.2. </span>路徑條目尋檢器協定<a class="headerlink" href="#path-entry-finder-protocol" title="連結到這個標頭">¶</a></h3>
<p>為了支援模組與已初始化套件的引入,並能為命名空間套件提供部分組成,路徑條目尋檢器必須實作 <a class="reference internal" href="../library/importlib.html#importlib.abc.PathEntryFinder.find_spec" title="importlib.abc.PathEntryFinder.find_spec"><code class="xref py py-meth docutils literal notranslate"><span class="pre">find_spec()</span></code></a> 方法。</p>
<p><a class="reference internal" href="../library/importlib.html#importlib.abc.PathEntryFinder.find_spec" title="importlib.abc.PathEntryFinder.find_spec"><code class="xref py py-meth docutils literal notranslate"><span class="pre">find_spec()</span></code></a> 會接收兩個引數:正在引入的模組之完整限定名稱,以及(可選的)目標模組。<code class="docutils literal notranslate"><span class="pre">find_spec()</span></code> 會回傳一個完整填入的模組規格。此規格會一律設定 "loader"(只有一個例外)。</p>
<p>為了向引入機制表明該規格代表一個命名空間 <a class="reference internal" href="../glossary.html#term-portion"><span class="xref std std-term">portion</span></a>,路徑條目尋檢器會將 <code class="docutils literal notranslate"><span class="pre">submodule_search_locations</span></code> 設為包含該部分的 list。</p>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.4 版的變更: </span><a class="reference internal" href="../library/importlib.html#importlib.abc.PathEntryFinder.find_spec" title="importlib.abc.PathEntryFinder.find_spec"><code class="xref py py-meth docutils literal notranslate"><span class="pre">find_spec()</span></code></a> 已取代 <code class="xref py py-meth docutils literal notranslate"><span class="pre">find_loader()</span></code> 與 <code class="xref py py-meth docutils literal notranslate"><span class="pre">find_module()</span></code>,兩者現已棄用,但若未定義 <code class="docutils literal notranslate"><span class="pre">find_spec()</span></code> 仍會被使用。</p>
<p>較舊的路徑條目尋檢器可能會實作這兩個已棄用的方法之一,而不是 <code class="docutils literal notranslate"><span class="pre">find_spec()</span></code>。為了向後相容,這些方法仍會被使用。然而,如果路徑條目尋檢器實作了 <code class="docutils literal notranslate"><span class="pre">find_spec()</span></code>,這些舊方法就會被忽略。</p>
<p><code class="xref py py-meth docutils literal notranslate"><span class="pre">find_loader()</span></code> 接收一個引數,即正在引入的模組之完整限定名稱。<code class="docutils literal notranslate"><span class="pre">find_loader()</span></code> 會回傳一個 2-tuple,其中第一個項目是 loader,第二個項目是命名空間 <a class="reference internal" href="../glossary.html#term-portion"><span class="xref std std-term">portion</span></a>。</p>
<p>為了與其他引入協定的實作向後相容,許多路徑條目尋檢器也支援元路徑尋檢器所支援的相同、傳統的 <code class="docutils literal notranslate"><span class="pre">find_module()</span></code> 方法。然而,路徑條目尋檢器的 <code class="docutils literal notranslate"><span class="pre">find_module()</span></code> 方法永遠不會帶著 <code class="docutils literal notranslate"><span class="pre">path</span></code> 引數被呼叫(它們預期會從對路徑條目掛鉤的初始呼叫中記錄適當的路徑資訊)。</p>
<p>路徑條目尋檢器上的 <code class="docutils literal notranslate"><span class="pre">find_module()</span></code> 方法已被棄用,因為它不允許路徑條目尋檢器為命名空間套件只提供部分組成。若路徑條目尋檢器同時存在 <code class="docutils literal notranslate"><span class="pre">find_loader()</span></code> 與 <code class="docutils literal notranslate"><span class="pre">find_module()</span></code>,引入系統會一律優先呼叫 <code class="docutils literal notranslate"><span class="pre">find_loader()</span></code>。</p>
</div>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.10 版的變更: </span>引入系統對 <code class="xref py py-meth docutils literal notranslate"><span class="pre">find_module()</span></code> 與 <code class="xref py py-meth docutils literal notranslate"><span class="pre">find_loader()</span></code> 的呼叫將會引發 <a class="reference internal" href="../library/exceptions.html#ImportWarning" title="ImportWarning"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ImportWarning</span></code></a>。</p>
</div>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.12 版的變更: </span><code class="docutils literal notranslate"><span class="pre">find_module()</span></code> 和 <code class="docutils literal notranslate"><span class="pre">find_loader()</span></code> 已被移除。</p>
</div>
</section>
</section>
<section id="replacing-the-standard-import-system">
<h2><span class="section-number">5.6. </span>取代標準引入系統<a class="headerlink" href="#replacing-the-standard-import-system" title="連結到這個標頭">¶</a></h2>
<p>取代整個引入系統最可靠的機制是刪除 <a class="reference internal" href="../library/sys.html#sys.meta_path" title="sys.meta_path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.meta_path</span></code></a> 的預設內容,並以自訂的元路徑掛鉤完全取代它們。</p>
<p>如果可以只改變 import 陳述式的行為,而不影響其他存取引入系統的 API,那麼替換內建的 <a class="reference internal" href="../library/functions.html#import__" title="__import__"><code class="xref py py-func docutils literal notranslate"><span class="pre">__import__()</span></code></a> 函式可能就足夠了。</p>
<p>若要從元路徑較早處的掛鉤選擇性地阻止某些模組被引入(而不是完全停用標準引入系統),只要在 <a class="reference internal" href="../library/importlib.html#importlib.abc.MetaPathFinder.find_spec" title="importlib.abc.MetaPathFinder.find_spec"><code class="xref py py-meth docutils literal notranslate"><span class="pre">find_spec()</span></code></a> 直接引發 <a class="reference internal" href="../library/exceptions.html#ModuleNotFoundError" title="ModuleNotFoundError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ModuleNotFoundError</span></code></a>,而不是回傳 <code class="docutils literal notranslate"><span class="pre">None</span></code> 即可。後者表示元路徑搜尋應繼續,而引發例外則會立即終止。</p>
</section>
<section id="package-relative-imports">
<span id="relativeimports"></span><h2><span class="section-number">5.7. </span>套件相對引入<a class="headerlink" href="#package-relative-imports" title="連結到這個標頭">¶</a></h2>
<p>相對引入使用前導點號。一個前導點號表示從目前套件開始的相對引入。兩個或更多前導點號表示相對引入到目前套件的父層,第一個之後每多一個點號就往上一層。例如,給定以下套件配置:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">package</span><span class="o">/</span>
<span class="fm">__init__</span><span class="o">.</span><span class="n">py</span>
<span class="n">subpackage1</span><span class="o">/</span>
<span class="fm">__init__</span><span class="o">.</span><span class="n">py</span>
<span class="n">moduleX</span><span class="o">.</span><span class="n">py</span>
<span class="n">moduleY</span><span class="o">.</span><span class="n">py</span>
<span class="n">subpackage2</span><span class="o">/</span>
<span class="fm">__init__</span><span class="o">.</span><span class="n">py</span>
<span class="n">moduleZ</span><span class="o">.</span><span class="n">py</span>
<span class="n">moduleA</span><span class="o">.</span><span class="n">py</span>
</pre></div>
</div>
<p>在 <code class="docutils literal notranslate"><span class="pre">subpackage1/moduleX.py</span></code> 或 <code class="docutils literal notranslate"><span class="pre">subpackage1/__init__.py</span></code> 中,以下皆為有效的相對引入:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">.moduleY</span><span class="w"> </span><span class="kn">import</span> <span class="n">spam</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.moduleY</span><span class="w"> </span><span class="kn">import</span> <span class="n">spam</span> <span class="k">as</span> <span class="n">ham</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.</span><span class="w"> </span><span class="kn">import</span> <span class="n">moduleY</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">..subpackage1</span><span class="w"> </span><span class="kn">import</span> <span class="n">moduleY</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">..subpackage2.moduleZ</span><span class="w"> </span><span class="kn">import</span> <span class="n">eggs</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">..moduleA</span><span class="w"> </span><span class="kn">import</span> <span class="n">foo</span>
</pre></div>
</div>
<p>絕對引入可以使用 <code class="docutils literal notranslate"><span class="pre">import</span> <span class="pre"><></span></code> 或 <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre"><></span> <span class="pre">import</span> <span class="pre"><></span></code> 語法,但相對引入只能使用第二種形式;原因是:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">XXX.YYY.ZZZ</span>
</pre></div>
</div>
<p>應該要將 <code class="docutils literal notranslate"><span class="pre">XXX.YYY.ZZZ</span></code> 作為可用的運算式公開,但 .moduleY 不是有效的運算式。</p>
</section>
<section id="special-considerations-for-main">
<span id="import-dunder-main"></span><h2><span class="section-number">5.8. </span>__main__ 的特殊考量<a class="headerlink" href="#special-considerations-for-main" title="連結到這個標頭">¶</a></h2>
<p><a class="reference internal" href="../library/__main__.html#module-__main__" title="__main__: The environment where top-level code is run. Covers command-line interfaces, import-time behavior, and ``__name__ == '__main__'``."><code class="xref py py-mod docutils literal notranslate"><span class="pre">__main__</span></code></a> 模組相對於 Python 的引入系統而言是一個特殊案例。如 <a class="reference internal" href="toplevel_components.html#programs"><span class="std std-ref">elsewhere</span></a> 所述,<code class="docutils literal notranslate"><span class="pre">__main__</span></code> 模組會在直譯器啟動時直接初始化,類似於 <a class="reference internal" href="../library/sys.html#module-sys" title="sys: Access system-specific parameters and functions."><code class="xref py py-mod docutils literal notranslate"><span class="pre">sys</span></code></a> 與 <a class="reference internal" href="../library/builtins.html#module-builtins" title="builtins: The module that provides the built-in namespace."><code class="xref py py-mod docutils literal notranslate"><span class="pre">builtins</span></code></a>。然而,與那兩者不同,它並不嚴格算是內建模組。這是因為 <code class="docutils literal notranslate"><span class="pre">__main__</span></code> 的初始化方式取決於呼叫直譯器時使用的旗標與其他選項。</p>
<section id="main-spec">
<span id="id5"></span><h3><span class="section-number">5.8.1. </span>__main__.__spec__<a class="headerlink" href="#main-spec" title="連結到這個標頭">¶</a></h3>
<p>視 <a class="reference internal" href="../library/__main__.html#module-__main__" title="__main__: The environment where top-level code is run. Covers command-line interfaces, import-time behavior, and ``__name__ == '__main__'``."><code class="xref py py-mod docutils literal notranslate"><span class="pre">__main__</span></code></a> 的初始化方式而定,<code class="docutils literal notranslate"><span class="pre">__main__.__spec__</span></code> 會被適當設定,或設為 <code class="docutils literal notranslate"><span class="pre">None</span></code>。</p>
<p>當 Python 以 <a class="reference internal" href="../using/cmdline.html#cmdoption-m"><code class="xref std std-option docutils literal notranslate"><span class="pre">-m</span></code></a> 選項啟動時,<code class="docutils literal notranslate"><span class="pre">__spec__</span></code> 會設定為對應模組或套件的模組規格。當 <code class="docutils literal notranslate"><span class="pre">__main__</span></code> 模組作為執行目錄、zipfile 或其他 <a class="reference internal" href="../library/sys.html#sys.path" title="sys.path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.path</span></code></a> 條目的一部分而被載入時,<code class="docutils literal notranslate"><span class="pre">__spec__</span></code> 也會被填入。</p>
<p>在 <a class="reference internal" href="../using/cmdline.html#using-on-interface-options"><span class="std std-ref">其餘狀況</span></a> 中,<code class="docutils literal notranslate"><span class="pre">__main__.__spec__</span></code> 會被設為 <code class="docutils literal notranslate"><span class="pre">None</span></code>,因為用來填入 <a class="reference internal" href="../library/__main__.html#module-__main__" title="__main__: The environment where top-level code is run. Covers command-line interfaces, import-time behavior, and ``__name__ == '__main__'``."><code class="xref py py-mod docutils literal notranslate"><span class="pre">__main__</span></code></a> 的程式碼並不直接對應可引入的模組:</p>
<ul class="simple">
<li><p>互動式提示字元</p></li>
<li><p><a class="reference internal" href="../using/cmdline.html#cmdoption-c"><code class="xref std std-option docutils literal notranslate"><span class="pre">-c</span></code></a> 選項</p></li>
<li><p>從 stdin 執行</p></li>
<li><p>直接從原始碼或位元組碼檔案執行</p></li>
</ul>
<p>請注意,在最後一種情況下,<code class="docutils literal notranslate"><span class="pre">__main__.__spec__</span></code> 一律為 <code class="docutils literal notranslate"><span class="pre">None</span></code>,<em>即使</em> 該檔案在技術上可直接作為模組引入也一樣。若希望在 <a class="reference internal" href="../library/__main__.html#module-__main__" title="__main__: The environment where top-level code is run. Covers command-line interfaces, import-time behavior, and ``__name__ == '__main__'``."><code class="xref py py-mod docutils literal notranslate"><span class="pre">__main__</span></code></a> 中取得有效的模組詮釋資料,請使用 <a class="reference internal" href="../using/cmdline.html#cmdoption-m"><code class="xref std std-option docutils literal notranslate"><span class="pre">-m</span></code></a> 選項。</p>
<p>另請注意,即使 <code class="docutils literal notranslate"><span class="pre">__main__</span></code> 對應到可引入的模組,且 <code class="docutils literal notranslate"><span class="pre">__main__.__spec__</span></code> 也已相應設定,它們仍被視為 <em>不同</em> 的模組。這是因為由 <code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">__name__</span> <span class="pre">==</span> <span class="pre">"__main__":</span></code> 檢查所包住的程式碼區塊,只會在該模組用來填入 <code class="docutils literal notranslate"><span class="pre">__main__</span></code> 命名空間時執行,而不會在一般引入時執行。</p>
</section>
</section>
<section id="references">
<h2><span class="section-number">5.9. </span>參考資料<a class="headerlink" href="#references" title="連結到這個標頭">¶</a></h2>
<p>引入機制自 Python 早期以來已有相當大的演進。原始的 <a class="reference external" href="https://www.python.org/doc/essays/packages/">套件規格</a> 仍可閱讀,儘管自該文件撰寫以來部分細節已有所變更。</p>
<p><a class="reference internal" href="../library/sys.html#sys.meta_path" title="sys.meta_path"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.meta_path</span></code></a> 的原始規格是 <span class="target" id="index-47"></span><a class="pep reference external" href="https://peps.python.org/pep-0302/"><strong>PEP 302</strong></a>,後續在 <span class="target" id="index-48"></span><a class="pep reference external" href="https://peps.python.org/pep-0420/"><strong>PEP 420</strong></a> 中擴充。</p>
<p><span class="target" id="index-49"></span><a class="pep reference external" href="https://peps.python.org/pep-0420/"><strong>PEP 420</strong></a> 在 Python 3.3 中引進了 <a class="reference internal" href="../glossary.html#term-namespace-package"><span class="xref std std-term">命名空間套件</span></a>。<span class="target" id="index-50"></span><a class="pep reference external" href="https://peps.python.org/pep-0420/"><strong>PEP 420</strong></a> 也引進了 <code class="xref py py-meth docutils literal notranslate"><span class="pre">find_loader()</span></code> 協定,作為 <code class="xref py py-meth docutils literal notranslate"><span class="pre">find_module()</span></code> 的替代方案。</p>
<p><span class="target" id="index-51"></span><a class="pep reference external" href="https://peps.python.org/pep-0366/"><strong>PEP 366</strong></a> 描述了為主模組中的明確相對引入新增 <code class="docutils literal notranslate"><span class="pre">__package__</span></code> 屬性。</p>
<p><span class="target" id="index-52"></span><a class="pep reference external" href="https://peps.python.org/pep-0328/"><strong>PEP 328</strong></a> 引進了絕對引入與明確的相對引入,並最初提出以 <code class="docutils literal notranslate"><span class="pre">__name__</span></code> 來表示 <span class="target" id="index-53"></span><a class="pep reference external" href="https://peps.python.org/pep-0366/"><strong>PEP 366</strong></a> 最終為 <code class="docutils literal notranslate"><span class="pre">__package__</span></code> 指定的語意。</p>
<p><span class="target" id="index-54"></span><a class="pep reference external" href="https://peps.python.org/pep-0338/"><strong>PEP 338</strong></a> 定義了將模組作為腳本執行。</p>
<p><span class="target" id="index-55"></span><a class="pep reference external" href="https://peps.python.org/pep-0451/"><strong>PEP 451</strong></a> 增加了在 spec 物件中封裝個別模組的引入狀態。它也將載入器的大部分樣板責任移回引入機制。這些變更讓引入系統中的多個 API 得以棄用,並新增尋檢器與載入器的方法。</p>
<p class="rubric">註解</p>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="fnmo" role="doc-footnote">
<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id1">1</a><span class="fn-bracket">]</span></span>
<p>參閱 <a class="reference internal" href="../library/types.html#types.ModuleType" title="types.ModuleType"><code class="xref py py-class docutils literal notranslate"><span class="pre">types.ModuleType</span></code></a>。</p>
</aside>
<aside class="footnote brackets" id="fnlo" role="doc-footnote">
<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id3">2</a><span class="fn-bracket">]</span></span>
<p>importlib 的實作避免直接使用回傳值,而是透過在 <a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a> 中查找模組名稱來取得模組物件。這樣的間接效果是,被引入的模組可能會在 <a class="reference internal" href="../library/sys.html#sys.modules" title="sys.modules"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.modules</span></code></a> 中替換自己。這是實作特定的行為,並不保證能在其他 Python 實作中運作。</p>
</aside>
</aside>
</section>
</section>
<div class="clearer"></div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="Main">
<div class="sphinxsidebarwrapper">
<div>
<h3><a href="../contents.html">目錄</a></h3>
<ul>
<li><a class="reference internal" href="#">5. 模組引入系統</a><ul>
<li><a class="reference internal" href="#importlib">5.1. <code class="xref py py-mod docutils literal notranslate"><span class="pre">importlib</span></code></a></li>
<li><a class="reference internal" href="#packages">5.2. 套件</a><ul>
<li><a class="reference internal" href="#regular-packages">5.2.1. 一般套件</a></li>
<li><a class="reference internal" href="#namespace-packages">5.2.2. 命名空間套件</a></li>
</ul>
</li>
<li><a class="reference internal" href="#searching">5.3. 搜尋</a><ul>
<li><a class="reference internal" href="#the-module-cache">5.3.1. 模組快取</a></li>
<li><a class="reference internal" href="#finders-and-loaders">5.3.2. 尋檢器 (Finder) 與載入器 (Loader)</a></li>
<li><a class="reference internal" href="#import-hooks">5.3.3. 引入掛鉤 (Import hooks)</a></li>
<li><a class="reference internal" href="#the-meta-path">5.3.4. 元路徑</a></li>
</ul>
</li>
<li><a class="reference internal" href="#loading">5.4. 載入</a><ul>
<li><a class="reference internal" href="#loaders">5.4.1. 載入器</a></li>
<li><a class="reference internal" href="#submodules">5.4.2. 子模組</a></li>
<li><a class="reference internal" href="#module-specs">5.4.3. 模組規格</a></li>
<li><a class="reference internal" href="#path-attributes-on-modules">5.4.4. 模組上的 __path__ 屬性</a></li>
<li><a class="reference internal" href="#module-reprs">5.4.5. 模組的 reprs</a></li>
<li><a class="reference internal" href="#cached-bytecode-invalidation">5.4.6. 被快取的位元組碼的無效化</a></li>
</ul>
</li>
<li><a class="reference internal" href="#the-path-based-finder">5.5. 基於路徑的尋檢器</a><ul>
<li><a class="reference internal" href="#path-entry-finders">5.5.1. 路徑條目尋檢器</a></li>
<li><a class="reference internal" href="#path-entry-finder-protocol">5.5.2. 路徑條目尋檢器協定</a></li>
</ul>
</li>
<li><a class="reference internal" href="#replacing-the-standard-import-system">5.6. 取代標準引入系統</a></li>
<li><a class="reference internal" href="#package-relative-imports">5.7. 套件相對引入</a></li>
<li><a class="reference internal" href="#special-considerations-for-main">5.8. __main__ 的特殊考量</a><ul>
<li><a class="reference internal" href="#main-spec">5.8.1. __main__.__spec__</a></li>
</ul>
</li>
<li><a class="reference internal" href="#references">5.9. 參考資料</a></li>
</ul>
</li>
</ul>
</div>
<div>
<h4>上個主題</h4>
<p class="topless"><a href="executionmodel.html"
title="上一章"><span class="section-number">4. </span>執行模型</a></p>
</div>
<div>
<h4>下個主題</h4>
<p class="topless"><a href="expressions.html"
title="下一章"><span class="section-number">6. </span>運算式</a></p>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const title = document.querySelector('meta[property="og:title"]').content;
const elements = document.querySelectorAll('.improvepage');
const pageurl = window.location.href.split('?')[0];
elements.forEach(element => {
const url = new URL(element.href.split('?')[0].replace("-nojs", ""));
url.searchParams.set('pagetitle', title);
url.searchParams.set('pageurl', pageurl);
url.searchParams.set('pagesource', "reference/import.rst");
element.href = url.toString();
});
});
</script>
<div role="note" aria-label="source link">
<h3>此頁面</h3>
<ul class="this-page-menu">
<li><a href="../bugs.html">回報錯誤</a></li>
<li><a class="improvepage" href="../improve-page-nojs.html">改進此頁面</a></li>
<li>
<a href="https://github.com/python/cpython/blob/main/Doc/reference/import.rst?plain=1"
rel="nofollow">顯示原始碼
</a>
</li>
<li>
<a href="https://github.com/python/python-docs-zh-TW/blob/3.14/reference/import.po?plain=1"
rel="nofollow">顯示翻譯原始碼</a>
</li>
</ul>
</div>
</div>
<div id="sidebarbutton" title="收合側邊欄">
<span>«</span>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="Related">
<h3>導航</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="總索引"
>索引</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python 模組索引"
>模組</a> |</li>
<li class="right" >
<a href="expressions.html" title="6. 運算式"
>下一頁</a> |</li>
<li class="right" >
<a href="executionmodel.html" title="4. 執行模型"
>上一頁</a> |</li>
<li><img src="../_static/py.svg" alt="Python logo" style="vertical-align: middle; margin-top: -1px"></li>
<li><a href="https://www.python.org/">Python</a> »</li>
<li class="switchers">
<div class="language_switcher_placeholder"></div>
<div class="version_switcher_placeholder"></div>
</li>
<li>
</li>
<li id="cpython-language-and-version">
<a href="../index.html">3.14.7 Documentation</a> »
</li>
<li class="nav-item nav-item-1"><a href="index.html" >Python 語言參考手冊</a> »</li>
<li class="nav-item nav-item-this"><a href=""><span class="section-number">5. </span>模組引入系統</a></li>
<li class="right">
<div class="inline-search" role="search">
<form class="inline-search" action="../search.html" method="get">
<input placeholder="快速搜索" aria-label="快速搜索" type="search" name="q" id="search-box">
<input type="submit" value="前往">
</form>
</div>
|
</li>
<li class="right">
<label class="theme-selector-label">
主題
<select class="theme-selector" oninput="activateTheme(this.value)">
<option value="auto" selected>自動</option>
<option value="light">淺色模式</option>
<option value="dark">深色模式</option>
</select>
</label> |</li>
</ul>
</div>
<div class="footer">
© <a href="../copyright.html">版權所有</a> 2001 Python Software Foundation.
<br>
此頁面採用 Python 軟體基金會授權條款第 2 版。
<br>
文件中的範例、應用技巧與其他程式碼額外採用了 Zero Clause BSD 授權條款。
<br>
更多訊息請見<a href="/license.html">歷史與授權條款</a>。<br>
<br>
Python 軟體基金會是一家非營利法人。
<a href="https://www.python.org/psf/donations/">敬請捐贈。</a>
<br>
<br>
最後更新於 8月 14, 2026 (02:39 UTC)。
<a href="/bugs.html">發現 bug</a>?
<br>
以 <a href="https://www.sphinx-doc.org/">Sphinx</a>8.2.3建立。
</div>
</body>
</html>